在编辑器中,使用backend='graph'或者backend='mpl'切换后端。
效果图
from PyQt5.QtWidgets import QWidget
from pyminer2.extensions.packages.pmagg.PMAgg import Window
from pyminer2.extensions.packages.graph_agg.graph_agg import GraphAgg
import matplotlib.pyplot as plt
class Graph:
def __init__(self, app=None, widget: QWidget = None, subplots: tuple = (1, 1), backend: str = 'mpl'):
"""
:param widget: 将图绘制在哪个widget上,如果不指定,则默认使用pmagg的tabWidget,或其它绘图后端UI
:param figsize: 如绘制3*3个子图
:param backend: 选择mpl或者graph作为绘图后端
"""
self.axes = [[None]*subplots[1]]*subplots[0] # 二维数组,用于存储所有的子图对象
self.backend = backend
self.subplots = subplots
self.widget = widget
self.app = app
if (app and widget) is None and backend == 'mpl':
fig = plt.figure()
self.axes = fig.subplots(nrows=subplots[0], ncols=subplots[1])
if subplots == (1, 1):
self.axes = [[self.axes]]
else:
self.axes=self.axes.tolist()
self.app = Window(bg=self.backend)
self.app.get_canvas(fig)
self.widget = self.app.tabWidget.widget(self.app.tab_page_title_index) # 指定widget为pmagg的tab
if (app and widget) is None and backend == 'graph':
self.app=GraphAgg()
self.widget=self.app.widget
for row in range(subplots[0]):
for col in range(subplots[1]):
ax=self.widget.addPlot(row=row,col=col)
self.axes[row][col]=ax
# 在初始化过程中,需要提供app,widget,axes
def plot(self, x, y, position: tuple):
"""根据不同的绘图库,进行封装"""
row,col=position
if self.backend == 'mpl':
self.axes[row][col].plot(x, y)
if self.backend == 'graph':
self.widget.getItem(row,col).plot(x,y)
def show(self):
self.app.show()
if __name__ == '__main__':
graph = Graph(subplots=(3, 3),backend='graph')
graph.plot([1, 2, 3], [4, 5, 6], position=(0, 0))
graph.plot([1, 2, 3], [6, 5, 4], position=(0, 1))
graph.plot([1, 2, 3], [3, 5, 3], position=(0, 1))
graph.plot([1, 2, 3], [6, 3, 6], position=(0, 2))
graph.show()
在插件文件夹下创建了graph_agg文件夹,用来做将来的pyqtgraph的UI界面(名称可以后面再改)
在算法文件夹下创建了graph文件,用作绘图api的构建
统一的绘图api的好处,一是用户使用起来简单,提供多种绘图引擎,二是可以根据需要定制某些功能。
我这也只是搭了个简单的架子,对封装绘图函数有兴趣的朋友可以在graph.py文件下,写plot,scatter,三维图的方法封装。有人对pyqtgraph的UI界面包装感兴趣,可以在graph_agg文件夹下开展工作。
我的关注点之一是引入pyqtgraph可以解决哪些问题,pyqtgraph可以解决哪些matplotlib无法解决的问题?
首先是一些我关于绘图方面比较关注的问题。
我的关注点之二在于接口的顶层设计。
接口是面向用户的终端,而相对于界面可以进行多次迭代调整,接口一旦定义,只能增加功能,不可删减功能。
在进行接口的定义时,matlab与mpl的接口模式可以认为是目前较好的接口,可以沿用。
在引入pyqtgraph的过程中,有三种方案:
第一种,将pyqtgraph嵌入matplotlib的接口中,即将pyqtgraph作为一个matplotlib的Agg,
不过matplotlib似乎是有qt5agg的,这样的意义何在?
第二种,将pyqtgraph作为matplotlib并行的同样强大的接口而存在,定义一个pyminer_plot_backend
之类的配置项,然后对所有matplotlib的函数进行封装,通过分支判断采用何种接口。这需要实现所有的matplotlib函数,而这与matplotlib相比的优势在哪里?
第三种,脱离matplotlib,定义一套全新的接口,采用qt_*作为函数的前缀,比如qt_plot,qt_scatter等。
此时,可以将pyqtgraph作为一个专用的绘图包,专门解决一些matplotlib无法解决的问题,比如真三维绘图等。
这一部分我非常不关心,作为程序员,解决问题是家常便饭。明确目标与需求,写出代码并不需要很多时间。
关于开发新库,我的观点是一向是,先基于开源世界已有的内容进行整合,形成核心,打造python世界最好用的数据分析平台,然后再基于python社区的已有成果进行扩展。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
近期我在用pyqtgraph制作一款系统监视的软件,经过尝试,我对图形的设置选项有一点点建议。
paper_color
(用canvas_color
更严谨一些,但是paper_color
记忆难度较小)paper_opacity
text_color
legend_bg
legend_opacity
。线条颜色、散点颜色等。
line_color
line_width
line_type
border_color
(对于饼图、条形图则指图元的边缘线颜色)border_width
(对于饼图、条形图则指图元的边缘线宽度)fill_color
(对于饼图、条形图指图元的填充颜色)symbol_size
symbol_type
统一形状和颜色的名称,以matlab-matplotlib风格为主,为pyqtgraph提供一套转换。
具体如下:
symbols_dic = {'o': 'o', 's': 's', 't': 't', 't1': 't1', 't2': 't2', 't3': 't3',
'd': 'd', '+': '+', 'x': 'x', 'p': 'p', 'h': 'h', 'star': 'star',
'圆': 'o', '方': 's', '正三角': 't1', '倒三角': 't', '五边形': 'p', '六边形': 'h', '星': 'star',
'五星': 'star', '菱形': 'd'}
我写过一个类,在这里贴上来。绘图对象直接多继承这个类即可(类的属性不完全)。
from typing import Union
class PMGPlotCustomizer():
def __init__(self):
self._line_color = '#000000'
self._line_style = '--'
self._line_width = 2
self._border_color = '#000000'
self._border_width = 2
self._symbol = 't'
self._item_color = '#000000'
self._face_color = '#ffffff'
self._legend_face_color = '#ffffff'
self._symbols_dic = {}# 这里存储自定义的名称到线型映射。
@property
def border_color(self):
return self._border_color
@border_color.setter
def border_color(self, color: str):
self._border_color = color
@property
def border_width(self):
return self._border_width
@border_width.setter
def border_width(self, border_width: Union[int, float]):
self._border_width = border_width
@property
def face_color(self):
return self._face_color
@face_color.setter
def face_color(self, color: str):
self._face_color = color
@property
def item_color(self):
return self._item_color
@item_color.setter
def item_color(self, color: str):
self._item_color = color
@property
def line_color(self):
return self._line_color
@line_color.setter
def line_color(self, color: str):
self._line_color = color
@property
def line_style(self):
return self._line_style
@line_style.setter
def line_style(self, style: str):
self._line_style = style
@property
def line_width(self):
return self._line_width
@line_width.setter
def line_width(self, width: Union[int, float]):
assert isinstance(width, (int, float))
self._line_width = width
@property
def symbol(self):
return self._symbol
@symbol.setter
def symbol(self, symbol: str):
if symbol in self._symbols_dic.keys():
self._symbol = self._symbols_dic[symbol]
else:
raise ValueError(
'Symbol \'%s\' is not allowed.\nAll allowed symbols are:%s' % (symbol,
list(self._symbols_dic.keys())))
@property
def legend_face_color(self):
return self._legend_face_color
@legend_face_color.setter
def legend_face_color(self, color):
self._legend_face_color = color
当使用pyminer的内置编辑器书写绘图函数的时候,编辑器一端可以针对性的,对绘图设置项字符串进行补全。
我想我们是想要统一封装一个库给用户使用起来方便呢,还是为用户提供一个良好的图形化的界面来进行操作呢?
毕竟我们基于python的生态,我们需要再创建一套接口吗?
我觉得我们应该更加注重于常见图形的使用上,类似于业内有很多专业的作图工具,各种图形的基本轮廓由,由用户来进行数据填充以及少的设定就能得到其想要的图片,而不是让用户来学pyminer的统一作图接口来绘图
登录 后才可以发表评论