Python {Article148}

ようこそ「Python」へ...

Python: Plotlyで散布図(Scatter Plots)を作成する (Plotly Express, Plotly Graph Objects【Plotly超入門】

ここでは、Plotlyを使用して散布図(Scatter Plots)を作成する方法を解説します。 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」などに分類されています。 たとえば、今回のように散布図を作成したいときは、 「Scatter Plots」を選択します。

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

  • Step3:
    散布図をカスタマイズするときは、 「plotly.express」 のサイトから 「scatter」 を選択します。

  • Step4:
    plotly.express.scatter」 のWebサイトには、散布図を作成するための「scatter()」メソッドに指定する引数(プロパティ)の一覧とその説明が掲載されています。 これらの情報をもとに散布図をカスタマイズします。
    plotly.express.scatter(
        data_frame=None,    
        x=None, y=None,     
        color=None,         
        symbol=None,        
        size=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, 
        color_continuous_scale=None, 
        range_color=None, 
        color_continuous_midpoint=None, 
        symbol_sequence=None, 
        symbol_map=None, 
        opacity=None, 
        size_max=None, marginal_x=None, marginal_y=None, 
        trendline=None, trendline_options=None, 
        trendline_color_override=None, trendline_scope='trace', 
        log_x=False, log_y=False, 
        range_x=None, range_y=None, 
        render_mode='auto', 
        title=None,         
        template=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
click image to zoom!
図K
click image to zoom!
図L
click image to zoom!
図M

Plotlyで散布図(Scatter Plots)を作成する 【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のファイルには「リスト21-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の「scatter()」メソッドに引数「x, y」を指定して、 年度別の人口の散布図を表示しています。 引数「x」には「year(年度)」、引数「y」には「population(人口)」を指定しています。

    # 2: simple scatter plots
    add = "Simple Scatter Plots"
    text = f"px.scatter(x=year, y=population): {add}"
    
    year = [1950,1960,1970,1980,1990]
    population = [86459025,95831757,125956499,137065841,147467972]
    
    fig = px.scatter(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」軸のラベル名は自動的に表示されます。 ここでは、「scatter()」メソッドの引数「title」の代わりに 「add_annotation()」メソッドでグラフの注釈を表示しています。
  5. 散布図にタイトルを追加する

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

    # 3: add a title
    add = "title='Simple Scatter Plots'"
    title = f"px.scatter({add})"
    # title = f"px.scatter(<b style='color:red'>{add}</b>)"
    
    fig = px.scatter(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の「scatter()」メソッドに引数「template」 を追加して テーマを「seaborn」に変えています。

    # 4: add a template (theme)
    add = "template='seaborn'"
    title = f"px.scatter({add})"
    
    fig = px.scatter(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に取り込んで後述するステップで利用します。

    # 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  
    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」には「一人当たりの国内総生産]が格納されています。 「continent」には「Asia, Europe, Africa, Americas, Oceania」が格納されています。

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

    ここでは、Plotly Expressの「scatter()」メソッドに引数「color」を追加して 散布図のプロットの色を分けています。

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

    ここでは、Plotly Expressの「scatter()」メソッドに引数「color」を追加して 散布図のプロットのサイズを人口と連動させています。

    # 7: add a size
    add = "size='pop'"
    title = f"px.scatter({add})"
    
    df = raw_df.query("country in ['Japan','China','India']")
    
    fig = px.scatter(df, 
                  x='year', y='pop', 
                  size='pop',
                  color='country',
                  title=title   
                 )
    
    fig.show()  
    click image to zoom!
    図9
    図9には、中国、インド、日本の散布図が表示されています。 散布図のドットのサイズは人口と連動して変化しています。
  10. Plotly Expressの「scatter()」メソッドに引数「labels」を追加する

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

    # 8: add a labels
    add = "labels=dict(year='Year', pop='Population', country='Country',...)"
    title = f"px.scatter({add})"
    
    df = raw_df.query("country in ['Japan','China','India']")
    
    fig = px.scatter(df, 
                  x='year', y='pop', 
                  size='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!
    図10
    図10では、X軸、Y軸のラベル名がDataFrameのカラム名「year, pop」から 「Year, Population」に変わっています。 凡例も「country」から「Country」に変わっています
  11. Plotly Expressの「scatter()」メソッドに引数「symbol」を追加する

    ここでは、Plotly Exressの「scatter()」メソッドに引数「symbol」を追加して、 散布図のプロットの形を変えています。

    # 9: add a symbol
    add = "symbol='country'"
    title = f"px.scatter({add})"
    
    df = raw_df.query(f"country in ['Canada','Japan']")
    
    fig = px.scatter(df, 
                  x='lifeExp', y='gdpPercap',
                  size='gdpPercap',
                  color='country',
                  symbol='country',             
                  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には、カナダと日本の散布図が表示されています。 散布図のドットの形がカナダが「丸」、日本が「ダイヤモンド」になっています。
  12. Plotly Expressの「scatter()」メソッドに引数「hover_name, hover_data」を追加する

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

    # 10 : add a hove_name & hover_data
    add = "hover_name='country', hover_data=['lifeExp']"
    title = f"px.scatter({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)
    
    fig = px.scatter(df, 
                  x='year', y='pop', 
                  size='pop',
                  color='country',
                  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!
    図12
    図12には、ホバーテキストが表示されています。 「hover_name='country'」を追加すると、 ホバーテキストの上部に「China」のように国名が表示されます。 「hover_data=['lifeExp']」では、 ホバーテキストに「平均寿命」も表示されるようにしています。 「hover_data」にはリスト型で複数のカラム名(DataFrameのカラム名)を指定することができます。
  13. Plotly Expressの「scatter()」メソッドに引数「text」を追加する

    ここでは、Plotly Exressの「scatter()」メソッドに引数「text」を追加して、 散布図にテキストを表示させます。

    # 11: add a text
    add = "text='year'"
    traces = "marker=dict(size=20)"
    title = f"px.scatter({add}) + update_traces({traces})"
    
    df = raw_df.query(f"country in ['Canada','Japan']")
    df = df.query("year >= 1980")
    
    fig = px.scatter(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.update_traces(marker=dict(size=20))
    
    fig.show()  
    click image to zoom!
    図13
    図13では、散布図に「年度」を表示させています。 これでいつの年度の平均寿命かが分かりやすくなります。
  14. figureの「update_layout()」メソッドに「xaxis_tickangle=-45」を追加する

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

    # 12: rotate x ticks 
    add = ""
    layout="xaxis_tickangle=-45"
    title = f"px.scatter({add}) + update_layout({layout})"
    
    df = raw_df.query("country in ['Japan','China','India']")
    
    fig = px.scatter(df, 
                   x='year', y='pop',
                   size='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!
    図14-1
    図14-1には、X軸の「年度」が斜めに表示されています。 ここでは、「update_layout()」メソッドを使用して「年度」を斜めにしています。

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

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

    # 13: stock
    raw_df = px.data.stocks()
    # raw_df.info()
    # raw_df.head(3)
    # raw_df['date'].unique
    
    
    # %%
    
    # 13-1: simple stock scatter plots 
    add = "x='date', y='GOOG'"
    title = f"px.scatter({add}) : Simple stock scatter plots"
    
    df = raw_df.copy()
    
    fig = px.scatter(df, 
                  x='date', y='GOOG',
                  labels=dict(date='Date', GOOG='Google Stock Price'),
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 13-2: y=df.columns + update_xaxes(tickformat=...)
    add = "y=df.columns"
    xaxes = "tickformat='%b\n%Y')"
    title = f"px.scatter({add}) + update_xaxes({xaxes})"
    
    fig = px.scatter(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()
    
    
    # %%
    
    # 13-3: y=df.columns + update_xaxes(dtick='M1',tickformat=...)
    add = "y=df.columns"
    xaxes = "dtick='M1',tickformat='%b\n%Y')"
    title = f"px.scatter({add}) + update_xaxes({xaxes})"
    
    fig = px.scatter(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()
    
    
    # %%
    
    # 13-4: 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.scatter({add}) + update_xaxes({xaxes})"
    
    df = raw_df.copy()
    
    fig = px.scatter(df, 
                  x='date', y=df.columns,
                  hover_data={'date': '|%B %d, %Y'},
                  labels=dict(date='Year', value='Price (US $)', variable='Company'),
                  title=title
                  )
    
    fig.update_xaxes(
        dtick='M1',
        tickformat='%b\n%Y',    # 2018 Jan, Feb, Mar,...
        ticklabelmode='period'
        )
    
    fig.show()
    
    
    # %%
    
    # 13-5: y=df.columns + update_xaxes(dtick='M1',tickformat=...)
    add = "y=df.columns"
    xaxes = "dtick='M1',tickformat='%Y-%m-%d')"
    title = f"px.scatter({add}) + update_xaxes({xaxes})"
    
    fig = px.scatter(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()
    
    
    # %%
    
    # 13-6: scatter plots : y=df.columns + update_xaxes(dtick='M1',tickformat=...)
    add = "y=df.columns"
    xaxes = "dtick='M1',tickformat='%m/%d')"
    title = f"px.scatter({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.scatter(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()  
    
    # %%
    
    # 13-7: Apple stock scatter plots with trendline
    add = "trendline='ols'"
    title = f"px.scatter({add}) : Apple stock scatter plots with trendline"
    
    fig = px.scatter(df, 
                  x='date', y='AAPL',
                  labels=dict(date='Date', close='Close Price'),
                  trendline='ols',
                  title=title   
                 )
    
    fig.update_traces(line_color='red')
    
    fig.show()  
    click image to zoom!
    図15-1
    図15-1には、DataFrameの構造が表示されています。 DataFrameは「date, GOOG, AAPL, AMZN,...」などのカラムから構成されています。 つまり、GAFAMとNetflixの株価が格納されています。

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

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

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

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

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

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

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

    click image to zoom!
    図15-9
    図15-9では、Appleの株価を散布図にプロットしています。 さらに、株価のトレンドラインを「赤色」で表示しています。
  16. Plotly Expressの散布図に「レンジ・スライダー」を表示する

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

    # 14: 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)
    
    fig = px.scatter(df, 
                  x='Date', 
                  y='AAPL.High', 
                  title=title
                 )
    
    fig.update_xaxes(rangeslider_visible=True)
    
    fig.show()  
    click image to zoom!
    図16
    図16には、株価の散布図とスライダーが表示されています。 スライダーにマウスを移動してドラッグしながら左右に移動させると、 散布図に表示させる年度を変えることができます。
  17. Plotly Expressの散布図に「レンジ・セレクター」ボタンを表示する

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

    # 15: 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.scatter({add}) + update_xaxes({xaxes})"
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
    
    fig = px.scatter(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!
    図17-1
    図17-1には、Appleの株価の散布図が表示されています。 散布図の上部には「レンジ・セレクター」ボタンが表示されています。 散布図の下部には「レンジ・スライダー」が表示されています。 Plotly Expressの「scatter()」メソッドに指定している df(DataFrame)には、 「2015-02-17」から「2017-02-16」までの株価が格納されています。 ここでは、「レンジ・セレクター」ボタンの[all]がクリックされた状態なので、 散布図には全期間の株価がプロットされています。

    click image to zoom!
    図17-2
    図17-2には、「レンジ・セレクター」ボタンから[6m]をクリックしたときの 散布図が表示されています。 X軸の「年月」には「Sep 2016」から「Feb 2017」の「6ヶ月間」の株価がプロットされています。 [1y]ボタンをクリックすると「1年分」の株価がプロットされます。
  18. Plotly Expressの「scatter()」メソッドに引数「marginal_x, marginal_y」を追加する

    ここでは、Plotly Exressの「scatter()」メソッドに引数「 marginal_x='histogram', marginal_y='rug'」を追加して、 散布図に「ヒストグラム」と「ラグ」を表示させます。

    # 16: Marginal Distribution Plots
    
    add = "marginal_x='histogram', marginal_y='rug'"
    title = f"px.scatter({add})"
    
    df = px.data.iris()
    
    fig = px.scatter(df, 
                     x='sepal_length', y='sepal_width', 
                     marginal_x='histogram', marginal_y='rug',
                     title=title
                    )
    
    fig.show()  
    click image to zoom!
    図18
    図18には、散布図のX軸の上部に「ヒストグラム」、Y軸の右側に「ラグ」が表示されています。 ヒストグラムにマウスをホバリングさせると、 「sepal_length, count」が表示されます。 ラグにマウスをホバリングさせると、 「sepal_width」が表示されます。
  19. Plotly Expressの「scatter()」メソッドに引数「facet_col, facet_row」を追加する

    ここでは、Plotly Exressの「scatter()」メソッドに引数「facet_col='sex', facet_row='time'」を追加して、 4種類の散布図を表示させます。

    具体的には、facet_colとfacet_rowを使用して散布図を分割させています。 x軸には、DataFrameの「total_bill」を、y軸には「tip」を使用し、 「smoker」に基づいて点の色を分けます。 また、DataFrameの「sex」に基づいて行方向に散布図を分割し、 「time」に基づいて列方向に散布図を分割します。 これで4種類の散布図が同時に表示されます。

    # 17: Facetting
    
    add = "facet_col='sex', facet_row='time'"
    title = f"px.scatter({add})"
    
    df = px.data.tips()
    
    fig = px.scatter(df, 
                     x='total_bill', y='tip', 
                     color='smoker', 
                     facet_col='sex', facet_row='time',
                     title=title
                    )
    
    fig.show()  
    click image to zoom!
    図19
    図19には、4種類の散布図が表示されています。 左側には「女性」の「昼食・夕食」のチップの散布図が表示されています。 右側には「男性」の「昼食・夕食」のチップの散布図が表示されています。 なお、プロットの「赤」は「喫煙者」、「青」は「非喫煙者」を意味します。
  20. Plotly Expressの「scatter()」メソッドに引数「trendline」を追加する

    ここでは、Plotly Exressの「scatter()」メソッドに引数「trendline='ols'」を追加して、 散布図に「トレンド線」を表示させます。

    OLS(Ordinary Least Squares)回帰直線は、 データポイントの散らばりを最小限に抑える1次元の線形回帰モデルです。 OLS回帰直線は、XとYの関係を説明するために最も一般的に使用される回帰モデルの一つで、 独立変数(X)と従属変数(Y)の間の線形関係を推定するために使用されます。

    散布図にOLS回帰直線を追加することで、XとYの間の関係を直感的に理解することができます。

    # 18: Linear Regression and Other Trendlines
    
    add = "rendline='ols'"
    title = f"px.scatter({add})"
    
    df = px.data.tips()
    
    fig = px.scatter(df, 
                     x='total_bill', y='tip', 
                     trendline='ols', # 'ols', 'lowess', 'rolling', 'expanding' or 'ewm'
                     title=title
                    )
    
    # fig.update_traces(line_color='red')
    
    fig.show()  
    click image to zoom!
    図20-1
    図20-1には、食事の合計請求額とチップの「散布図」と「OSL回帰直線」が同時に表示されています。 「OSL回帰直線」を表示させると、食事の請求額とチップの関係を直感的に理解することができます。 この図では、請求金額が高くなるほどチップの金額も高くなることが理解できます。
    click image to zoom!
    図20-2
    図20-2では、「OSL回帰直線」の色を「赤色」に変えています。
  21. 全てのコードを掲載

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

    リスト21-1: Article148.py
    # Article148 Plotly Scatter Plots 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.scatter(
        data_frame=None,    ★
        x=None, y=None,     ★
        color=None,         ★
        symbol=None,        ★
        size=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, 
        color_continuous_scale=None, 
        range_color=None, 
        color_continuous_midpoint=None, 
        symbol_sequence=None, 
        symbol_map=None, 
        opacity=None, 
        size_max=None, marginal_x=None, marginal_y=None, 
        trendline=None, trendline_options=None, 
        trendline_color_override=None, trendline_scope='trace', 
        log_x=False, log_y=False, 
        range_x=None, range_y=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 scatter plots
    add = "Simple Scatter Plots"
    text = f"px.scatter(x=year, y=population): {add}"
    
    year = [1950,1960,1970,1980,1990]
    population = [86459025,95831757,125956499,137065841,147467972]
    
    fig = px.scatter(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 Scatter Plots'"
    # title = f"px.scatter({add})"
    title = f"px.scatter(<b style='color:red'>{add}</b>)"
    
    fig = px.scatter(x=year, y=population,
                  title=title
                 )
    
    fig.show()
    
    
    # %%
    
    # 4: add a template (theme)
    add = "template='seaborn'"
    title = f"px.scatter({add})"
    
    fig = px.scatter(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: add a color
    add = "color='country'"
    title = f"px.scatter({add})"
    
    df = raw_df.query("country in ['Japan','China','India']")
    
    fig = px.scatter(df, 
                  x='year', y='pop', 
                  color='country',
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 7: add a size
    add = "size='pop'"
    title = f"px.scatter({add})"
    
    df = raw_df.query("country in ['Japan','China','India']")
    
    fig = px.scatter(df, 
                  x='year', y='pop', 
                  size='pop',
                  color='country',
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 8: add a labels
    add = "labels=dict(year='Year', pop='Population', country='Country',...)"
    title = f"px.scatter({add})"
    
    df = raw_df.query("country in ['Japan','China','India']")
    
    fig = px.scatter(df, 
                  x='year', y='pop', 
                  size='pop',
                  color='country',
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    
    # %%
    
    # 9: add a symbol
    add = "symbol='country'"
    title = f"px.scatter({add})"
    
    df = raw_df.query(f"country in ['Canada','Japan']")
    
    fig = px.scatter(df, 
                  x='lifeExp', y='gdpPercap',
                  size='gdpPercap',
                  color='country',
                  symbol='country',             
                  labels=dict(
                            year='Year', 
                            pop='Population', 
                            country='Country',
                            lifeExp='Life expectancy',
                            gdpPercap='GDP per capita'),             
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 10 : add a hove_name & hover_data
    add = "hover_name='country', hover_data=['lifeExp']"
    title = f"px.scatter({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)
    
    fig = px.scatter(df, 
                  x='year', y='pop', 
                  size='pop',
                  color='country',
                  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()
    
    
    # %%
    
    # 11: add a text
    
    add = "text='year'"
    traces = "marker=dict(size=20)"
    title = f"px.scatter({add}) + update_traces({traces})"
    
    df = raw_df.query(f"country in ['Canada','Japan']")
    df = df.query("year >= 1980")
    
    fig = px.scatter(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.update_traces(marker=dict(size=20))
    
    fig.show()
    
    
    # %%
    
    # 12: rotate x ticks 
    add = ""
    layout="xaxis_tickangle=-45"
    title = f"px.scatter({add}) + update_layout({layout})"
    
    df = raw_df.query("country in ['Japan','China','India']")
    
    fig = px.scatter(df, 
                   x='year', y='pop',
                   size='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()
    
    
    # %%
    
    # 13: 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
    
    
    # %%
    
    # 13-1: simple stock scatter plots 
    add = "x='date', y='GOOG'"
    title = f"px.scatter({add}) : Simple stock scatter plots"
    
    df = raw_df.copy()
    
    fig = px.scatter(df, 
                  x='date', y='GOOG',
                  labels=dict(date='Date', GOOG='Google Stock Price'),
                  title=title   
                 )
    
    fig.show()
    
    
    # %%
    
    # 13-2: y=df.columns + update_xaxes(tickformat=...)
    add = "y=df.columns"
    xaxes = "tickformat='%b\n%Y')"
    title = f"px.scatter({add}) + update_xaxes({xaxes})"
    
    fig = px.scatter(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()
    
    
    # %%
    
    # 13-3: y=df.columns + update_xaxes(dtick='M1',tickformat=...)
    add = "y=df.columns"
    xaxes = "dtick='M1',tickformat='%b\n%Y')"
    title = f"px.scatter({add}) + update_xaxes({xaxes})"
    
    fig = px.scatter(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()
    
    
    # %%
    
    # 13-4: 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.scatter({add}) + update_xaxes({xaxes})"
    
    df = raw_df.copy()
    
    fig = px.scatter(df, 
                  x='date', y=df.columns,
                  hover_data={'date': '|%B %d, %Y'},
                  labels=dict(date='Year', value='Price (US $)', variable='Company'),
                  title=title
                  )
    
    fig.update_xaxes(
        dtick='M1',
        tickformat='%b\n%Y',    # 2018 Jan, Feb, Mar,...
        ticklabelmode='period'
        )
    
    fig.show()
    
    
    # %%
    
    # 13-5: y=df.columns + update_xaxes(dtick='M1',tickformat=...)
    add = "y=df.columns"
    xaxes = "dtick='M1',tickformat='%Y-%m-%d')"
    title = f"px.scatter({add}) + update_xaxes({xaxes})"
    
    fig = px.scatter(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()
    
    
    # %%
    
    # 13-6: scatter plots : y=df.columns + update_xaxes(dtick='M1',tickformat=...)
    add = "y=df.columns"
    xaxes = "dtick='M1',tickformat='%m/%d')"
    title = f"px.scatter({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.scatter(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()
    
    # %%
    
    # 13-7: Apple stock scatter plots with trendline
    add = "trendline='ols'"
    title = f"px.scatter({add}) : Apple stock scatter plots with trendline"
    
    fig = px.scatter(df, 
                  x='date', y='AAPL',
                  labels=dict(date='Date', close='Close Price'),
                  trendline='ols',
                  title=title   
                 )
    
    fig.update_traces(line_color='red')
    
    fig.show()
    
    # %%
    
    # 14: 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)
    
    fig = px.scatter(df, 
                  x='Date', 
                  y='AAPL.High', 
                  title=title
                 )
    
    fig.update_xaxes(rangeslider_visible=True)
    
    fig.show()
    
    
    # %%
    
    # 15: 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.scatter({add}) + update_xaxes({xaxes})"
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
    
    fig = px.scatter(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()
    
    
    # %%
    
    ### 16: Marginal Distribution Plots
    
    add = "marginal_x='histogram', marginal_y='rug'"
    title = f"px.scatter({add})"
    
    df = px.data.iris()
    
    fig = px.scatter(df, 
                     x='sepal_length', y='sepal_width', 
                     marginal_x='histogram', marginal_y='rug',
                     title=title
                    )
    
    fig.show()
    
    
    # %%
    
    ### 17: Facetting
    
    add = "facet_col='sex', facet_row='time'"
    title = f"px.scatter({add})"
    
    df = px.data.tips()
    
    fig = px.scatter(df, 
                     x='total_bill', y='tip', 
                     color='smoker', 
                     facet_col='sex', facet_row='time',
                     title=title
                    )
    
    fig.show()
    
    
    # %%
    
    ### 18: Linear Regression and Other Trendlines
    
    add = "rendline='ols'"
    title = f"px.scatter({add})"
    
    df = px.data.tips()
    
    fig = px.scatter(df, 
                     x='total_bill', y='tip', 
                     trendline='ols', # 'ols', 'lowess', 'rolling', 'expanding' or 'ewm'
                     title=title
                    )
    
    # fig.update_traces(line_color='red')
    
    fig.show()