MEP27: pyplot をバックエンドから切り離す#
ステータス番号
進捗
ブランチとプルリクエスト#
主な PR (GTK3 を含む):
バックエンド固有のブランチ差分:
アブストラクト#
この MEP はバックエンドをリファクタリングして、より構造化された一貫性のある API を提供し、一般的なコードを削除して既存のコードを統合します。これを行うために、分割を提案します。
FigureManagerBase
およびその派生クラスをコア機能クラスFigureManager
とバックエンド固有のクラス に変換しWindowBase
、ShowBase
およびその派生クラスをGcf.show_all
およびに変換しMainLoopBase
ます。
詳細な説明#
この MEP は、バックエンド API を 1 つの統一された API に統合し、バックエンドから汎用コード (
_pylab_helpers
およびを含むGcf
) を削除し、コードを matplotlib のより適切なレベルにプッシュすることを目的としています。これにより、バックエンドに応じてキャンバスを設定したり、ウィンドウ全体を指定されたサイズに設定したりするなど、バックエンドに現れる矛盾を自動的に取り除き
ます。FigureManagerBase.resize(w, h)
FigureManagerBase
およびから派生したクラスには、汎用コードの 2 つの主要な場所が表示されます
ShowBase
。
FigureManagerBase
現在、次の3 つのジョブがあります。ドキュメントでは、pyplot モードのヘルパー クラスとして説明されており、すべてがきちんとしたバンドルにまとめられています。
ただし、キャンバスとツールバーをラップするだけでなく、すべてのウィンドウ操作自体も実行します。これら 2 つのタスクの融合は、次の行で最もよく見られます。 これは、バックエンド固有のコードと matplotlib の汎用コードを組み合わせたものです。
self.set_window_title("Figure %d" % num)
self.set_window_title(title)
title = "Figure %d" % num
現在、 のバックエンド固有のサブクラスが
FigureManager
、メインループをいつ終了するかを決定します。フィギュアは他のフィギュアを制御してはならないので、これも非常に間違っているようです。
ShowBase
次の 2 つのジョブがあります。に登録されているすべてのフィギュアマネージャー
_pylab_helpers.Gcf
を調べて、自分自身を見せるように指示する仕事をしています.mainloop
そして第二に、メインプログラムをブロックするために特定のバックエンドを実行し 、数字が死なないようにする役割があります。
実装#
この MEP の説明から、ほとんどの解決策が得られます。
ウィンドウ処理の側面を取り除き、
FigureManagerBase
この新しいクラスを他のバックエンド クラスと一緒に単純にラップできるようにします。WindowBase
パススルー メソッド (:arrow_right:) を使用して、この機能を処理できる 新しいクラスを作成しますWindowBase
。サブクラス化するクラスWindowBase
は、下位互換性を確保するために、GUI 固有のウィンドウ クラスもサブクラス化する必要があります ( )。manager.window == manager.window
ShowBase
のメインループをintoにリファクタリングしMainLoopBase
ます。これにより、ループの最後もカプセル化されます。MainLoop
exit メソッドのロックを解除するキーとしてtoのインスタンスを 指定しますFigureManager
(ループが終了する前に、すべてのキーが返される必要があります)。これにより、複数のバックエンドが同時に実行される可能性が開かれることに注意してください。FigureManagerBase
にバックエンドの詳細が含まれていないため、名前を に変更し、次のことに注意してFigureManager
新しいファイルに移動します 。backend_managers.py
FigureManagerBase
これにより、既存のクラスとその依存関係をそのまま維持できるため、バックエンドの変換を個別の PR に分割できます。また、これは MEP22 を想定しており、新しいもの
NavigationBase
は独立したバックエンドに 変わりましたToolManager
。
FigureManagerBase(キャンバス, 数値) |
FigureManager(フィギュア, 数値) |
|
ノート |
---|---|---|---|
見せる |
見せる |
||
破壊する |
すべてのコンポーネントで destroy を呼び出します |
破壊する |
|
full_screen_toggle |
ロジックを扱う |
set_fullscreen |
|
サイズ変更 |
サイズ変更 |
||
key_press |
key_press |
||
get_window_title |
get_window_title |
||
set_window_title |
set_window_title |
||
_get_ツールバー |
FigureManagerBase のすべてのサブクラスに共通のメソッド |
||
set_default_size |
|||
add_element_to_window |
ShowBase |
MainLoopBase |
ノート |
---|---|---|
メインループ |
始める |
|
終わり |
サブクラスのインスタンスが存在しなくなると、自動的に呼び出されます |
|
__電話__ |
メソッドを Gcf.show_all に移動 |
将来の互換性#
上記の MEP 22 について説明したときに回避されたように、このリファクタリングにより、新しい一般的な機能を簡単に追加できます。現時点では、MEP 22 は から拡張された各クラスに醜いハックを作成する必要がありFigureManagerBase
ます。このコードでは、これを単一のFigureManager
クラスで行うだけで済みます。これにより、後の非推奨も
非常に簡単になり、単一のクラスNavigationToolbar2
に触れるだけで済みますFigureManager
MEP 23 では、このリファクタリングされたコードが非常に役立つ別のユース ケースが用意されています。
下位互換性#
すべてのバックエンド コードをそのままにして、不足しているメソッドを既存のクラスに追加するだけなので、これはすべてのユース ケースでシームレスに機能するはずです。FigureManager.resize
唯一の違いは、API の標準化により、ウィンドウではなくキャンバスのサイズを変更していたバックエンド
にあります。
このリファクタリングによって廃止されたクラスは廃止され、 と同じタイムテーブルで削除されることを想像します
。また、コンストラクタNavigationToolbar2
への呼び出しシグネチャの変更にも注意してください。FigureCanvasWx
下位互換性はありますが、古い(私見醜いスタイル)シグネチャは廃止されるべきだと思います他のすべてと同じ方法で削除されます。
バックエンド |
manager.resize(w,h) |
追加 |
---|---|---|
gtk3 |
窓 |
|
Tk |
キャンバス |
|
Qt |
窓 |
|
横 |
キャンバス |
FigureManagerWx は
|
代替案#
同じ問題を解決する別の解決策がある場合は、選択したアプローチの正当性とともに、ここで説明する必要があります。
質問#
Mdehoon: 複数のバックエンドを同時に実行する方法について詳しく教えてください。
OceanWolf: @mdehoon、私が言うように、この MEP のためではありませんが、この MEP は将来の可能性としてそれを開くと思います。基本的に、このMainLoopBase
クラスはバックエンド Gcf ごとに機能します。この MEP では、バックエンドごとに開いている図の数を追跡し、それらのバックエンドのメインループを管理します。そのバックエンドに対して開いたままの Figure がないことを検出すると、バックエンド固有のメインループを閉じます。このため、わずかな微調整だけで、完全なマルチバックエンドの matplotlib を実行できると思います。なぜそうしたいのかはまだわかりませんが、可能性を MainLoopBase に残しておきます。すべてのバックエンド コードの詳細がリファクタリングされてFigureManager
いるため、1 つのマネージャーがそれら (バックエンド) をすべて管理します。
Mdehoon: @OceanWolf さん、説明ありがとうございます。バックエンド用の統一された API を持つことは、matplotlib の保守性にとって非常に重要です。この MEP は正しい方向への一歩だと思います。