Python {Article147}

ようこそ「Python」へ...

Python: Plotlyで線グラフ(Line Charts)を作成する (Plotly Express, Plotly Graph Objects【Plotly超入門】

ここでは、Plotlyを使用して線グラフ(Line Charts)を作成する方法を解説します。 Pythonでグラフを作成するためのライブラリとして、 Matplotlib、Seaborn、Plotly Express、Plotly Graph Objectsなどがあります。

MatplotlibはPythonで最も広く使われているグラフ描画ライブラリの1つで、 様々なグラフを作成することができます。線グラフ、ヒストグラム、散布図、バブルチャート、等々の作成ができます。 また、多数のカスタマイズオプションがあります。

Seabornは、統計データを視覚化するために設計されたPythonのデータ可視化ライブラリです。 Seabornを使用すると、Matplotlibよりも簡単に美しく見栄えのするグラフを作成することができます。 特に、箱ひげ図やヒートマップなど、統計分析でよく用いられるグラフの描画に優れています。

Plotlyは、インタラクティブなグラフを作成するために設計されたPythonライブラリです。 Plotlyを使用すると、HTMLでエクスポートできるブラウザで表示されるグラフを作成することができます。 また、Plotlyには、グラフの拡大・縮小や標準偏差などを示す誤差バーなどのインタラクティブな機能が多数あります。

MatplotlibとSeabornは、 静的なグラフを作成するために設計されたPythonライブラリであるのに対して、 Plotlyはインタラクティブなグラフを作成するために設計されています。 したがって、Plotlyは、グラフを拡大・縮小したり、マウスオーバーでデータ値を表示するなどのインタラクティブな操作が可能で、 より直感的なデータの解析ができるようになっています。 これは、MatplotlibやSeabornでは実現できない機能です。 それぞれのライブラリの用途と特徴をまとめると以下にようになります。
  • Matplotlib:
    • 2Dグラフ描画のためのデファクトスタンダード的なライブラリ
    • 線グラフ、散布図、ヒストグラム、棒グラフなど多数のグラフタイプに対応
    • グラフを細かくカスタマイズすることができ、高度なカスタマイズも可能
    • 豊富なドキュメントやチュートリアルがあり、比較的習得しやすい
  • Seaborn:
    • Matplotlibのラッパーライブラリの一つで、Matplotlibの機能を拡張したライブラリ
    • Matplotlibに比べて、より美しく見やすいグラフを作成できる
    • ヒストグラム、カーネル密度推定、箱ひげ図、散布図行列などの高度なグラフに対応
    • データの分布を可視化するための専用の機能を提供
    • ドキュメントが充実しており、初心者でも扱いやすい
  • Plotly Express:
    • Plotlyの高水準APIの一つで、より簡単にグラフを作成できる
    • MatplotlibやSeabornよりもインタラクティブなグラフを作成できる
    • 線グラフ、散布図、バブルチャート、棒グラフ、箱ひげ図、ヒートマップなど多数のグラフタイプに対応
    • グラフの色、軸の範囲、ラベルなどを簡単にカスタマイズできる
    • 簡単にアニメーション化することができる
  • Plotly Graph Objects:
    • Plotlyの低水準APIの一つで、より細かいカスタマイズが可能
    • グラフの全ての要素をコントロールすることができ、より高度なグラフを作成できる
    • グラフの軸、レイアウト、トレースなどの設定が可能
    • インタラクティブなグラフを簡単に作成することができる
    • ドキュメントが充実しており、高度なグラフを作成するための情報が豊富に提供されている
ここでは、Plotly Expressを中心に線グラフを作成する方法を解説します。 Plotly Expressで線グラフを作成するには、以下の手順で行うことをおすすめします。
  • Step1:
    Plotlyで各種グラフを作成するには、 「Plotly Graphing Library」のサイトから、 グラフの種類を選択します。 Plotlyのグラフは「Fundamentals」「Basic Charts」「Statistical Charts」「Scientific Charts」 「Financial Charts」「Maps」「Artificial Intelligence and Machine Learning」 「Bioinformatics」「3D Charts」「Subplots」などに分類されています。 たとえば、今回のように線グラフを作成したいときは、 「Line Charts」を選択します。

  • Step2:
    Line Charts」のサイトには、 線グラフを作成するためのサンプルコードと線グラフが掲載されています。 これらの中から自分が作成したいものに近い線グラフのサンプルを参考にしてカスタマイズします。

  • Step3:
    線グラフをカスタマイズするときは、 「plotly.express」 のサイトから 「line」 を選択します。

  • Step4:
    plotly.express.line」 のWebサイトには、線グラフを作成するための「line()」メソッドに指定する引数(プロパティ)の一覧とその説明が掲載されています。 これらの情報をもとに線グラフをカスタマイズします。
    plotly.express.line(
        data_frame=None, 
        x=None, y=None, 
        line_group=None, 
        color=None, 
        line_dash=None, 
        symbol=None, 
        hover_name=None, hover_data=None, 
        custom_data=None, 
        text=None, 
        facet_row=None, facet_col=None, facet_col_wrap=0, facet_row_spacing=None, facet_col_spacing=None, 
        error_x=None, error_x_minus=None, error_y=None, error_y_minus=None, 
        animation_frame=None, animation_group=None, 
        category_orders=None, 
        labels=None, 
        orientation=None, 
        color_discrete_sequence=None, color_discrete_map=None, 
        line_dash_sequence=None, line_dash_map=None, 
        symbol_sequence=None, symbol_map=None, 
        markers=False, 
        log_x=False, log_y=False, 
        range_x=None, range_y=None, 
        line_shape=None, 
        render_mode='auto', 
        title=None, 
        template=None, 
        width=None, height=None
        ) → plotly.graph_objects._figure.Figure  
  • Step5:
    最後に、 「update_traces() 」 「update_layout() 」 「update_annotations() 」 「 update_yaxes()」 「update_xaxes() 」 メソッドを使用して線グラフの細かい部分をカスタマイズして完了させます。 「update_layout()」メソッドは、 「frames, title, color, tick, hover, legend」などをカスタマイズするときに使用します。
説明文の左側に図の画像が表示されていますが縮小されています。 画像を拡大するにはマウスを画像上に移動してクリックします。 画像が拡大表示されます。拡大された画像を閉じるには右上の[X]をクリックします。 画像の任意の場所をクリックして閉じることもできます。
click image to zoom!
図A
click image to zoom!
図B
click image to zoom!
図C
click image to zoom!
図D
click image to zoom!
図E
click image to zoom!
図F
click image to zoom!
図G
click image to zoom!
図H
click image to zoom!
図I
click image to zoom!
図J

Plotlyで線グラフ(Line Charts)を作成する 【Plotly超入門】

  1. まずは、Pythonの開発環境を準備する

    まずは、 「記事(Article137)」を参照して、 Pythonの開発環境を準備してください。 ここでは、Pythonのプロジェクトフォルダとして「Plotly」を使用しています。

    click image to zoom!
    図1
    図1は、Visual Studio Code(VS Code)の「Terminal」メニューから「New Terminal」を選択して、 「Terminal」ウィンドウを開いたときの画面です。 緑色の「(venv)」が表示されていれば、 Pythonの仮想環境が正常に作成されていることになります。
  2. Visual Studio Codeを起動してプログラムファイルを作成する

    Pythonの開発環境の準備が完了したら、 VS Codeを起動して新規のPythonファイル(*.py)を作成します。 ここで作成したPythonのファイルには「リスト17-1」のコードをコピペします。

    click image to zoom!
    図2
    図2は、VS Codeの画面です。
  3. Plotlyのデフォルトのテーマをダークモードに設定する

    ここでは、pioクラスの「templates.defulat」に デフォルトのテーマ「plotly_dark」を設定してダークモードにしています。

    # set a defulat template
    pio.templates.default = 'plotly_dark'
    pio.templates
    click image to zoom!
    図3
    図3では、pioクラスの「templates」に格納されている、Plotlyのテーマの一覧を表示しています。
  4. Plotly Expressでシンプルな線グラフを作成して見る

    ここでは、Plotly Expressの「line()」メソッドに引数「x, y」を指定して、 年度別の人口の線グラフを表示しています。 引数「x」には「year(年度)」、引数「y」には「population(人口)」を指定しています。

    # 2: simple line chart
    add = "Simple Line Chart"
    text = f"px.line(x=year, y=population): {add}"
    
    year = [1950,1960,1970,1980,1990]
    population = [86459025,95831757,125956499,137065841,147467972]
    
    fig = px.line(x=year, y=population)
    
    fig.add_annotation(text=text, 
                       xref="paper", yref="paper",
                       x=0.0, y=1.2, 
                       showarrow=False)
    
    fig.show()
    click image to zoom!
    図4
    図4には、年度別の人口の線グラフが表示されています。 「x」軸と「y」軸のラベル名は自動的に表示されます。 ここでは、「line()」メソッドの引数「title」の代わりに「add_annotation()」メソッドでグラフの注釈を表示しています。
  5. 線グラフにタイトルを追加する

    ここでは、Plotly Expressの「line()」メソッドに引数「title」を追加して 図にタイトルを表示しています。

    # 3: add a title
    add = "title='Simple Line Chart'"
    title = f"px.line({add})"
    
    fig = px.line(x=year, y=population,
                  title=title
                 )
    
    fig.show()
    click image to zoom!
    図5-1
    図5-1では、図のタイトルを表示しています。

    click image to zoom!
    図5-2
    図5-2では、タイトルにhtmlの「<b style='color:red'>...</b>」を追加しています。
  6. Plotlyのデフォルトのテーマを変更する

    ここでは、Plotly Expressの「line()」メソッドに引数「template」を追加して テーマを「seaborn」に変えています。

    # 4: add a template (theme)
    add = "template='seaborn'"
    title = f"px.line({add})"
    
    fig = px.line(x=year, y=population,
                  template='seaborn',  
                  title=title                
                 )
    
    fig.show()
    
    click image to zoom!
    図6
    図6には、「seaborn」のテーマが表示されています。 図の背景色がダークモードから「白+灰色」に変わっています。
  7. Plotly ExpressのgapminderデータをPandasのDataFrameに取り込む

    ここでは、Plotly Expressが用意している「gapminder」データを PandasのDataFrameに取り込んで後述するステップで利用します。

    raw_df = px.data.gapminder()
    # raw_df.info()
    # raw_df['continent'].unique()
    # len(raw_df['country'].unique().tolist())     
    asia_df = raw_df.query("continent=='Asia'")
    # len(asia_df['country'].unique().tolist())
    japan_df = raw_df.query("country=='Japan'")
    # japan_df
    click image to zoom!
    図7-1
    図7-1では、「px.data.gapminder()」メソッドで 世界の各種データをPandasのDataFrameに取り込んでいます。 DataFrameは「country, continent, year, lifeExp, pop, gdpPercap,...」 などのカラムから構成されています。 「country」には「国名」、「continent」には「大陸名」、「year」には「年度」、 「lifeExp」には「平均寿命」、「pop」には「人口」、 「gdpPercap」には「一人当たりの国内総生産]が格納されています。

    click image to zoom!
    図7-2
    図7-2では、DataFrameのカラム「continent, country」の内容を表示しています。 「continent」には「Asia, Europe, Africa, Americas, Oceania」が格納されています。 「country」には、142カ国の国名が格納されています。 アジアには、33カ国の国名が格納されています。 「lifeExp, pop, gdpPercap...」などのデータは、1952年から2007年までのものが格納されています。
  8. Plotly Expressの「line()」メソッドに引数「color」を追加する

    ここでは、Plotly Expressの「line()」メソッドに引数「color」を追加して 線グラフの線の色を分けています。

    # 6: line chart : add a color
    add = "color='country'"
    title = f"px.line({add})"
    
    df = raw_df.query("country in ['Japan','China','India']")
    
    fig = px.line(df, 
                  x='year', y='pop', 
                  color='country',
                  title=title   
                 )
    
    fig.show()
    click image to zoom!
    図8
    図8には、中国、インド、日本の年度別の人口が線グラフで表示されています。 中国、インドの人口は増えていますが、日本の人口はほとんど変わっていません。
  9. Plotly Expressの「line()」メソッドに引数「labels」を追加する

    ここでは、Plotly Exressの「line()」メソッドに引数「labels」を追加して、 X軸、Y軸のラベル名と凡例を分かりやすくしています。

    # 7: line chart : add a labels
    add = "labels=dict(year='Year', pop='Population', country='Country',...)"
    title = f"px.line({add})"
    
    df = raw_df.query("country in ['Japan','China','India']")
    
    fig = px.line(df, 
                  x='year', y='pop', 
                  color='country',
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),
                  title=title   
                 )
    
    fig.show()
    click image to zoom!
    図9
    図9では、X軸、Y軸のラベル名がDataFrameのカラム名「year, pop」から 「Year, Population」に変わっています。 凡例も「country」から「Country」に変わっています。
  10. Plotly Expressの「line()」メソッドに引数「marker」を追加する

    ここでは、Plotly Exressの「line()」メソッドに引数「marker」を追加して、 年度ごとにマーカーを表示させます。

    # 8: line chart : add a marker
    
    # 8-1: line chart : marker=True
    add = "marker=True"
    title = f"px.line({add})"
    
    df = raw_df.query(f"country in ['Canada','Japan']")
    
    fig = px.line(df, 
                  x='lifeExp', y='gdpPercap',
                  color='country',
                  markers=True, 
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),             
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 8-2: line chart : marker=True => change a marker size
    add = "marker=True"
    traces = "marker=dict(size=10)"
    title = f"px.line({add}) + update_traces({traces}) "
    
    df = raw_df.query(f"country in ['Canada','Japan']")
    
    fig = px.line(df, 
                  x='lifeExp', y='gdpPercap',
                  color='country',
                  markers=True, 
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),             
                  title=title   
                 )
    
    fig.update_traces(marker=dict(size=10))
    
    fig.show()
    
    
    # %%
    
    # 8-3: line chart : marker=True, symbol='country'
    add = "marker=True, symbol='country'"
    title = f"px.line({add})"
    
    df = raw_df.query(f"country in ['Canada','Japan']")
    
    fig = px.line(df, 
                  x='lifeExp', y='gdpPercap',
                  color='country',
                  markers=True, symbol='country',             
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),             
                  title=title   
                 )
    
    fig.update_traces(marker=dict(size=10))
    
    fig.show()
    click image to zoom!
    図10-1
    図10-1には、該当する年度にマーカー「●」が表示されています。 マーカーがあると、ホバーテキストを表示させるときに便利です。 ホバーテキストには、「Country, Life expectancy, GDP per capita」がポップアップ表示されます。

    click image to zoom!
    図10-2
    図10-2では、「update_traces()」メソッドでマーカーのサイズを指定してマーカーを大きくしています。

    click image to zoom!
    図10-3
    図10-3では、「line()」メソッドに引数「symbol='country'」を追加して、 マーカーの形を国ごとに変えています。
  11. Plotly Expressの「line()」メソッドに引数「hover_name, hover_data」を追加する

    ここでは、Plotly Exressの「line()」メソッドに引数「hover_name, hover_data」を追加して、 ホバーテキストに表示されるデータを増やしています。

    # 9 line chart : add a hove_name & hover_data
    add = "hover_name='country', hover_data=['lifeExp']"
    title = f"px.line({add})"
    
    df = raw_df.groupby('country') \
            .agg({'pop': 'last'}) \
            .nlargest(5, 'pop') \
            .reset_index()
    top_5 = df['country'].values.tolist()
    
    df = raw_df.query(f"country in {top_5}")
    df = df.sort_values('pop', ascending=False).reset_index(drop=True)
    
    fig = px.line(df, 
                  x='year', y='pop', 
                  color='country',
                  markers=True,
                  hover_name='country',
                  hover_data=['lifeExp'],
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),             
                  title=title   
                 )
    
    fig.show()
    click image to zoom!
    図11
    図11には、ホバーテキストが表示されています。 「hover_name='country'」を追加すると、 ホバーテキストの上部に「China」のように国名が表示されます。 「hover_data=['lifeExp']」では、ホバーテキストに「平均寿命」も表示されるようにしています。 「hover_data」にはリスト型で複数のカラム名(DataFrameのカラム名)を指定することができます。
  12. Plotly Expressの「line()」メソッドに引数「text」を追加する

    ここでは、Plotly Exressの「line()」メソッドに引数「text」を追加して、 線グラフにテキストを表示させます。

    # 10: line chart : text
    
    # 10-1: line chart : text='year'
    add = "text='year'"
    title = f"px.line({add})"
    
    df = raw_df.query(f"country in ['Canada','Japan']")
    df = df.query("year >= 1980")
    
    fig = px.line(df, 
                  x='lifeExp', y='gdpPercap',
                  color='country',             
                  text='year',
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),               
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 10-2: line chart : text='lifeExp'
    add = "text='lifeExp'"
    title = f"px.line({add})"
    
    df = raw_df.groupby('country') \
            .agg({'pop': 'last'}) \
            .nlargest(3, 'pop') \
            .reset_index()
    top_3 = df['country'].values.tolist()
    df = raw_df.query(f"country in {top_3}")
    df = df.sort_values('pop', ascending=False).reset_index(drop=True)
    df['lifeExp'] = df['lifeExp'].apply(lambda x: math.floor(x))
    
    fig = px.line(df, 
                  x='year', y='pop',
                  color='country',
                  text='lifeExp',
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),              
                  title=title   
                 )
    
    fig.show()
    click image to zoom!
    図12-1
    図12-1では、線グラフに「年度」を表示させています。 これでいつの年度の平均寿命かが分かりやすくなります。

    click image to zoom!
    図12-2
    図12-2では、線グラフに「平均寿命」を表示させています。 つまり、図12-1とは逆になっています。 この線グラフでは、年度ごとに平均寿命がどのように変化しているかが視覚化できます。
  13. figureの「update_layout()」メソッドに「xaxis_tickangle=-45」を追加する

    ここでは、figureクラスの「update_layout()」メソッドに 引数「xaxis_tickangle」を追加してX軸の年度を斜めに表示させます。

    # 11: line chart : Rotated Line Chart Labels
    add = ""
    layout="xaxis_tickangle=-45"
    title = f"px.line({add}) + update_layout({layout})"
    
    df = raw_df.query("country in ['Japan','China','India']")
    
    fig = px.line(df, 
                   x='year', y='pop',
                   color='country',
                   labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'), 
                   title=title   
                )
    
    # fig.update_xaxes(
    #     color='red',
    #     tickangle=-45,
    # )
    
    fig.update_layout(xaxis_tickangle=-45)
    
    fig.show()
    click image to zoom!
    図13-1
    図13-1には、X軸の「年度」が斜めに表示されています。 ここでは、「update_layout()」メソッドを使用して「年度」を斜めにしています。

    click image to zoom!
    図13-2
    図13-2には、「年度」が赤色で斜めに表示されています。 ここでは、「update_xaxes()」メソッドを使用しています。
  14. Plotly ExpressのstocksデータをPandasのDataFrameに取り込む

    ここでは、Plotly Expressの「data.stocks()」メソッドを使用して、 株価のデータをPandasのDataFrameに取り込んで各種線グラフを作成します。

    # 12: stock
    # Configuring Tick Labels
    
    raw_df = px.data.stocks()
    # raw_df.info()
    # raw_df.head(3)
    # raw_df['date'].unique
    
    
    # %%
    
    # 12-1: line chart : simple stock line chart 
    add = "x='date', y='GOOG'"
    title = f"px.line({add}) : Simple stock line chart"
    
    df = raw_df.copy()
    
    fig = px.line(df, 
                  x='date', y='GOOG',
                  labels=dict(date='Date', GOOG='Google Stock Price'),
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 12-2: line chart : y=df.columns + update_xaxes(tickformat=...)
    add = "y=df.columns"
    xaxes = "tickformat='%b\n%Y')"
    title = f"px.line({add}) + update_xaxes({xaxes})"
    
    fig = px.line(df, 
                  x='date', y=df.columns,
                  hover_data={'date': '|%B %d, %Y'},
                  labels=dict(date='Date', value='Price (US $)', variable='Company'),
                  title=title
                 )
    
    fig.update_xaxes(
        tickformat='%b\n%Y' # 2018, Jan, Feb, Mar,...
        )    
    
    fig.show()
    
    
    # %%
    
    # 12-3: line chart : y=df.columns + update_xaxes(dtick='M1',tickformat=...)
    add = "y=df.columns"
    xaxes = "dtick='M1',tickformat='%b\n%Y')"
    title = f"px.line({add}) + update_xaxes({xaxes})"
    
    fig = px.line(df, 
                  x='date', y=df.columns,
                  hover_data={'date': '|%B %d, %Y'}, # Jan 11, 1918
                  labels=dict(date='Date', value='Price (US $)', variable='Company'),
                  title=title
                  )
    
    fig.update_xaxes(
        dtick='M1',
        tickformat='%b\n%Y' # 2018, Jan, Feb, Mar,...
        )    
    
    fig.show()
    
    
    # %%
    
    # 12-4: line chart : y=df.columns + update_xaxes(dtick='M1',tickformat=...)
    # Moving Tick Labels to the Middle of the Period
    add = "y=df.columns"
    xaxes = "dtick='M1',tickformat='%m/%d', ticklabelmode='period')"
    title = f"px.line({add}) + update_xaxes({xaxes})"
    
    df = raw_df.copy()
    
    fig = px.line(df, 
                  x='date', y=df.columns,
                  hover_data={'date': '|%B %d, %Y'},
                  labels=dict(date='Year 2019', value='Price (US $)', variable='Company'),
                  title=title
                  )
    
    fig.update_xaxes(
        dtick='M1',
        tickformat='%b\n%Y',    
        ticklabelmode='period'
        )
    
    fig.show()
    
    
    # %%
    
    # 12-5: line chart : y=df.columns + update_xaxes(dtick='M1',tickformat=...)
    add = "y=df.columns"
    xaxes = "dtick='M1',tickformat='%Y-%m-%d')"
    title = f"px.line({add}) + update_xaxes({xaxes})"
    
    fig = px.line(df, 
                  x='date', y=df.columns,
                  hover_data={'date': '|%Y-%m-%d'}, # 2018-01-15
                  labels=dict(date='Date', value='Price (US $)', variable='Company'),
                  title=title
                  )
    
    fig.update_xaxes(
        dtick='M1',
        tickformat='%Y-%m-%d'    # update tickformat to yyyy-mm-dd
        ) 
    
    fig.show()
    
    
    # %%
    
    # 12-6: line chart : y=df.columns + update_xaxes(dtick='M1',tickformat=...)
    add = "y=df.columns"
    xaxes = "dtick='M1',tickformat='%m/%d')"
    title = f"px.line({add}) + update_xaxes({xaxes})"
    
    # Convert date column to datetime object
    df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')
    df = df.query("date.dt.year == 2019")
    
    fig = px.line(df, x="date", y=df.columns,
                  hover_data={'date': '|%m/%d'}, # mm/dd
                  labels=dict(date='Year 2019', value='Price (US $)', variable='Company'),
                  title=title
                  )
    
    fig.update_xaxes(
        dtick='M1',
        tickformat='%m/%d'   # update tickformat to mm/dd
        ) 
    
    fig.show()
    click image to zoom!
    図14-1
    図14-1には、DataFrameの構造が表示されています。 DataFrameは「date, GOOG, AAPL, AMZN,...」などのカラムから構成されています。 つまり、GAFAMの株価が格納されています。

    click image to zoom!
    図14-2
    図14-2では、DataFrameのカラム「date」の内容(日付)を表示しています。 DataFrameには、「2018-01-08」から「2019-12-30」までの株価が格納されています。 日付は連続した「日付」ではなく飛び飛びになっています。

    click image to zoom!
    図14-3
    図14-3には、「Google」の株価が表示されています。 「line()」メソッドの引数「x」には「date」、 引数「y」には「GOOG」のカラムを指定しています。 これで「Google」の株価が表示されます。

    click image to zoom!
    図14-4
    図14-4には、DataFrameに格納されている全ての会社の株価が表示されています。 「line()」メソッドの引数「y」に「df.columns」を指定しているので、 DataFrameの全てのカラム「GOOG, APPL, AMZN,...」の株価が表示されます。 さらに、「update_xaxes()」メソッドの引数に「tickformat」を追加して X軸に表示される「年・月」をカスタマイズしています。 ここでは、「年度(%Y)」と「月(%b)」が表示されるようにしています。 「\n」は改行することを意味します。

    click image to zoom!
    図14-5
    図14-5では、「update_xaxes()」メソッドに引数「dtick='M1'」を追加して X軸に表示される「年・月」をカスタマイズしています。 「M1」は月単位で表示することを意味します。 たとえば、3ヶ月単位で表示させるときは「M3」を指定します。 通常、「dtick」は「tick0」とペアで使用します。 詳細は 「layout-xaxis」を参照してください。 図14-4では、「年・月」が横型で表示されていますが、 ここでは、「年・月」が縦型で表示されています。

    click image to zoom!
    図14-6
    図14-6では、「update_xaxes()」メソッドに引数「ticklabelmode='period'」を 追加して「月」を「中央」に表示させています。 図14-5と図14-6の「Jan, Feb, Mar,...」の表示位置を比較して見てください。

    click image to zoom!
    図14-7
    図14-7では、「update_xaxes()」メソッドの引数「tickformat」を「%Y-%m-%d」 のように変えています。 つまり、日付が「yyyy-mm-dd」の書式で表示されるようにしています。

    click image to zoom!
    図14-8
    図14-8では、「update_xaxes()」メソッドの引数「tickformat」を「%m/%d」 のように変えています。 つまり、日付が「mm/dd」の書式で表示されるようにしています。 X軸のラベルは「Date」から「Year 2019」に変えています。
  15. Plotly Expressの線グラフに「レンジ・スライダー」を表示する

    ここでは、figureクラスの「update_xaxes()」メソッドに引数 「rangeslider_visible=True」を追加して線グラフに「レンジ・スライダー」を表示させます。

    # 13: line chart : update_xaxes(rangeslider_visible=True)
    # Time Series With Range Slider
    add = "x='Date',y='AAPL.High'"
    xaxes = "rangeslider_visible=True"
    title = f"px.line({add}) + update_xaxes({xaxes})"
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
    # df.info()
    # df.head(3)
    # df.tail(3)
    
    fig = px.line(df, 
                  x='Date', 
                  y='AAPL.High', 
                  title=title
                 )
    
    fig.update_xaxes(rangeslider_visible=True)
    
    fig.show()
    click image to zoom!
    図15-1
    図15-1では、DataFrameの構造と内容を表示しています。 DataFrameには「Apple」の株価(Open, High, Low, Close,...)などが格納されています。 このDataFrameには、「2015-02-17」から「2017-02-16」までの株価が格納されています。

    click image to zoom!
    図15-2
    図15-2には、株価の線グラフとスライダーが表示されています。 スライダーにマウスを移動してドラッグしながら左右に移動させると、 グラフに表示させる年度を変えることができます。
  16. Plotly Expressの線グラフに「レンジ・セレクター」ボタンを表示する

    ここでは、figureクラスの「update_xaxes()」メソッドに引数 「rangeselector」を追加して線グラフに「レンジ・セレクター」ボタンを表示させます。

    # 14: line chart : update_xaxes(rangeslider_visible=True)
    # Time Series with Range Selector Buttons
    add = "x='Date',y='AAPL.High'"
    xaxes = "rangeslider_visible=True,rangeselector=..."
    title = f"px.line({add}) + update_xaxes({xaxes})"
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
    
    fig = px.line(df, 
                  x='Date', 
                  y='AAPL.High', 
                  title=title
                 )
    
    fig.update_xaxes(
        rangeslider_visible=True,
        rangeselector=dict(
            buttons=list([
                dict(count=1, label='1m', step='month', stepmode='backward'),
                dict(count=6, label='6m', step='month', stepmode='backward'),
                dict(count=1, label='YTD', step='year', stepmode='todate'),
                dict(count=1, label='1y', step='year', stepmode='backward'),
                dict(step="all")
            ]),
            font=dict(
                color='red',            
            )
        )
    )
    
    fig.show()
    click image to zoom!
    図16-1
    図16-1には、Appleの株価の線グラフが表示されています。 グラフの上部には「レンジ・セレクター」ボタンが表示されています。 グラフの下部には「レンジ・スライダー」が表示されています。 Plotly Expressの「line()」メソッドに指定している df(DataFrame)には、「2015-02-17」から「2017-02-16」までの株価が格納されています。 ここでは、「レンジ・セレクター」ボタンの[all]がクリックされた状態なので、 グラフには全期間の株価が表示されています。

    click image to zoom!
    図16-2
    図16-2には、「レンジ・セレクター」ボタンから[6m]をクリックしたときの グラフが表示されています。 X軸の「年月」には「Sep 2016」から「Feb 2017」の「6ヶ月間」の株価が表示されています。 [1y]ボタンをクリックすると「1年分」の株価が表示されます。
  17. 全てのコードを掲載

    ここでは、本記事で解説している全てのコードを掲載しています。

    リスト17-1: Article147.py
    # Article147 Plotly Line Charts v10.py
    # %%
    
    ### import the libraries
    import numpy as np
    import math
    import pandas as pd
    
    import plotly.io as pio
    import plotly.express as px
    import plotly.graph_objects as go
    
    
    # %%
    
    '''
    plotly.express.line(
        data_frame=None, 
        x=None, y=None, 
        line_group=None, 
        color=None, 
        line_dash=None, 
        symbol=None, 
        hover_name=None, hover_data=None, 
        custom_data=None, 
        text=None, 
        facet_row=None, facet_col=None, facet_col_wrap=0, facet_row_spacing=None, facet_col_spacing=None, 
        error_x=None, error_x_minus=None, error_y=None, error_y_minus=None, 
        animation_frame=None, animation_group=None, 
        category_orders=None, 
        labels=None, 
        orientation=None, 
        color_discrete_sequence=None, color_discrete_map=None, 
        line_dash_sequence=None, line_dash_map=None, 
        symbol_sequence=None, symbol_map=None, 
        markers=False, 
        log_x=False, log_y=False, 
        range_x=None, range_y=None, 
        line_shape=None, 
        render_mode='auto', 
        title=None, 
        template=None, 
        width=None, height=None
        ) → plotly.graph_objects._figure.Figure
    '''
    
    # %%
    
    # 1: set a defulat template
    pio.templates.default = 'plotly_dark'
    pio.templates
    
    
    # %%
    
    # 2: simple line chart
    add = "Simple Line Chart"
    text = f"px.line(x=year, y=population): {add}"
    
    year = [1950,1960,1970,1980,1990]
    population = [86459025,95831757,125956499,137065841,147467972]
    
    fig = px.line(x=year, y=population)
    
    fig.add_annotation(text=text, 
                       xref="paper", yref="paper",
                       x=0.0, y=1.2, 
                       showarrow=False)
    
    fig.show()
    
    
    # %%
    
    # 3: add a title
    add = "title='Simple Line Chart'"
    title = f"px.line({add})"
    
    fig = px.line(x=year, y=population,
                  title=title
                 )
    
    fig.show()
    
    
    # %%
    
    # 4: add a template (theme)
    add = "template='seaborn'"
    title = f"px.line({add})"
    
    fig = px.line(x=year, y=population,
                  template='seaborn',  
                  title=title                
                 )
    
    fig.show()
    
    
    # %%
    
    # 5: load data from plotly express gapminder()
    raw_df = px.data.gapminder()
    # raw_df.info()
    # raw_df['continent'].unique()
    # len(raw_df['country'].unique().tolist())     
    asia_df = raw_df.query("continent=='Asia'")
    # len(asia_df['country'].unique().tolist())
    japan_df = raw_df.query("country=='Japan'")
    # japan_df
    
    
    # %%
    
    # 6: line chart : add a color
    add = "color='country'"
    title = f"px.line({add})"
    
    df = raw_df.query("country in ['Japan','China','India']")
    
    fig = px.line(df, 
                  x='year', y='pop', 
                  color='country',
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 7: line chart : add a labels
    add = "labels=dict(year='Year', pop='Population', country='Country',...)"
    title = f"px.line({add})"
    
    df = raw_df.query("country in ['Japan','China','India']")
    
    fig = px.line(df, 
                  x='year', y='pop', 
                  color='country',
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 8: line chart : add a marker
    
    # 8-1: line chart : marker=True
    add = "marker=True"
    title = f"px.line({add})"
    
    df = raw_df.query(f"country in ['Canada','Japan']")
    
    fig = px.line(df, 
                  x='lifeExp', y='gdpPercap',
                  color='country',
                  markers=True, 
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),             
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 8-2: line chart : marker=True => change a marker size
    add = "marker=True"
    traces = "marker=dict(size=10)"
    title = f"px.line({add}) + update_traces({traces}) "
    
    df = raw_df.query(f"country in ['Canada','Japan']")
    
    fig = px.line(df, 
                  x='lifeExp', y='gdpPercap',
                  color='country',
                  markers=True, 
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),             
                  title=title   
                 )
    
    fig.update_traces(marker=dict(size=10))
    
    fig.show()
    
    
    # %%
    
    # 8-3: line chart : marker=True, symbol='country'
    add = "marker=True, symbol='country'"
    title = f"px.line({add})"
    
    df = raw_df.query(f"country in ['Canada','Japan']")
    
    fig = px.line(df, 
                  x='lifeExp', y='gdpPercap',
                  color='country',
                  markers=True, symbol='country',             
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),             
                  title=title   
                 )
    
    fig.update_traces(marker=dict(size=10))
    
    fig.show()
    
    
    # %%
    
    # 9 line chart : add a hove_name & hover_data
    add = "hover_name='country', hover_data=['lifeExp']"
    title = f"px.line({add})"
    
    df = raw_df.groupby('country') \
            .agg({'pop': 'last'}) \
            .nlargest(5, 'pop') \
            .reset_index()
    top_5 = df['country'].values.tolist()
    
    df = raw_df.query(f"country in {top_5}")
    df = df.sort_values('pop', ascending=False).reset_index(drop=True)
    
    fig = px.line(df, 
                  x='year', y='pop', 
                  color='country',
                  markers=True,
                  hover_name='country',
                  hover_data=['lifeExp'],
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),             
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 10: line chart : text
    
    # 10-1: line chart : text='year'
    add = "text='year'"
    title = f"px.line({add})"
    
    df = raw_df.query(f"country in ['Canada','Japan']")
    df = df.query("year >= 1980")
    
    fig = px.line(df, 
                  x='lifeExp', y='gdpPercap',
                  color='country',             
                  text='year',
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),               
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 10-2: line chart : text='lifeExp'
    add = "text='lifeExp'"
    title = f"px.line({add})"
    
    df = raw_df.groupby('country') \
            .agg({'pop': 'last'}) \
            .nlargest(3, 'pop') \
            .reset_index()
    top_3 = df['country'].values.tolist()
    df = raw_df.query(f"country in {top_3}")
    df = df.sort_values('pop', ascending=False).reset_index(drop=True)
    df['lifeExp'] = df['lifeExp'].apply(lambda x: math.floor(x))
    
    fig = px.line(df, 
                  x='year', y='pop',
                  color='country',
                  text='lifeExp',
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),              
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 11: line chart : Rotated Line Chart Labels
    add = ""
    layout="xaxis_tickangle=-45"
    title = f"px.line({add}) + update_layout({layout})"
    
    df = raw_df.query("country in ['Japan','China','India']")
    
    fig = px.line(df, 
                   x='year', y='pop',
                   color='country',
                   labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'), 
                   title=title   
                )
    
    # fig.update_xaxes(
    #     color='red',
    #     tickangle=-45,
    # )
    
    fig.update_layout(xaxis_tickangle=-45)
    
    fig.show()
    
    
    # %%
    
    # 12: stock
    
    # Configuring Tick Labels
    # https://plotly.com/python/time-series/
    
    raw_df = px.data.stocks()
    # raw_df.info()
    # raw_df.head(3)
    # raw_df['date'].unique
    
    
    # %%
    
    # 12-1: line chart : simple stock line chart 
    add = "x='date', y='GOOG'"
    title = f"px.line({add}) : Simple stock line chart"
    
    df = raw_df.copy()
    
    fig = px.line(df, 
                  x='date', y='GOOG',
                  labels=dict(date='Date', GOOG='Google Stock Price'),
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 12-2: line chart : y=df.columns + update_xaxes(tickformat=...)
    add = "y=df.columns"
    xaxes = "tickformat='%b\n%Y')"
    title = f"px.line({add}) + update_xaxes({xaxes})"
    
    fig = px.line(df, 
                  x='date', y=df.columns,
                  hover_data={'date': '|%B %d, %Y'},
                  labels=dict(date='Date', value='Price (US $)', variable='Company'),
                  title=title
                 )
    
    fig.update_xaxes(
        tickformat='%b\n%Y' # 2018, Jan, Feb, Mar,...
        )    
    
    fig.show()
    
    
    # %%
    
    # 12-3: line chart : y=df.columns + update_xaxes(dtick='M1',tickformat=...)
    add = "y=df.columns"
    xaxes = "dtick='M1',tickformat='%b\n%Y')"
    title = f"px.line({add}) + update_xaxes({xaxes})"
    
    fig = px.line(df, 
                  x='date', y=df.columns,
                  hover_data={'date': '|%B %d, %Y'}, # Jan 11, 1918
                  labels=dict(date='Date', value='Price (US $)', variable='Company'),
                  title=title
                  )
    
    fig.update_xaxes(
        dtick='M1',
        tickformat='%b\n%Y' # 2018, Jan, Feb, Mar,...
        )    
    
    fig.show()
    
    
    # %%
    
    # 12-4: line chart : y=df.columns + update_xaxes(dtick='M1',tickformat=...)
    # Moving Tick Labels to the Middle of the Period
    add = "y=df.columns"
    xaxes = "dtick='M1',tickformat='%m/%d', ticklabelmode='period')"
    title = f"px.line({add}) + update_xaxes({xaxes})"
    
    df = raw_df.copy()
    
    fig = px.line(df, 
                  x='date', y=df.columns,
                  hover_data={'date': '|%B %d, %Y'},
                  labels=dict(date='Year 2019', value='Price (US $)', variable='Company'),
                  title=title
                  )
    
    fig.update_xaxes(
        dtick='M1',
        tickformat='%b\n%Y',    # 2018 Jan, Feb, Mar,...
        ticklabelmode='period'
        )
    
    fig.show()
    
    
    # %%
    
    # 12-5: line chart : y=df.columns + update_xaxes(dtick='M1',tickformat=...)
    add = "y=df.columns"
    xaxes = "dtick='M1',tickformat='%Y-%m-%d')"
    title = f"px.line({add}) + update_xaxes({xaxes})"
    
    fig = px.line(df, 
                  x='date', y=df.columns,
                  hover_data={'date': '|%Y-%m-%d'}, # 2018-01-15
                  labels=dict(date='Date', value='Price (US $)', variable='Company'),
                  title=title
                  )
    
    fig.update_xaxes(
        dtick='M1',
        tickformat='%Y-%m-%d'    # update tickformat to yyyy-mm-dd
        ) 
    
    fig.show()
    
    
    # %%
    
    # 12-6: line chart : y=df.columns + update_xaxes(dtick='M1',tickformat=...)
    add = "y=df.columns"
    xaxes = "dtick='M1',tickformat='%m/%d')"
    title = f"px.line({add}) + update_xaxes({xaxes})"
    
    #   date	    GOOG	    AAPL	    AMZN	    FB	        NFLX	    MSFT
    # 0	2018-01-01	1.000000	1.000000	1.000000	1.000000	1.000000	1.000000
    # 1	2018-01-08	1.018172	1.011943	1.061881	0.959968	1.053526	1.015988
    # 2	2018-01-15	1.032008	1.019771	1.053240	0.970243	1.049860	1.020524
    
    # Convert date column to datetime object
    df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')
    df = df.query("date.dt.year == 2019")
    
    fig = px.line(df, x="date", y=df.columns,
                  hover_data={'date': '|%m/%d'}, # mm/dd
                  labels=dict(date='Year 2019', value='Price (US $)', variable='Company'),
                  title=title
                  )
    
    fig.update_xaxes(
        dtick='M1',
        tickformat='%m/%d'   # update tickformat to mm/dd
        ) 
    
    fig.show()
    
    
    # %%