PysimpleGUIで3つの方法でmatplotlibのグラフ表示


####はじめに
PysimpleGUIでmatplotlibのグラフを表示するには、別Windowで表示する方法、sg.Imageを使う方法、Canvasを使う方法などがあります。それぞれの表示方法を覚えとして記載します。

####作成したデモ

（1）別Windowで表示する方法。

参考：[PySimpleGUIでMatplotlibのxyグラフを表示する。](https://qiita.com/Gyutan/items/705dcc643b880d4147a6)

（2）sg.Imageを使う方法
sg.Imageでは、png形式のBytesデータ渡さなければなりません。グラフをpngでSaveする際にByteIOを使います。

（3）Canvasを使う方法
Figureをcanvasに紐づけします。

参考：[PySimpleGUIにMatplotlibを埋め込みたい](https://qiita.com/bear_montblanc/items/cce4e8c58dfa236200f6)




####動作環境
Windows10　64bit
Anaconda
python 3.7
VSCode


#### (1) 別Windowで表示する方法

```python
"""
Matplotlibのグラフを別Winodwで表示

"""
import numpy as np
import matplotlib.pyplot as plt

import PySimpleGUI as sg

def make_data_fig(make=True):
    fig = plt.figure()

    if make:
        # x = np.linspace(0, 2*np.pi, 500)
        x = np.arange(0, 2*np.pi, 0.05*np.pi)
        ax = fig.add_subplot(111)
        ax.plot(x, np.sin(x))
        return fig

    else:
        return fig


def draw_plot(fig):
    
    plt.show(block=False)
    # block=Falseに指定。これが重要
    # コンソールは何も入力を受け付けなくなり、GUI を閉じないと作業復帰できない。

def del_plot(fig):
    
    # plt.cla(): Axesをクリア
    # plt.clf(): figureをクリア
    # plt.close(): プロットを表示するためにポップアップしたウィンドウをクローズ
    
    plt.close()
    

sg.theme('Light Blue 2')

layout = [[sg.Text('Graph Diasplay')],
          [sg.Button('Display',key='-display-'), sg.Button('clear',key='-clear-'), sg.Cancel()]
          ]

window = sg.Window('Plot', layout, location=(100, 100), finalize=True)

while True:
    event, values = window.read()

    if event in (None, 'Cancel'):
        break
    
    elif event == '-display-':
        fig_ = make_data_fig(make=True)
        draw_plot(fig_)
        
    elif event == '-clear-':
        del_plot(fig_)

window.close()

```

##### 実行例

プログラムを実行するとボタン画面が現れます。
![gui01.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165987/717484db-ba40-c7b7-5062-8c87ed59a912.jpeg)

Displayボタンを押すと別ウインドウでグラフが表示されます。

![gui02.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165987/218b4cf1-357d-1bd5-041a-452252bc36f6.jpeg)

clearボタンを押すとウインドウが閉じます。


#### (2) sg.Imageを使う方法

```python
"""
Matplotlibのグラフをsg.Imagenに埋め込む

"""
import io
import numpy as np
import matplotlib.pyplot as plt

import PySimpleGUI as sg

def make_data_fig(make=True):
    fig = plt.figure()
    
    if make:
        # x = np.linspace(0, 2*np.pi, 500)
        x = np.arange(0, 2*np.pi, 0.05*np.pi)
        ax = fig.add_subplot(111)
        ax.plot(x, np.sin(x))
        return fig
    
    else:
        return fig

def draw_plot_image(fig):
    item = io.BytesIO()
    plt.savefig(item, format='png')
    plt.clf()
    # plt.close('all')
    return item.getvalue()

sg.theme('Light Blue 2')

layout = [[sg.Text('Graph Diasplay')],
          [sg.Button('Display',key='-display-'), sg.Button('clear',key='-clear-'), sg.Cancel()],
          [sg.Image(filename='', key='-image-')]
          ]

window = sg.Window('Plot', layout, location=(100, 100), finalize=True)

while True:
    event, values = window.read()

    if event in (None, 'Cancel'):
        break
    
    elif event == '-display-':
        fig_ = make_data_fig()
        fig_bytes = draw_plot_image(fig_)
        window['-image-'].update(data=fig_bytes)

    elif event == '-clear-':
        fig_ = make_data_fig(False)
        fig_bytes = draw_plot_image(fig_)
        window['-image-'].update(data=fig_bytes)

window.close()

```

##### 実行例

プログラムを実行するとボタン画面が現れます。

![gui01.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165987/1e8bd5ce-4825-6601-c71f-984d92200d03.jpeg)



Displayボタンを押すとグラフが埋め込まれた表示になります。

![gui03.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165987/d748b1e3-9a4c-d127-58ac-98baa3113721.jpeg)


clearボタンを押すとグラフが消えます。

![gui04.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165987/aa995111-3e62-73a4-4fdd-73f6590d7c07.jpeg)


#### (3) Canvasを使う方法

```python
"""
MatplotlibのグラフをCanvasに埋め込む

"""
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

import PySimpleGUI as sg

fig = plt.figure(figsize=(5, 4))
ax = fig.add_subplot(111)

def make_data_fig(fig,make = True):
    
    if make:
        # x = np.linspace(0, 2*np.pi, 500)
        x = np.arange(0, 2*np.pi, 0.05*np.pi)
        ax.plot(x, np.sin(x))
        return fig
    
    else:
        ax.cla()
        return fig

def draw_figure(canvas, figure):
    figure_canvas = FigureCanvasTkAgg(figure, canvas)
    figure_canvas.draw()
    figure_canvas.get_tk_widget().pack(side='top', fill='both', expand=1)
    return figure_canvas


sg.theme('Light Blue 2')

layout = [[sg.Text('Graph Diasplay')],
          [sg.Button('Display',key='-display-'), sg.Button('clear',key='-clear-'), sg.Cancel()],
          [sg.Canvas(key='-CANVAS-')]
          ]

window = sg.Window('Plot', layout, location =(100,100), finalize=True)

# figとCanvasを関連付ける
fig_agg = draw_figure(window['-CANVAS-'].TKCanvas, fig)

while True:
    event, values = window.read()

    if event in (None, 'Cancel'):
        break
    
    elif event == '-display-':
        fig = make_data_fig(fig, make=True)
        fig_agg.draw()
        
    elif event == '-clear-':
        fig = make_data_fig(fig, make=False)
        fig_agg.draw()

window.close()

```

##### 実行例

プログラムを実行するボタンとグラフ表示画面が現れます。

![gui05.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165987/79a0daf3-d77b-b730-dd9a-51099ffad61a.jpeg)


Displayボタンを押すとグラフがが表示されます。

![gui06.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165987/63a3bf7f-72c9-467c-9964-1cb5984207f8.jpeg)

#### まとめ

PysimpleGUIでmatplotlibのグラフを表示する3つの方法についてデモを示しました。（（1）別Windowで表示する方法、（2）sg.Imageを使う方法、（3）Canvasを使う方法。）

お手軽に表示するには（1）の方法が良いです。 plt.show(block=False)にするのがポイントです。（2）と（3）についてはそれなりに面倒ですが、私は（2）の方が理解しやすいです。png形式に保存する際にio.BytesIO()を使うのがポイントです。