Я использую оболочку PyQt (pyqtgraph) для создания графического приложения. Я хочу вставить в него участок Seaborn, используя MatplotlibWidget. Однако моя проблема заключается в том, что метод обертки Seaborn, такой как FacetGrid
, не принимает внешнюю фигуру. Более того, когда я пытаюсь обновить объект MatplotlibWidget, лежащий в основе рисунка (.fig
), с рисунком, созданным FacetGrid
, он не работает (без графика после draw
). Любое предложение об обходном пути?Вложение "Figure Type" Seaborn Plot in PyQt (pyqtgraph)
ответ
Seaborn's Facetgrid
предоставляет удобную функцию для быстрого соединения данных с данными pandas с интерфейсом pyplot matplotlib.
Однако в приложениях GUI вы редко хотите использовать pyplot, а скорее API matplotlib.
Проблема, с которой вы сталкиваетесь, заключается в том, что Facetgrid
уже создает свой собственный объект matplotlib.figure.Figure
(Facetgrid.fig
). Кроме того, MatplotlibWidget создает свою собственную фигуру, поэтому вы получаете две цифры.
Теперь давайте вернемся немного назад: В принципе можно использовать Сиборн Facetgrid
участок в PyQt, сначала создавая сюжет, а затем обеспечивая полученную фигуру на фигуру холста (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_())
Хотя это работает нормально, это немного сомнительно, если оно вообще полезно. Создание сюжета внутри графического интерфейса в большинстве случаев имеет целью обновить его в зависимости от взаимодействия пользователя. В примере выше, это довольно неэффективно, поскольку для создания нового экземпляра фигуры потребуется создать новый холст с этой фигурой и заменить старый экземпляр canvas новым, добавив его в макет.
Обратите внимание, что эта проблематика является специфической для этих функций рисования в Сиборне, которые работают на уровне фигуры, как lmplot
, factorplot
, jointplot
, FacetGrid
и, возможно, другие.
Другие функции, такие как regplot
, boxplot
, kdeplot
работают на уровне осей и принимают matplotlib axes
объект в качестве аргумента (sns.regplot(x, y, ax=ax1)
).
possibile раствор должен сначала создать подзаговор осей, а затем и участок для этих осей, например, с помощью pandas plotting functionality.
df.plot(kind="scatter", x=..., y=..., ax=...)
, где ax
должны быть установлены в ранее созданных оси.
Это позволяет обновить график в графическом интерфейсе. См. Пример ниже. Разумеется, нормальный график matplotlib (ax.plot(x,y)
) или использование описанной выше функции уровня осей морского судна работают одинаково хорошо.
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_())
Заключительное слово о pyqtgraph: Я бы не назвал pyqtgraph обертку для PyQt, но больше в расширение,.Хотя pyqtgraph поставляется со своим Qt (что делает его переносимым и работает из коробки), это также пакет, который можно использовать из PyQt. Таким образом, вы можете добавить
GraphicsLayoutWidget
в макете PyQt просто
self.pgcanvas = pg.GraphicsLayoutWidget()
self.layout().addWidget(self.pgcanvas)
То же самое справедливо для MatplotlibWidget (mw = pg.MatplotlibWidget()
). Хотя вы можете использовать этот вид виджетов, это всего лишь удобная оболочка, поскольку все, что он делает, это поиск правильного импорта matplotlib и создание Figure
и FigureCanvas
экземпляра. Если вы не используете другие функции pyqtgraph, импортирование полного пакета pyqtgraph просто для сохранения 5 строк кода кажется мне немного лишним.
Это тщательный и хороший ответ, но ваше первое предложение неточно. – mwaskom
@mwaskom Пожалуйста, не стесняйтесь исправлять меня, если я ошибаюсь. Что еще вы бы назвали «FacetGrid», если бы не функция удобства? – ImportanceOfBeingErnest
Ну для начала, это класс, а не функция. – mwaskom
- 1. Bokeh annular_wedge plot in datetime type figure
- 2. Seaborn Plot не отображается
- 3. PyQtGraph и numpy realtime plot
- 4. ярлык ylab in timeSeries :: plot, type = 'o'
- 5. Вставка pyqtgraph в виджет вкладки Pyqt
- 6. Реализация pyqtgraph многопроцессорности в виджет pyqt
- 7. Lissajous figure in Direct3D
- 8. pyqtgraph объектов для pcolor plot llike matplotlib
- 9. Pyqtgraph string in x tick
- 10. loglog plot with matplotlib in pyqt - оси исчезают
- 11. log-log plot with seaborn jointgrid
- 12. Отключить полосы ошибок в Seaborn Bar Plot
- 13. Seaborn timeseries plot with multiple series
- 14. PyQt/PySide простой XY Plot widget
- 15. plot triangle in MATLAB
- 16. pcolor in plot plot matlab
- 17. open MATLAB figure in ubuntu
- 18. Hover tooltiptext in Rascal figure
- 19. Bokeh hovertool in multiple_line plot
- 20. Построение больших массивов в pyqtgraph
- 21. Изменить шрифт family in plot plot in R
- 22. Live Plotting with PyQtGraph in PyQt4 # 2
- 23. python fft plot "type error"
- 24. Вложение bokeh plot и datatable в колбе
- 25. 3D plot plot in real time
- 26. Overlaying Legend in Map Plot Covers Plot
- 27. Python - matplotlib - PyQT: plot to QPixmap
- 28. Layer plot in R
- 29. plot in node.js
- 30. plot shapefile in python
Является ли эта проблема действительно связана с MatplotlibWidget от pyqtgraph или она будет происходить таким же образом в рамках обычного графика matplotlib? Можете ли вы указать, что вы подразумеваете под «когда я пытаюсь обновить объект MatplotlibWidget, лежащий в основе рисунка (.fig), с рисунком, созданным FacetGrid»? Как вы обновляете фигуру с фигурой? Можете ли вы показать код, который пытается это сделать? – ImportanceOfBeingErnest