2015-01-14 11 views
20

私は多くの異なるmatplotlibの図を生成するpython(2.7)プログラムで作業しています(データはランダムではありません)。私は生成された数字が正しいことを確認するために(unittestを使って)何らかのテストを実装しようと思います。たとえば、予想される図(データまたは画像)をある場所に保存し、関数を実行して結果を参照と比較します。これを行う方法はありますか?matplotlibを使用するコードに対して単体テストを書く方法は?

答えて

19

私のexperienceでは、画像比較テストの結果、価値があるよりも多くのトラブルが発生します。これは、多少異なるフォントや描画バックエンドを持つ複数のシステム(TravisCIなど)間で継続的な統合を実行する場合に特に当てはまります。機能が完全に正しく機能している場合でもテストを通過させるためには、多くの作業が必要です。さらに、この方法をテストするには、gitリポジトリに画像を保存する必要があります。コードを頻繁に変更すると、リポジトリが肥大化する可能性があります。

私の意見では、(1)matplotlibが実際に図形を正確に描画すると仮定し、(2)プロット関数によって返されたデータに対して数値テストを実行することです。 (。あなたが見てどこを知っている場合にも、常にAxesオブジェクト内でこのデータを見つけることができます)例えば

、あなたはこのような単純な機能をテストしたいと言う:

import numpy as np 
import matplotlib.pyplot as plt 
def plot_square(x, y): 
    y_squared = np.square(y) 
    return plt.plot(x, y_squared) 

あなたのユニットテストは、可能性があります

def test_plot_square1(): 
    x, y = [0, 1, 2], [0, 1, 2] 
    line, = plot_square(x, y) 
    x_plot, y_plot = line.get_xydata().T 
    np.testing.assert_array_equal(y_plot, np.square(y)) 

または、同等に、

def test_plot_square2(): 
    f, ax = plt.subplots() 
    x, y = [0, 1, 2], [0, 1, 2] 
    plot_square(x, y) 
    x_plot, y_plot = ax.lines[0].get_xydata().T 
    np.testing.assert_array_equal(y_plot, np.square(y)) 
+1

あなたのソリューションでは、プロットの結果を返す必要があります。返すことなく同じことをする方法はありますか?イチジクを「捕まえる」ことによって?私のプロット関数は "返す"ことができません。私が変更できる唯一の方法だが、私はしたくない。 –

+0

2番目の例を見ると、Axesオブジェクトをイントロスペクションして、その中にプロットを描画するために使用されるすべてのデータを見つける方法が示されています。 – mwaskom

+0

@mwaskom明示的に追加したmpl.collectionに対するテストを実行しているすべての経験はありますか?例えば'ax.add_collection(PatchCollection(...))'? –

9

Matplotlibはtesting infrastructureを有する。 docsから

import numpy as np 
import matplotlib 
from matplotlib.testing.decorators import image_comparison 
import matplotlib.pyplot as plt 

@image_comparison(baseline_images=['spines_axes_positions']) 
def test_spines_axes_positions(): 
    # SF bug 2852168 
    fig = plt.figure() 
    x = np.linspace(0,2*np.pi,100) 
    y = 2*np.sin(x) 
    ax = fig.add_subplot(1,1,1) 
    ax.set_title('centered spines') 
    ax.plot(x,y) 
    ax.spines['right'].set_position(('axes',0.1)) 
    ax.yaxis.set_ticks_position('right') 
    ax.spines['top'].set_position(('axes',0.25)) 
    ax.xaxis.set_ticks_position('top') 
    ax.spines['left'].set_color('none') 
    ax.spines['bottom'].set_color('none') 

:例えば はと比較する

このテストが実行された最初の時間は、何のベースライン画像は存在しないので、テストは失敗します。出力ファイル (この場合はresult_images/test_category/spines_axes_positions。*)をソースディレクトリ (この場合はlib/matplotlib/tests/baseline_images/test_category)のbaseline_imagesツリーの サブディレクトリにコピーします。テストを再実行するとき、テストは合格するはずです。

+0

は、私はあなたの方法を試してみたと私はEを得たように見えます不具合matplotlib.testing.decoratorsには、importErrorを生成する "import matplotlib.tests"があります:testsという名前のモジュールはありません。 私はいくつかの研究を行いましたが、実際にはmatplolibファイルにはテストモジュールはなく、ドキュメンテーションは静かではありません。誰かがそれを解決する方法を知っていますか? –

関連する問題