QGraphicsView显示matplotlib绘图刷新图片

QGraphicsView显示matplotlib绘制的柱状图

一、Figure各部分介绍

matplotlib官网上专门有Figure各部分介绍

https://matplotlib.org/faq/usage_faq.html#what-is-a-backend

Figure为画纸,保存所有的axes、artists和canvas。一个figure可以拥有一个或多个axes。

Figure

The whole figure. The figure keeps track of all the child Axes, a smattering of ‘special’ artists (titles, figure legends, etc), and the canvas. (Don’t worry too much about the canvas, it is crucial as it is the object that actually does the drawing to get you your plot, but as the user it is more-or-less invisible to you). A figure can have any number of Axes, but to be useful should have at least one.

The easiest way to create a new figure is with pyplot:

fig = plt.figure()  # an empty figure with no axes
fig, ax_lst = plt.subplots(2, 2)  # a figure with a 2x2 grid of Axes

Axes为画轴,为figure上一片指定区域。一个figure可以有多个axes,但是一个axes只能属于一个figure。

一个axes包含2(2D)或3(3D)个axis(坐标轴),限制图画大小。

每一个axes有一个title和X轴坐标x-label,Y轴坐标y-label

Axes

This is what you think of as ‘a plot’, it is the region of the image with the data space (marked as the inner blue box). A given figure can contain many Axes, but a given Axes object can only be in one Figure. The Axes contains two (or three in the case of 3D) Axis objects (be aware of the difference between Axes and Axis) which take care of the data limits (the data limits can also be controlled via set via the set_xlim() and set_ylim() Axes methods). Each Axes has a title (set via set_title()), an x-label (set via set_xlabel()), and a y-label set via set_ylabel()).

The Axes class and it’s member functions are the primary entry point to working with the OO interface.

axis为坐标轴,设置坐标刻度。刻度的位置由Locator决定,刻度显示格式由Formatter决定。

Axis

These are the number-line-like objects (circled in green). They take care of setting the graph limits and generating the ticks (the marks on the axis) and ticklabels (strings labeling the ticks). The location of the ticks is determined by a Locator object and the ticklabel strings are formatted by a Formatter. The combination of the correct Locator and Formatter gives very fine control over the tick locations and labels.

本质上figure上所有能看到的,包括axes、axis、线条、文本都是artist。figure渲染后,所有的artist都画在画布上。绝大多数的artist归属于某一axes。

Artist

Basically everything you can see on the figure is an artist (even the FigureAxes, and Axis objects). This includes Text objects, Line2D objects, collection objects, Patch objects ... (you get the idea). When the figure is rendered, all of the artists are drawn to the canvas. Most Artists are tied to an Axes; such an Artist cannot be shared by multiple Axes, or moved from one to another.

二、QGraphicsView显示matplotlib绘制的柱状图

使用QtDesigner设置了界面后,有一个界面需要显示柱状图。查了Pyqt5可通过matplotlib绘制柱状图。参考下面文档绘制。

https://www.cnblogs.com/laoniubile/p/5904817.html

Figure、axis和axes的介绍如下:

https://matplotlib.org/api/_as_gen/matplotlib.figure.Figure.html

https://matplotlib.org/api/axis_api.html

https://matplotlib.org/api/axes_api.html

https://matplotlib.org/api/artist_api.html

第一步,通过matplotlib.backends.backend_qt5agg类来连接PyQt5,这里涉及到后端的概念

后端官网介绍:https://matplotlib.org/faq/usage_faq.html#what-is-a-backend

matplotlib经常用在python shell中用作交互式编程,也有将其作为类似wxpython和pygtk这样的图形化界面使用,也有将其用在网络应用服务器中动态提供图片。因此为了能够包含所有的这些需求,matplotlib提供了指向不同输出的后端,相对应的前端就是用户编写使用的代码接口。后端包含两类,一类是user interface backends(用于pygtk, wxpython, tkinter, qt4, or macosx这类的交互式后端),另一类则是hardcopy backends(主要用于PNG, SVG, PDF, PS这类图片渲染并保存)。


 

import matplotlib
matplotlib.use("Qt5Agg")
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
from matplotlib import pyplot

pyplot.rcParams['font.sans-serif'] = ['SimHei']
pyplot.rcParams['axes.unicode_minus'] = False

第二步:具体图形代码实现,关键在于每次绘图后需要self.fig.canvas.draw() 刷新画布。开始没有该语句,只有第一个图能显示。后面用axes重新绘制图片后,显示不再刷新。为了找到问题的原因,将重新绘制的图片用self.fig.savefig(filename)保存下来,看看是绘制的原因,还是显示的原因。结果发现添加savefig之后显示也正常了,保存的图片也正常了。

savefig做了什么操作使显示刷新呢,在figure源文件中可以看到执行了self.canvas.print_figure(fname, **kwargs)

为什么执行该步骤就能刷新呢,为了找到print_figure的源码,传递了一个错误参数使print_figure执行失败。

终于找到了在backend_qt5agg.py中定义了print_figure方法,其中有个draw()方法用于画布刷新。

class FigureCanvasQTAgg(FigureCanvasAgg, FigureCanvasQT):


    def print_figure(self, *args, **kwargs):
        super().print_figure(*args, **kwargs)
        self.draw()
class Figure_Bar(FigureCanvasQTAgg):

    def __init__(self, width ,height , parent = None):

        self.fig = pyplot.figure(figsize=(width, height), facecolor='#666666', dpi= 100, edgecolor='#0000FF')
        FigureCanvasQTAgg.__init__(self, self.fig )
        self.setParent(parent)

        self.myAxes = self.fig.add_subplot(111)

        self.x = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 ]

    def ShowImage(self, axisX, axisY ):
        filename = os.getcwd() + "/" + datetime.datetime.now().strftime('%H-%M-%S.%f') + ".png"

        #由于图片需要反复绘制,所以每次绘制前清空,然后绘图,最后刷新显示。
        self.myAxes.clear()
      
        self.myAxes.bar(self.x, axisY, width = 0.02, color = 'blue', align = 'center', tick_label =  axisX )

        # 刷新画布,否则不刷新显示
        self.fig.canvas.draw()  

第三步,GUI上通过QGraphicsView控件呈现matplotlib画出来的图形

        #获取graphicsView的长和宽单位为像素,Figure的单位是inches,在DPI为100时,除以100转换为inches
        width = self.graphicsView.width()
        height = self.graphicsView.height()

        self.myImage = Figure_Bar(width/100, height/100)

      
        self.myGraphyScene = QGraphicsScene()
        #取消水平和垂直滚动条
        self.graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) 
        self.graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.myQGraphicsProxyWidget = self.myGraphyScene.addWidget(self.myImage)
        self.graphicsView.setScene(self.myGraphyScene)

        #每次显示不同图像,只需调用ShowImage方法
        self.myImage.ShowImage(self.axisXcontent, self.axisYcontent)

猜你喜欢

转载自blog.csdn.net/bluewhu/article/details/104937341
今日推荐