2017-01-16 25 views
2

私はPyQt(pyqtgraph)のラッパーを使ってGUIアプリケーションを構築しています。 MatplotlibWidgetを使用してSeabornプロットを埋め込みたいとします。しかし、私の問題は、FacetGridのようなSeabornラッパーメソッドは外部のFigureハンドルを受け入れないということです。さらに、FacetGridによって生成された図形(.fig)の基礎となるMatplotlibWidgetオブジェクトを更新しようとすると、機能しません(drawの後のプロットなし)。回避策の提案はありますか?PyQt(pyqtgraph)に "Figure Type" Seaborn Plotを埋め込む

+0

この問題は本当にpyqtgraphのMatplotlibWidgetに関連していますか、通常のmatplotlibプロット内で同じ方法で発生しますか? 「図形(.fig)のMatplotlibWidgetオブジェクトをFacetGridによって生成された図形で更新しようとすると」という意味を指定できますか?あなたは人物で人物をどのように更新しますか?これを試みるコードを表示できますか? – ImportanceOfBeingErnest

答えて

3

SeabornのFacetgridは、pandasデータフレームをmatplotlib pyplotインターフェイスにすばやく接続する便利な機能を提供します。

しかし、GUIアプリケーションでは、pyplotではなくmatplotlib APIを使用することはめったにありません。

ここで直面している問題は、Facetgridが既に独自のmatplotlib.figure.Figureオブジェクト(Facetgrid.fig)を作成していることです。また、MatplotlibWidget は独自の図形を作成するので、2つの図形になります。

さて、少しバックステップしてみましょう: 原理的には、最初のプロットを作成し、図のキャンバス(matplotlib.backends.backend_qt4agg.FigureCanvasQTAgg)に得られた数値を提供することで、PyQtは中seaborn Facetgridプロットを使用することが可能です。以下は、その方法の例です。

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内にプロットを作成することは、ユーザーのやりとりに応じて更新されることを目的としています。上の例の場合、新しい図形インスタンスを作成し、この図形で新しいキャンバスを作成し、古いキャンバスインスタンスを新しいキャンバスインスタンスに置き換えてレイアウトに追加する必要があるので、これはかなり非効率的です。このproblematicsはlmplotfactorplotjointplotFacetGridおよびおそらく他のような、図形レベルで動作seabornのものプロット関数、に特異的であること

注意。
regplot,boxplot,kdeplotのような他の関数は、軸レベルで動作し、matplotlib axesオブジェクトを引数(sns.regplot(x, y, ax=ax1))として受け入れます。


possibile溶液最初pandas plotting functionalityを使用して、例えば、それらの軸にサブプロット軸と後プロットを作成することです。

df.plot(kind="scatter", x=..., y=..., ax=...) 

ここで、axは、以前に作成された軸に設定する必要があります。
これにより、GUI内のプロットを更新できます。以下の例を参照してください。もちろん、通常のマットプロットライブプロット(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_()) 

enter image description here


最終単語について pyqtgraph:私はpyqtgraph PyQtは用のラッパーが、より多くの拡張子を呼び出すことはありません。pyqtgraphには独自のQt(ポータブルで自由に動作する)が付属していますが、Pyqt内で使用できるパッケージでもあります。そのため、同じことが MatplotlibWidgetmw = pg.MatplotlibWidget())についても同様で、単に

self.pgcanvas = pg.GraphicsLayoutWidget() 
self.layout().addWidget(self.pgcanvas) 

でPyQtはレイアウトにGraphicsLayoutWidgetを追加することができます。この種のウィジェットを使用することはできますが、これは便利なラッパーにすぎません。なぜなら、正しいmatplotlibのインポートを見つけ、FigureFigureCanvasというインスタンスを作成するだけだからです。他のpyqtgraph機能を使用していない限り、完全なpyqtgraphパッケージをインポートするだけで、5行のコードを保存することができます。

+0

これは徹底的で良い回答ですが、最初の文章は正確ではありません。 – mwaskom

+0

@mwaskom私が間違っている場合は、私を修正してください。便利な関数ではない場合、 'FacetGrid'と呼べるものは何ですか? – ImportanceOfBeingErnest

+0

初心者のために、それはクラスであり、関数ではありません。 – mwaskom

関連する問題