gpt4 book ai didi

matplotlib - 在 PyQt (pyqtgraph) 中嵌入 "Figure Type"Seaborn Plot

转载 作者:行者123 更新时间:2023-12-01 10:31:53 24 4
gpt4 key购买 nike

我正在使用 PyQt ( pyqtgraph ) 的包装器来构建 GUI 应用程序。
我希望嵌入 Seaborn使用 MatplotlibWidget 在其中绘制.但是,我的问题是 Seaborn 包装方法如 FacetGrid不接受外部图形 handle 。此外,当我尝试使用 .fig 生成的图形更新 MatplotlibWidget 对象底层图形( FacetGrid )时它不起作用( draw 之后没有情节)。任何解决方法的建议?

最佳答案

Seaborn 的 Facetgrid提供了一个方便的功能,可以快速将 pandas 数据帧连接到 matplotlib pyplot 接口(interface)。

然而,在 GUI 应用程序中,您很少想要使用 pyplot,而是使用 matplotlib API。

您在这里面临的问题是 Facetgrid已经创建了自己的matplotlib.figure.Figure对象(Facetgrid.fig)。此外,MatplotlibWidget
创建自己的图形,因此您最终得到两个图形。

现在,让我们退后一步:
原则上可以使用 seaborn Facetgrid在 PyQt 中绘图,首先创建绘图,然后将生成的图形提供给图形 Canvas (matplotlib.backends.backend_qt4agg.FigureCanvasQTAgg)。以下是如何执行此操作的示例。

from PyQt4 import QtGui, QtCore
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
import sys
import seaborn as sns
import matplotlib.pyplot as plt

tips = sns.load_dataset("tips")


def seabornplot():
g = sns.FacetGrid(tips, col="sex", hue="time", palette="Set1",
hue_order=["Dinner", "Lunch"])
g.map(plt.scatter, "total_bill", "tip", edgecolor="w")
return g.fig


class MainWindow(QtGui.QMainWindow):
send_fig = QtCore.pyqtSignal(str)

def __init__(self):
super(MainWindow, self).__init__()

self.main_widget = QtGui.QWidget(self)

self.fig = seabornplot()
self.canvas = FigureCanvas(self.fig)

self.canvas.setSizePolicy(QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Expanding)
self.canvas.updateGeometry()
self.button = QtGui.QPushButton("Button")
self.label = QtGui.QLabel("A plot:")

self.layout = QtGui.QGridLayout(self.main_widget)
self.layout.addWidget(self.button)
self.layout.addWidget(self.label)
self.layout.addWidget(self.canvas)

self.setCentralWidget(self.main_widget)
self.show()


if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec_())

虽然这很好用,但它是否有用有点问题。在大多数情况下,在 GUI 内创建绘图的目的是根据用户交互进行更新。在上面的示例中,这是非常低效的,因为它需要创建一个新的图形实例,用这个图形创建一个新的 Canvas ,并用新的 Canvas 实例替换旧的 Canvas 实例,将其添加到布局中。

请注意,这个问题特定于 seaborn 中的那些绘图函数,它们在图形级别上工作,例如 lmplot , factorplot , jointplot , FacetGrid可能还有其他人。
其他功能如 regplot , boxplot , kdeplot在轴级别上工作并接受 matplotlib axes对象作为参数 ( sns.regplot(x, y, ax=ax1))。

一个 可能的解决方案是首先创建子图轴,然后绘制到这些轴,例如使用 pandas plotting functionality .
df.plot(kind="scatter", x=..., y=..., ax=...)

在哪里 ax应设置为先前创建的轴。
这允许在 GUI 中更新绘图。请参见下面的示例。当然,正常的 matplotlib 绘图( ax.plot(x,y))或使用上面讨论的 seaborn 轴水平函数同样有效。
from PyQt4 import QtGui, QtCore
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import sys
import seaborn as sns

tips = sns.load_dataset("tips")

class MainWindow(QtGui.QMainWindow):
send_fig = QtCore.pyqtSignal(str)

def __init__(self):
super(MainWindow, self).__init__()

self.main_widget = QtGui.QWidget(self)

self.fig = Figure()
self.ax1 = self.fig.add_subplot(121)
self.ax2 = self.fig.add_subplot(122, sharex=self.ax1, sharey=self.ax1)
self.axes=[self.ax1, self.ax2]
self.canvas = FigureCanvas(self.fig)

self.canvas.setSizePolicy(QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Expanding)
self.canvas.updateGeometry()

self.dropdown1 = QtGui.QComboBox()
self.dropdown1.addItems(["sex", "time", "smoker"])
self.dropdown2 = QtGui.QComboBox()
self.dropdown2.addItems(["sex", "time", "smoker", "day"])
self.dropdown2.setCurrentIndex(2)

self.dropdown1.currentIndexChanged.connect(self.update)
self.dropdown2.currentIndexChanged.connect(self.update)
self.label = QtGui.QLabel("A plot:")

self.layout = QtGui.QGridLayout(self.main_widget)
self.layout.addWidget(QtGui.QLabel("Select category for subplots"))
self.layout.addWidget(self.dropdown1)
self.layout.addWidget(QtGui.QLabel("Select category for markers"))
self.layout.addWidget(self.dropdown2)

self.layout.addWidget(self.canvas)

self.setCentralWidget(self.main_widget)
self.show()
self.update()

def update(self):

colors=["b", "r", "g", "y", "k", "c"]
self.ax1.clear()
self.ax2.clear()
cat1 = self.dropdown1.currentText()
cat2 = self.dropdown2.currentText()
print cat1, cat2

for i, value in enumerate(tips[cat1].unique().get_values()):
print "value ", value
df = tips.loc[tips[cat1] == value]
self.axes[i].set_title(cat1 + ": " + value)
for j, value2 in enumerate(df[cat2].unique().get_values()):
print "value2 ", value2
df.loc[ tips[cat2] == value2 ].plot(kind="scatter", x="total_bill", y="tip",
ax=self.axes[i], c=colors[j], label=value2)
self.axes[i].legend()
self.fig.canvas.draw_idle()


if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec_())

enter image description here

关于 的最后一句话pyqtgraph :我不会将 pyqtgraph 称为 PyQt 的包装器,而是将其称为扩展。尽管 pyqtgraph 附带了自己的 Qt(这使其可移植并且开箱即用),但它也是一个可以在 PyQt 中使用的包。因此,您可以添加 GraphicsLayoutWidget简单地通过 PyQt 布局
self.pgcanvas = pg.GraphicsLayoutWidget()
self.layout().addWidget(self.pgcanvas)

MatplotlibWidget 也是如此。 ( mw = pg.MatplotlibWidget())。虽然您可以使用这种小部件,但它只是一个方便的包装器,因为它所做的只是找到正确的 matplotlib 导入并创建一个 FigureFigureCanvas实例。除非您使用其他 pyqtgraph 功能,否则导入完整的 pyqtgraph 包只是为了节省 5 行代码对我来说似乎有点矫枉过正。

关于matplotlib - 在 PyQt (pyqtgraph) 中嵌入 "Figure Type"Seaborn Plot,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41671867/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com