Python {Article075}

ようこそ「Python」へ...

PyScriptでCSVファイルをアップロードしてMatplotlibでグラフを作成する

この記事では、PyScriptを使用してCSVファイルをアップロードしてPandasのDataFrameに取り込み、Matplotlibでグラフを作成する方法を解説しています。 まずは、「GO LIVE DEMO」をクリックして「Live DEMO」をご覧ください。 なお、「Live DEMO」で使用するCSVファイルは 「ダウンロード」 をクリックして任意のフォルダに事前に保存しておいてください。

Visual Studio Code(VSC)からHTMLファイルをブラウザに表示するには「Live Serer」を使用します。 「Live Server」のインストール手順は「記事(Article073)」で解説しています。

説明文の左側に図の画像が表示されていますが縮小されています。 画像を拡大するにはマウスを画像上に移動してクリックします。 画像が拡大表示されます。拡大された画像を閉じるには右上の[X]をクリックします。 画像の任意の場所をクリックして閉じることもできます。

click image to zoom!
図A: PyScript DEMO #1
click image to zoom!
図B: PyScript DEMO #2
click image to zoom!
図C: PyScript DEMO #3


PyScriptでCSVファイルをPandasのDataFrameに取り込んで内容を表示する

  1. 新規HTMLファイルを作成してCSSを追加する

    Visual Studio Code(VSC)を起動したら新規HTMLファイルを作成します。 HTMLファイルが表示されたら「!」を入力してポップアップリストから「先頭行」クリックします。 HTMLのテンプレートが表示されたら行7のtitleを書き換えます。 さらに、行8-16のCSSを追加します。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>How to draw a Line Chart with PyScript using Matplotlib 🐍</title>  
        <style>      
            body {
              margin: 5% 5% !important;
            }
    
            .h1_article075 {
                font-size:xx-large;
            }
        </style>
             
    </head>
    <body>
    
    </body>
    </html>

  2. headセクションにlink, scriptを追加してPyScriptのCSS, JavaScriptライブラリを取り込む

    headセクションに行18-36を追加します。 行18-28ではJavaScriptの各種ライブラリを取り込んでいます。 行29-30ではPyScriptのCSSとJavScriptのライブラリを取り込んでいます。 行31-36ではPythonのライブラリを宣言しています。行34のpanelはバージョン番号を指定してください。 バージョン番号を指定しないと実行時に警告メッセージが表示されます。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>How to draw a Line Chart with PyScript using Matplotlib 🐍</title>  
        <style>      
            body {
              margin: 5% 5% !important;
            }
    
            .h1_article075 {
                font-size:xx-large;
            }
        </style>
    
        <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vega@5"></script>
        <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vega-lite@5"></script>
        <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>
        <script type="text/javascript" src="https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js"></script>
        <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.js"></script>
        <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.2.min.js"></script>
        <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.2.min.js"></script>
        <script type="text/javascript" src="https://unpkg.com/@holoviz/panel@0.13.0/dist/panel.min.js"></script>
        <script type="text/javascript">
            Bokeh.set_log_level("info");
        </script>      
        <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
        <script defer src="https://pyscript.net/alpha/pyscript.js"></script>       
        <py-env>
          - numpy
          - pandas
          - panel==0.13.1a2
          - matplotlib
        </py-env>      
    </head>
    <body>
    
    </body>
    </html>

  3. bodyセクションにHTMLのh1, div要素を配置する

    bodyセクションにh1, div要素を追加して配置します。 行8のdiv#fileinput要素には実行時に「input type="file"」要素が挿入されます。 行9のdiv#upload要素には実行時に[Upload]の「button type="button"」要素が挿入されます。 行10のdiv#table要素には実行時にCSVファイルのデータが表示されます。 行12のdiv#draw要素には[Draw]の「button type="button"」要素が挿入されます。 行13のdiv#plot要素にはグラフが作成されます。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        :::     
    </head>
    <body>
        <h1 class="h1_article075">Draw a Line Chart with PyScript using Matplotlib 🐍</h1>  
        <div id="fileinput"></div>
        <div id="upload"></div>
        <div id="table"></div> 
        <hr />
        <div id="draw"></div>
        <div id="plot"></div>         
    </body>
    </html>

  4. bodyセクションにpy-scriptを追加してPythonのコードを追加する

    bodyセクションに<py-script>...</py-script>を追加してPythonのコードを記述します。 行16-23ではPythonのライブラリを取り込んでいます。 行27-32の関数「process_file()」では、アップロードされたCSVファイルをPandasのDataFrameに取り込んで表形式(Tabulator)で表示しています。

    行34-46の関数「draw_chart()」では、CSVファイルのデータをグラフで表示します。 ここでは中国、インド、日本、米国の年度別の人口の線グラフを作成しています。 行48ではHTMLの「button type="file" accept=".csv"」要素を生成しています。 行49ではHTMLの「button type="button"」要素(Upload)を生成しています。 行51ではTabulator要素を生成しています。 行53ではTabulatorのpager(ページ移動ボタン)を非表示にしています。 行55ではHTMLの「button type="button"」要素(Draw)を生成しています。 行57-58ではbutton要素にクリック時のイベントを設定しています。 行60-63ではdiv要素に行48-58で生成したHTML要素を挿入しています。 つまり、実行時に生成した各種HTML要素をブラウザ上に表示しています。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        :::   
    </head>
    <body>
        <h1 class="h1_article075">Draw a Line Chart with PyScript using Matplotlib 🐍</h1>  
        <div id="fileinput"></div>
        <div id="upload"></div>
        <div id="table"></div> 
        <hr />
        <div id="draw"></div>
        <div id="plot"></div> 
        
        <py-script>
    import asyncio
    import panel as pn
    import pandas as pd
    from panel.io.pyodide import show
    
    import matplotlib
    import matplotlib.pyplot as plt
    import numpy as np
    
    df = pd.DataFrame()
    
    def process_file(event):
        global df      
        if fileInput.value is not None:
            df = pd.read_csv(io.BytesIO(fileInput.value))
            table.value = df
            document.getElementById('table').style.display = 'block'
    
    def draw_chart(event):
        plt.style.use('dark_background')      
        fig, ax = plt.subplots()    
        countries_to_look_at = ['China', 'India', 'Japan', 'United States']    
        for country in df:    
            console.log(country)
            if country in countries_to_look_at:        
                ax.plot(df.SurveyYear, df[country], label=country, marker='.')
    
        ax.set(xlabel='Year', ylabel='Population', title='Population Line Graph')
        ax.legend()
        ax.grid()
        pyscript.write('plot', fig)
    
    fileInput = pn.widgets.FileInput(accept='.csv')
    uploadButton = pn.widgets.Button(name='Upload', button_type = 'primary')
    
    table = pn.widgets.Tabulator(pagination='remote', page_size=10)
    # hide pagination 'First, Prev [1][2][3] Next, Last'
    document.getElementById('table').style.display = 'none'
    
    drawButton = pn.widgets.Button(name='Draw', button_type = 'primary')
    
    uploadButton.on_click(process_file)
    drawButton.on_click(draw_chart)
    
    await show(fileInput, 'fileinput')
    await show(uploadButton, 'upload')
    await show(table, 'table') 
    await show(drawButton, 'draw')
        </py-script>    
    </body>
    </html>

  5. HTMLファイルのすべてを掲載

    最後にここで解説したHTMLファイルのすべてを掲載しましたので参考にしてください。 ここで使用するCSVファイルは当サイトからダウンロードすることができます。
    csv file:
    https://money-or-ikigai.com/Menu/Python/Article/data/article075/WorldPopulation.csv
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>How to draw a Line Chart with PyScript using Matplotlib 🐍</title>  
        <style>      
            body {
              margin: 5% 5% !important;
            }
    
            .h1_article075 {
                font-size:xx-large;
            }
        </style>
    
        <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vega@5"></script>
        <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vega-lite@5"></script>
        <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>
        <script type="text/javascript" src="https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js"></script>
        <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.js"></script>
        <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.2.min.js"></script>
        <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.2.min.js"></script>
        <script type="text/javascript" src="https://unpkg.com/@holoviz/panel@0.13.0/dist/panel.min.js"></script>
        <script type="text/javascript">
            Bokeh.set_log_level("info");
        </script>      
        <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
        <script defer src="https://pyscript.net/alpha/pyscript.js"></script>       
        <py-env>
          - numpy
          - pandas
          - panel==0.13.1a2
          - matplotlib
        </py-env>      
    </head>
    <body>
        <h1 class="h1_article075">Draw a Line Chart with PyScript using Matplotlib 🐍</h1>  
        <div id="fileinput"></div>
        <!-- <input type="file" accept=".csv"> -->
        <div id="upload"></div>
        <!-- <button type="button" pys-onclick="process_file">Upload</button> -->
        <div id="table"></div> 
        <hr />
        <div id="draw"></div>
        <!-- <button type="button" pys-onclick="draw_chart">Draw</button> -->
        <div id="plot"></div> 
        
        <py-script>
    import asyncio
    import panel as pn
    import pandas as pd
    from panel.io.pyodide import show
    
    import matplotlib
    import matplotlib.pyplot as plt
    import numpy as np
    
    df = pd.DataFrame()
    
    def process_file(event):
        global df      
        if fileInput.value is not None:
            df = pd.read_csv(io.BytesIO(fileInput.value))
            # columns = ['Population_Total', 'Australia', 'Brazil', 'Canada', 'Indonesia', 'Italy', 'United Kingdom']
            # df.drop(columns, axis=1, inplace=True)
            table.value = df
            document.getElementById('table').style.display = 'block'
    
    def draw_chart(event):
        plt.style.use('dark_background')      
        fig, ax = plt.subplots()    
        countries_to_look_at = ['China', 'India', 'Japan', 'United States']    
        for country in df:    
            console.log(country)
            if country in countries_to_look_at:        
                ax.plot(df.SurveyYear, df[country], label=country, marker='.')
    
        ax.set(xlabel='Year', ylabel='Population', title='Population Line Graph')
        ax.legend()
        ax.grid()
        pyscript.write('plot', fig)
    
    fileInput = pn.widgets.FileInput(accept='.csv')
    uploadButton = pn.widgets.Button(name='Upload', button_type = 'primary')
    
    table = pn.widgets.Tabulator(pagination='remote', page_size=10)
    # hide pagination 'First, Prev [1][2][3] Next, Last'
    document.getElementById('table').style.display = 'none'
    
    drawButton = pn.widgets.Button(name='Draw', button_type = 'primary')
    
    uploadButton.on_click(process_file)
    drawButton.on_click(draw_chart)
    
    await show(fileInput, 'fileinput')
    await show(uploadButton, 'upload')
    await show(table, 'table') 
    await show(drawButton, 'draw')
        </py-script>    
    </body>
    </html>

  6. HTMLファイルをブラウザに表示する

    Visual Studo Code(VSC)からHTMLファイルをブラウザに表示するには、「Live Server」を使用します。 「Live Server」のインストールと操作については「記事(Article073)」で解説しています。 VSCから「Explorer」アイコンをクリックしてHTMLファイルの一覧を表示します。 一覧からHTMLファイルを右クリックしてポップアップリストから先頭の「Open with Live Server」をクリックします。
    click image to zoom!
    図1-1
    ブラウザにHTMLファイルが表示されたら「ファイルを選択」をクリックしてCSVファイルを選択します。 ファイルを「開く」ダイアログが表示されたらCSVファイルを選択します。 ここでは「WorldPopulation.csv」を選択しています。 最後に[開く]ボタンをクリックしてダイアログを閉じます。


    click image to zoom!
    図1-2
    CSVファイルを選択したら[Upload]ボタンをクリックしてアップロードします。 アップロードが完了するとCSVファイルの内容が表形式(Tabulator)で表示されます。 表示されたデータは、ベージ番号をクリックしてページを移動したり列名をクリックしてデータを昇順・降順に並べ替えることができます。


    click image to zoom!
    図1-3
    [Draw]ボタンをクリックすると年度別の人口が線グラフで表示されます。 ここでは中国、インド、日本、米国のデータのみ表示しています。


HTMLファイルから実行するPyScriptのコードを外部ファイルに作成する

  1. 新規Pythonファイルを作成する

    新規のPythonファイル「article075_main.py」を作成したら前出のPythonのコードをコピペして外部ファイルに移動します。
    article075_main.py:
    
    import asyncio
    import panel as pn      
    import pandas as pd
    from panel.io.pyodide import show  
    from js import console  
    
    import matplotlib
    import matplotlib.pyplot as plt
    import numpy as np
    
    df = pd.DataFrame()
    
    def process_file(event):
        global df      
        if fileInput.value is not None:
            df = pd.read_csv(io.BytesIO(fileInput.value))
            table.value = df
            document.getElementById('table').style.display = 'block'
    
    def draw_chart(event):
        plt.style.use('dark_background')      
        fig, ax = plt.subplots()    
        countries_to_look_at = ['China', 'India', 'Japan', 'United States']    
        for country in df:    
            console.log(country)
            if country in countries_to_look_at:        
                ax.plot(df.SurveyYear, df[country], label=country, marker='.')
    
        ax.set(xlabel='Year', ylabel='Population', title='Population Line Graph')
        ax.legend()
        ax.grid()
        pyscript.write('plot', fig)
    
    fileInput = pn.widgets.FileInput(accept='.csv')
    uploadButton = pn.widgets.Button(name='Upload', button_type = 'primary')
    
    table = pn.widgets.Tabulator(pagination='remote', page_size=10)
    # hide pagination 'First, Prev [1][2][3] Next, Last'
    document.getElementById('table').style.display = 'none'
    
    drawButton = pn.widgets.Button(name='Draw', button_type = 'primary')
    
    uploadButton.on_click(process_file)
    drawButton.on_click(draw_chart)
    
    await show(fileInput, 'fileinput')
    await show(uploadButton, 'upload')
    await show(table, 'table') 
    await show(drawButton, 'draw')
  2. HTMLファイルのPythonのコードを外部ファイルから取り込む

    前出のHTMLファイルからPythonのコードを削除します。 そして、行50を追加します。 さらに「py-script」要素に「src=」属性を追加してPythonの外部ファイル「article075_main.py」のパスを設定します。 Pythonの外部ファイルは「./python」フォルダに格納されています。 Pythonのコードが多いときは、Pythonのコードを外部ファイルに格納することをお勧めします。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>How to draw a Line Chart with PyScript using Matplotlib 🐍</title>  
        <style>      
            body {
              margin: 5% 5% !important;
            }
    
            .h1_article075 {
                font-size:xx-large;
            }
        </style>
    
        <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vega@5"></script>
        <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vega-lite@5"></script>
        <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>
        <script type="text/javascript" src="https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js"></script>
        <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.js"></script>
        <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.2.min.js"></script>
        <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.2.min.js"></script>
        <script type="text/javascript" src="https://unpkg.com/@holoviz/panel@0.13.0/dist/panel.min.js"></script>
        <script type="text/javascript">
            Bokeh.set_log_level("info");
        </script>      
        <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
        <script defer src="https://pyscript.net/alpha/pyscript.js"></script>       
        <py-env>
          - numpy
          - pandas
          - panel==0.13.1a2
          - matplotlib
        </py-env>      
    </head>
    <body>
        <h1 class="h1_article075">Draw a Line Chart with PyScript using Matplotlib 🐍</h1>  
        <div id="fileinput"></div>
        <!-- <input type="file" accept=".csv"> -->
        <div id="upload"></div>
        <!-- <button type="button" pys-onclick="process_file">Upload</button> -->
        <div id="table"></div> 
        <hr />
        <div id="draw"></div>
        <!-- <button type="button" pys-onclick="draw_chart">Draw</button> -->
        <div id="plot"></div> 
        
        <py-script src="./python/article075_main.py"></py-script>
    </body>
    </html>

Live DEMO

注:この「Live DEMO」はスマホでは正常に動作しないことがありますのでパソコンでご覧ください。 それから、「Live DEMO」で使用するCSVファイルは「ダウンロード」 をクリックして任意のフォルダに事前に保存しておいてください。 「ファイルを選択」をクリックしてCSVファイルを選択したら[Upload]ボタンをクリックしてください。