首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >pyqtgraph:在使用TimeAxisItem和tickStrings时,固定x轴上显示的字符串数。

pyqtgraph:在使用TimeAxisItem和tickStrings时,固定x轴上显示的字符串数。
EN

Stack Overflow用户
提问于 2022-01-31 00:49:37
回答 2查看 431关注 0票数 2

我正在制作一个滚动图,它将绘制实时传感器数据,在x轴上显示时间。我对tickStrings的行为有点困惑。

我的代码基于下面的示例(来自这里)。当绘制的点数增加时,x轴字符串的数目会发生变化--有时会增加,有时会减少。它稳定一旦德克是完整的长度和‘滚动’开始。

是否有可能保持滴答字串之间的间距与绘图点的数目相同?我想,可能会使用一种方法,在添加新数据时替换空白的勾选字符串,但不知道如何做到这一点。

编辑:我希望实现的一个例子是这里

代码语言:javascript
运行
复制
import sys
import numpy as np
import datetime
from PyQt5.QtCore import QTime, QTimer
from pyqtgraph.Qt import QtGui
import pyqtgraph as pg
from collections import deque
import time

class TimeAxisItem(pg.AxisItem):
    def __init__(self, *args, **kwargs):
        super(TimeAxisItem, self).__init__(*args, **kwargs)

    def tickStrings(self, values, scale, spacing):
        return [int2dt(value).strftime("%H:%M:%S") for value in values]

def int2dt(ts):
    return(datetime.datetime.fromtimestamp(ts))

class MyApplication(QtGui.QApplication):
    def __init__(self, *args, **kwargs):
        super(MyApplication, self).__init__(*args, **kwargs)
        self.t = QTime()
        self.t.start()

        maxlen = 100
        self.data_x = deque(maxlen=maxlen)
        self.data_y = deque(maxlen=maxlen)

        self.win = pg.GraphicsLayoutWidget()
        self.win.resize(1000,600)
        self.plot = self.win.addPlot(title='Scrolling real-time plot', axisItems={'bottom': TimeAxisItem(
            orientation='bottom')})

        self.curve = self.plot.plot()

        self.tmr = QTimer()
        self.tmr.timeout.connect(self.update)
        self.tmr.start(1000)

        self.y = 100
        self.win.show()

    def update(self):
        x = int(time.time())
        self.y = self.y + np.random.uniform(-1, 1)

        self.data_x.append(x)
        self.data_y.append(self.y)
        time.sleep(2)
        print(self.data_x)
        print(self.data_y)
        self.curve.setData(x=list(self.data_x), y=list(self.data_y))

def main():
    app = MyApplication(sys.argv)
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-02-06 08:45:26

由于问题被更新了更多的细节,这里有更具体的答案。我保留先前的答案,以帮助某人,以防有固定数量的蜱显示。

要准确地处理您想要的内容,首先需要将滴答频率设置为每秒1次。这可以通过设置self.setTickSpacing(levels=[(1, 0)])来完成。在您的示例中,您有一分钟的更新时间,在这种情况下,您需要使用self.setTickSpacing(levels=[(60, 0)])

问题的第二部分是蜱的旋转-90度。旋转不是AxisItem实现的一部分。因此,我们必须重新实现drawPicture方法。完成滴答的旋转和平移。此外,为了有足够的高度,我们必须设置self.fixedHeight = 150以适应长的滴答线。

定间距是通过设置X轴的固定范围来实现的。为了达到滚动效果,我们必须在不附加任何数据的情况下隐藏第一滴滴。这是用ticks = [(1.0, ticks[0][1][self.hide_ticks:])]行完成的。

值得注意的是,我的解决方案适合你的具体情况。否则,必须使用fixedHeight和drawPicture方法的旋转部分。另外,队列的maxlen必须降低到10,这样就不会重叠。

这是完整的代码:

代码语言:javascript
运行
复制
import datetime
import sys
import time
from collections import deque

import numpy as np
import pyqtgraph as pg
from PyQt5.QtCore import QTime, QTimer
from pyqtgraph import debug as debug
from pyqtgraph.Qt import QtGui


class TimeAxisItem(pg.AxisItem):
    hide_ticks = 0

    def __init__(self, *args, **kwargs):
        super(TimeAxisItem, self).__init__(*args, **kwargs)
        # Paint tick every 1 second
        self.setTickSpacing(levels=[(1, 0)])
        # Paint tick every 1 minute
        # self.setTickSpacing(levels=[(60, 0)])
        # Set fixed tick height
        self.fixedHeight = 150

    def tickStrings(self, values, scale, spacing):
        return [int2dt(value).strftime("%Y-%m-%d %H:%M:%S") for value in values]

    def drawPicture(self, p, axisSpec, tickSpecs, textSpecs):

        profiler = debug.Profiler()

        p.setRenderHint(p.RenderHint.Antialiasing, False)
        p.setRenderHint(p.RenderHint.TextAntialiasing, True)

        ## draw long line along axis
        pen, p1, p2 = axisSpec
        p.setPen(pen)
        p.drawLine(p1, p2)
        # p.translate(0.5,0)  ## resolves some damn pixel ambiguity

        ## draw ticks
        for pen, p1, p2 in tickSpecs:
            p.setPen(pen)
            p.drawLine(p1, p2)
        profiler('draw ticks')

        # Draw all text
        if self.style['tickFont'] is not None:
            p.setFont(self.style['tickFont'])
        p.setPen(self.textPen())
        bounding = self.boundingRect().toAlignedRect()
        p.setClipRect(bounding)
        for rect, flags, text in textSpecs:
            p.save()  # save the painter state
            p.translate(rect.center())  # move coordinate system to center of text rect
            p.rotate(-90)  # rotate text
            p.translate(-rect.center())  # revert coordinate system
            p.translate(-65, 0)  # Move rotated tick down by 65 pixels
            p.drawText(rect, int(flags), text)
            p.restore()  # restore the painter state

        profiler('draw text')

    def tickValues(self, minVal, maxVal, size):
        if minVal == 0:
            return []
        else:
            ticks = super().tickValues(minVal, maxVal, size)
            ticks = [(1.0, ticks[0][1][self.hide_ticks:])]
            return ticks


def int2dt(ts):
    return (datetime.datetime.fromtimestamp(ts))


class MyApplication(QtGui.QApplication):
    def __init__(self, *args, **kwargs):
        super(MyApplication, self).__init__(*args, **kwargs)
        self.t = QTime()
        self.t.start()

        maxlen = 10
        self.data_x = deque(maxlen=maxlen)
        self.data_y = deque(maxlen=maxlen)
        self.win = pg.GraphicsLayoutWidget()
        self.win.resize(1000, 600)
        self.axis_x = TimeAxisItem(orientation='bottom')
        self.plot = self.win.addPlot(title='Scrolling real-time plot', axisItems={'bottom': self.axis_x})
        self.curve = self.plot.plot()

        self.tmr = QTimer()
        self.tmr.timeout.connect(self.update)
        self.tmr.start(1000)

        self.y = 100
        self.win.show()

    def update(self):
        x = int(time.time())
        self.y = self.y + np.random.uniform(-1, 1)

        self.data_x.append(x)
        self.data_y.append(self.y)
        time.sleep(1)

        # Set fixed range
        self.plot.setXRange(self.data_x[0] - self.data_x.maxlen + len(self.data_x),
                            self.data_x[0] + len(self.data_x) - 1, padding=0)
        # Hide ticks without data attached to it, to achieve scrolling effect
        self.axis_x.hide_ticks = self.data_x.maxlen - len(self.data_x)
        self.curve.setData(x=list(self.data_x), y=list(self.data_y))


def main():
    app = MyApplication(sys.argv)
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
票数 0
EN

Stack Overflow用户

发布于 2022-02-02 12:00:41

要设置固定数量的刻度,还必须重写tickValues方法。此方法生成滴答值,tickStrings方法给出这些值的字符串表示--在您的情况下转换为人类可读的时间。

下面是您可以在代码中使用的TimeAxisItem示例:

代码语言:javascript
运行
复制
class TimeAxisItem(pg.AxisItem):
    nticks = 6

    def __init__(self, *args, **kwargs):
        super(TimeAxisItem, self).__init__(*args, **kwargs)

    def tickStrings(self, values, scale, spacing):
        return [int2dt(value).strftime("%H:%M:%S") for value in values]

    def tickValues(self, minVal, maxVal, size):
        if self.nticks is not None:
            ticks = np.linspace(ceil(minVal), ceil(maxVal), num=self.nticks, endpoint=False)
            return [((1.0, 0), ticks)]
        else:
            return super().tickValues(minVal, maxVal, size)

您可以看到,如果nticks不是空的,我们就从minVal和maxVal之间的值生成n个滴答。Pyqtgraph在称为levels的范围内生成蜱。对于我们的情况,使用范围(1.0,0)就足够了,也就是说,滴答之间的距离是1秒,偏移量为0。

您可以根据需要使用setTickSpacing定义多个范围。例如,每小时、每分钟、每5秒都有滴答声,您可以将其设置为setTickSpacing(levels=[(3600, 0), (60, 0), (5, 0)])

如果Δx小于60秒,这将产生每5秒的滴答。如果Δx小于1小时,则每分钟进行勾选。然后每隔一小时滴答一次。

这是理解蜱是如何工作的关键知识。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70920246

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档