MEP27: pyplot をバックエンドから切り離す#

ステータス番号

進捗

ブランチとプルリクエスト#

主な PR (GTK3 を含む):

バックエンド固有のブランチ差分:

アブストラクト#

この MEP はバックエンドをリファクタリングして、より構造化された一貫性のある API を提供し、一般的なコードを削除して既存のコードを統合します。これを行うために、分割を提案します。

  1. FigureManagerBaseおよびその派生クラスをコア機能クラスFigureManagerとバックエンド固有のクラス に変換しWindowBase

  2. ShowBaseおよびその派生クラスをGcf.show_allおよびに変換しMainLoopBaseます。

詳細な説明#

この MEP は、バックエンド API を 1 つの統一された API に統合し、バックエンドから汎用コード ( _pylab_helpersおよびを含むGcf) を削除し、コードを matplotlib のより適切なレベルにプッシュすることを目的としています。これにより、バックエンドに応じてキャンバスを設定したり、ウィンドウ全体を指定されたサイズに設定したりするなど、バックエンドに現れる矛盾を自動的に取り除き ます。FigureManagerBase.resize(w, h)

FigureManagerBaseおよびから派生したクラスには、汎用コードの 2 つの主要な場所が表示されます ShowBase

  1. FigureManagerBase現在、次の3 つのジョブがあります。

    1. ドキュメントでは、pyplot モードのヘルパー クラスとして説明されており、すべてがきちんとしたバンドルにまとめられています。

    2. ただし、キャンバスとツールバーをラップするだけでなく、すべてのウィンドウ操作自体も実行します。これら 2 つのタスクの融合は、次の行で最もよく見られます。 これは、バックエンド固有のコードと matplotlib の汎用コードを組み合わせたものです。self.set_window_title("Figure %d" % num)self.set_window_title(title)title = "Figure %d" % num

    3. 現在、 のバックエンド固有のサブクラスがFigureManager 、メインループをいつ終了するかを決定します。フィギュアは他のフィギュアを制御してはならないので、これも非常に間違っているようです。

  2. ShowBase次の 2 つのジョブがあります。

    1. に登録されているすべてのフィギュアマネージャー_pylab_helpers.Gcfを調べて、自分自身を見せるように指示する仕事をしています.

    2. mainloopそして第二に、メインプログラムをブロックするために特定のバックエンドを実行し 、数字が死なないようにする役割があります。

実装#

この MEP の説明から、ほとんどの解決策が得られます。

  1. ウィンドウ処理の側面を取り除き、FigureManagerBaseこの新しいクラスを他のバックエンド クラスと一緒に単純にラップできるようにします。WindowBaseパススルー メソッド (:arrow_right:) を使用して、この機能を処理できる 新しいクラスを作成しますWindowBase。サブクラス化するクラスWindowBaseは、下位互換性を確保するために、GUI 固有のウィンドウ クラスもサブクラス化する必要があります ( )。manager.window == manager.window

  2. ShowBaseのメインループをintoにリファクタリングしMainLoopBaseます。これにより、ループの最後もカプセル化されます。MainLoopexit メソッドのロックを解除するキーとしてtoのインスタンスを 指定しますFigureManager(ループが終了する前に、すべてのキーが返される必要があります)。これにより、複数のバックエンドが同時に実行される可能性が開かれることに注意してください。

  3. FigureManagerBaseにバックエンドの詳細が含まれていないため、名前を に変更し、次のことに注意してFigureManager新しいファイルに移動します 。backend_managers.py

    1. FigureManagerBase これにより、既存のクラスとその依存関係をそのまま維持できるため、バックエンドの変換を個別の PR に分割できます。

    2. また、これは MEP22 を想定しており、新しいもの NavigationBaseは独立したバックエンドに 変わりましたToolManager

FigureManagerBase(キャンバス, 数値)

FigureManager(フィギュア, 数値)

WindowBase(title)

ノート

見せる

見せる

破壊する

すべてのコンポーネントで 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 は framewindow のエイリアスとして持っていたので、これも BC を壊します。

代替案#

同じ問題を解決する別の解決策がある場合は、選択したアプローチの正当性とともに、ここで説明する必要があります。

質問#

Mdehoon: 複数のバックエンドを同時に実行する方法について詳しく教えてください。

OceanWolf: @mdehoon、私が言うように、この MEP のためではありませんが、この MEP は将来の可能性としてそれを開くと思います。基本的に、このMainLoopBase クラスはバックエンド Gcf ごとに機能します。この MEP では、バックエンドごとに開いている図の数を追跡し、それらのバックエンドのメインループを管理します。そのバックエンドに対して開いたままの Figure がないことを検出すると、バックエンド固有のメインループを閉じます。このため、わずかな微調整だけで、完全なマルチバックエンドの matplotlib を実行できると思います。なぜそうしたいのかはまだわかりませんが、可能性を MainLoopBase に残しておきます。すべてのバックエンド コードの詳細がリファクタリングされてFigureManagerいるため、1 つのマネージャーがそれら (バックエンド) をすべて管理します。

Mdehoon: @OceanWolf さん、説明ありがとうございます。バックエンド用の統一された API を持つことは、matplotlib の保守性にとって非常に重要です。この MEP は正しい方向への一歩だと思います。