web-dev-qa-db-ja.com

これがmatplotlibの「$ DISPLAY環境がない」問題を解決するのはなぜですか?

デスクトップPCでmatplotlibライブラリを使用するコードを実行する場合、次の行を使用しても問題はありません。

import matplotlib.pyplot as plt

コードのはるか下で、実際にプロット関数を使用します。

サーバーでコードを実行すると、matplotlibbeforeをインポートし、Aggバックエンドを使用するように強制した場合にのみ機能します。つまり、コードの先頭に次の行を追加する必要があります。

import matplotlib
# Force matplotlib to not use any Xwindows backend.
matplotlib.use('Agg')

この回答 これが説明されている場所を参照してください)。そうしないと、コードがTclError: no display name and no $DISPLAY environment variableでクラッシュします(たとえば、 この質問 を参照)。

問題は、なぜこれを行う必要があるのか​​ということです。解決策は完全に機能しますが、デスクトップPCでこれを行う必要がない理由はわかりませんが、サーバーでコードを実行する場合は絶対に行う必要があります。

9
Gabriel

X11は、クライアント/サーバーモデルに従います。Xサーバーは、クライアントアプリケーション(インタラクティブなmatplotlibセッションなど)からのグラフィカル出力の要求を受け入れ、キーボード、マウスなどからユーザー入力を送り返します。このモデルが機能するには、クライアントアプリケーションが必要です。リクエストを送信するXサーバーを知るため。これは、_$DISPLAY_環境変数によって制御されます。リモートXセッションに接続している場合(たとえば、SSH接続を介して)、リモートセッションの_$DISPLAY_変数はローカルXサーバーを指す必要があります。

_$DISPLAY_変数は次のように構成されています。

_hostname:displaynumber.screennumber
_

すべての部分が存在するわけではありません。通常、ローカルセッションではホスト名が省略され、画面が1つしかない場合は画面番号も省略されます。ラップトップのローカルターミナルセッションでは、私の_$DISPLAY_は次のようになります。

_alistair@laptop:~$ echo $DISPLAY
:0
_

リモートサーバーがX11もサポートしている場合は、リモートマシンでグラフィカルウィンドウを開き、 X11転送 を使用してローカルマシンに表示させることができます。 SSH接続の場合、これを行うには、_-X_(または_-Y_)フラグを渡します。

例えば:

_alistair@laptop:~$ ssh -X [email protected]
alistair@workstation:~$ echo $DISPLAY
localhost:10.0
_

リモートSSHサーバーは、接続を開くときに_$DISPLAY_変数を適切に設定する必要があります。この特定のケースでは、_localhost:10.0_は実際にはリモートマシンで実行されている「プロキシ」X11サーバーであり、ディスプレイ10でリッスンし、SSH接続を介してローカルXサーバーにコマンドを中継します( これを見てください) 詳細に興味がある場合)。

これで、リモートIPythonセッションを開始し、インタラクティブなバックエンドを使用してmatplotlibをインポートし、ローカルマシンに表示されるプロットウィンドウを作成できるようになります。キーボード/マウス入力とディスプレイ出力が暗号化されたネットワーク接続を通過するようになったため、プロットウィンドウの応答性はローカルセッションに慣れているものよりも低くなります。

警告の別の言葉:インタラクティブなmatplotlibセッションを実行しているIPythonセッションを開いている場合、IPythonプロセスを強制終了せずにSSH接続を閉じることは不可能です。また、matplotlibをインポートする長時間実行プロセスを開始する前に、matplotlib.use("Agg")を呼び出すこともあります。これにより、プロセスを強制終了せずにリモートサーバーから切断できます。

10
ali_m