不显示动态matplotlib pyside小部件

时间:2016-03-31 20:08:17

标签: matplotlib pyside

我正在使用pyside和matplotlib编写一个python应用程序。在this tutorialthis SO post的组合之后,我创建了一个matplotlib小部件,我可以成功添加到父级。但是,当我实际添加数据时,似乎没有任何东西显示出来。

如果我添加像SO帖子那样的静态数据,它会显示出来,但是当我将其更改为动态更新时(目前计时器上每秒钟一次,但它最终将使用来自另一个类的信号),我从来没有得到任何东西,只有空轴出现。我怀疑我错过了强制抽奖或无效的调用,或者我调用update_datalim的方式有问题(尽管传递给它的值似乎是正确的)。

from PySide import QtCore, QtGui

import matplotlib
import random

matplotlib.use('Qt4Agg')
matplotlib.rcParams['backend.qt4']='PySide'

from matplotlib import pyplot as plt
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.patches import Rectangle

from collections import namedtuple

DataModel = namedtuple('DataModel', ['start_x', 'start_y', 'width', 'height'])

class BaseWidget(FigureCanvas):

    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111)
        # We want the axes cleared every time plot() is called
        self.axes.hold(False)
        self.axes.set_xlabel('X Label')
        self.axes.set_ylabel('Y Label')
        self.axes.set_title('My Data')

        FigureCanvas.__init__(self, fig)
        self.setParent(parent)

        FigureCanvas.setSizePolicy(self,
                                   QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)

        FigureCanvas.updateGeometry(self)

class DynamicWidget(BaseWidget):
    def set_data(self, the_data):
        self.axes.clear()
        xys = list()

        cmap = plt.cm.hot
        for datum in the_data:
            bottom_left = (datum.start_x, datum.start_y)
            top_right = (bottom_left[0] + datum.width, bottom_left[1] + datum.height)
            rect = Rectangle(
                xy=bottom_left,
                width=datum.width, height=datum.height, color=cmap(100)
            )
            xys.append(bottom_left)
            xys.append(top_right)
            self.axes.add_artist(rect)
        self.axes.update_datalim(xys)
        self.axes.figure.canvas.draw_idle()

class RandomDataWidget(DynamicWidget):
    def __init__(self, *args, **kwargs):
        DynamicWidget.__init__(self, *args, **kwargs)
        timer = QtCore.QTimer(self)
        timer.timeout.connect(self.generate_and_set_data)
        timer.start(1000)

    def generate_and_set_data(self):
        fake_data = [DataModel(
            start_x=random.randint(1, 100),
            width=random.randint(20, 40),
            start_y=random.randint(80, 160),
            height=random.randint(20, 90)
        ) for i in range(100)]

        self.set_data(fake_data)

编辑:我怀疑更新情节限制存在问题。运行上述代码时,图表将在x和y轴上以0和1的限制打开。由于我生成的数据都不属于该范围,因此我创建了另一个DynamicWidget的子类,它只绘制0到1之间的数据(来自链接的SO帖子的相同数据)。在实例化下面的类时,数据会成功显示。我是否需要做一些事情而不是调用update_datalim来让图表重新绑定自己?

class StaticWidget(DynamicWidget):
    def __init__(self):
        DynamicWidget.__init__(self)
        static_data = [
            DataModel(0.5, 0.05, 0.2, 0.05),
            DataModel(0.1, 0.2, 0.7, 0.2),
            DataModel(0.3, 0.1, 0.8, 0.1)
        ]
        self.set_data(static_data)

1 个答案:

答案 0 :(得分:2)

是的,update_datalim仅更新轴内部保留的边界框。您还需要启用自动缩放才能使用它。在self.axes.autoscale(enable=True)语句后添加self.axes.clear()即可。或者,您可以使用self.axes.set_xlimself.axes.set_ylim将轴的范围设置为固定值。

编辑:这是我的代码,适用于我

from PySide import QtCore, QtGui

import matplotlib
import random, sys

matplotlib.use('Qt4Agg')
matplotlib.rcParams['backend.qt4']='PySide'

from matplotlib import pyplot as plt
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.patches import Rectangle

from collections import namedtuple

DataModel = namedtuple('DataModel', ['start_x', 'start_y', 'width', 'height'])

class BaseWidget(FigureCanvas):

    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111)
        # We want the axes cleared every time plot() is called
        self.axes.hold(False)
        #self.axes.autoscale(enable=True)
        self.axes.set_xlabel('X Label')
        self.axes.set_ylabel('Y Label')
        self.axes.set_title('My Data')

        FigureCanvas.__init__(self, fig)
        self.setParent(parent)

        FigureCanvas.setSizePolicy(self,
                                   QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)

        FigureCanvas.updateGeometry(self)

class DynamicWidget(BaseWidget):
    def set_data(self, the_data):
        self.axes.clear()
        self.axes.autoscale(enable=True)
        #self.axes.set_xlim(0, 300)
        #self.axes.set_ylim(0, 300)
        xys = list()

        cmap = plt.cm.hot
        for datum in the_data:
            print datum
            bottom_left = (datum.start_x, datum.start_y)
            top_right = (bottom_left[0] + datum.width, bottom_left[1] + datum.height)
            rect = Rectangle(
                xy=bottom_left,
                width=datum.width, height=datum.height, color=cmap(100)
            )
            xys.append(bottom_left)
            xys.append(top_right)
            self.axes.add_artist(rect)
        self.axes.update_datalim(xys)
        self.axes.figure.canvas.draw_idle()

class RandomDataWidget(DynamicWidget):
    def __init__(self, *args, **kwargs):
        DynamicWidget.__init__(self, *args, **kwargs)
        timer = QtCore.QTimer(self)
        timer.timeout.connect(self.generate_and_set_data)
        timer.start(1000)

    def generate_and_set_data(self):
        fake_data = [DataModel(
            start_x=random.randint(1, 100),
            width=random.randint(20, 40),
            start_y=random.randint(80, 160),
            height=random.randint(20, 90)) for i in range(100)]

        self.set_data(fake_data)
        print "done:...\n\n"


def main():
    qApp = QtGui.QApplication(sys.argv)

    aw = RandomDataWidget()

    aw.show()
    aw.raise_()
    sys.exit(qApp.exec_())

if __name__ == "__main__":
    main()