サイトマップ

Pythonでインタラクティブなグラフの保存

普段は、matplotlibで作ったグラフをpngに保存して、会議等では報告しているのですが、
その場でグラフの縮小等のインタラクティブな操作がしたい時があります。

mpld3を使います。
https://mpld3.github.io/

まずは、普通にプロットします。
基本的に、matplotlibで出力した後に、「mpld3.show()」をすれば、
ブラウザが立ち上がり表示されます。

#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt 
import mpld3

fig = plt.figure() 
plt.xlabel("xlabel 1") 
plt.ylabel("ylabel 1") 
plt.title("Plot 1") 
x = np.linspace(0,2*np.pi)
y = np.sin(x)
y2 = np.cos(x)
plt.plot(x, y, 'ro-', lw=3, label='test1')
plt.plot(x, y2, 'bo-', lw=3, label='test2')
plt.legend()

mpld3.save_html(fig, 'test.html')

mpld3.show(fig)

途中のsave_htmlでhtml形式で保存もできます。
メイン部分を流用すれば下図のようにブログにも貼れます。
左下のアイコンで操作できます。


また、凡例のインタラクティブモードもあるようです。
Interactive legend plugin — Bringing Matplotlib to the Browser
が、私の環境では、このまま実行したらエラーになりました。

  File "/Users/XXXX.py", line 40, in <module>
    mpld3.show()

  File "/Users/XXXX/.pyenv/versions/3.6.1/Python.framework/Versions/3.6/lib/python3.6/site-packages/mpld3/_display.py", line 360, in show
    html = fig_to_html(fig, **kwargs)

  File "/Users/XXXX/.pyenv/versions/3.6.1/Python.framework/Versions/3.6/lib/python3.6/site-packages/mpld3/_display.py", line 253, in fig_to_html
    figure_json=json.dumps(figure_json, cls=NumpyEncoder),

  File "/Users/matsuoka/.pyenv/versions/3.6.1/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 238, in dumps
    **kw).encode(obj)

  File "/Users/XXXX/.pyenv/versions/3.6.1/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)

  File "/Users/XXXX/.pyenv/versions/3.6.1/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)

  File "/Users/XXXX/.pyenv/versions/3.6.1/Python.framework/Versions/3.6/lib/python3.6/site-packages/mpld3/_display.py", line 140, in default
    return json.JSONEncoder.default(self, obj)

  File "/Users/XXXX/.pyenv/versions/3.6.1/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 180, in default
    o.__class__.__name__)

TypeError: Object of type 'ndarray' is not JSON serializable

Numpy形式の変換でエラーになっているようです。
_display.pyのNumpyEncoderにndarrayの場合を追加すれば良いようです。

class NumpyEncoder(json.JSONEncoder):
    """ Special json encoder for numpy types """

    def default(self, obj):
        if isinstance(obj, (numpy.int_, numpy.intc, numpy.intp, numpy.int8,
            numpy.int16, numpy.int32, numpy.int64, numpy.uint8,
            numpy.uint16,numpy.uint32, numpy.uint64)):
            return int(obj)
        elif isinstance(obj, (numpy.float_, numpy.float16, numpy.float32, 
            numpy.float64)):
            return float(obj)
        elif isinstance(obj, numpy.ndarray):
            return obj.tolist()
        return json.JSONEncoder.default(self, obj)

ここを参考にしました。
wtnvenga.hatenablog.com