カテゴリー

px

【plotly&px.scatter】pxでの散布図の描き方

2021年11月12日

こんな人にオススメ

plotlyの中にpxってのがあるけど、これで散布図(scatter)を描くにはどうしたらいい?

ということで、今回はplotlyplotly.expresspxで散布図を作成する方法を解説する。plotlygoでの散布図については以下参照。

【plotly&go.Scatter】plotlyの散布図グラフの描き方

こんな人にオススメ plotlyのと{ ...

続きを見る

pxgoの違いはカスタム性と即席性。pxの方が簡単にカスタムすることは難しいけど、サクッとそれなりのグラフを作成可能。一方でgoだとガッツリ好みのグラフが作成しやすい。

なお、基本的はplotly公式の「Scatter Plots in Python」に描かれているプロットに沿って、適宜解説を加えたり追加コードを入れたりすることにする。

python環境は以下。

  • Python 3.10.1
  • numpy 1.21.4
  • pandas 1.3.5
  • plotly 5.4.0
  • plotly-orca 3.4.2

運営者のメガネです。YouTubeTwitterInstagramも運営してます。

自己紹介はこちらから、お問い合わせはこちら。

運営者メガネ

作成したコード全文

下準備(import

import numpy as np
import pandas as pd
import plotly.express as px
import plotly.io as pio

まずは下準備としてのimport関連。メインはpxと保存用のpioだが、データの都合上、一部でnumpypandasを使用するのでimport

1種類のデータプロット

まずは簡単な1種類のデータをプロットする方法。プロットする方法には大きく分けると2つある。

  1. x, yの配列を直接指定
  2. pandasのデータフレームからx, yを指定

基本は2番のデータフレームでプロットすることが多い。シンプルに1種類プロットだけなら配列でもいいけど、複数になったりするとデータフレームの方が楽。

また、データフレームからプロットする方が引数の持つ意味がわかりやすい。

x, yの値を指定してプロット


まずはシンプルに、値を指定してプロットする方法。これに関しては普通。シンプルにxyの値に配列を入れて実行するだけ。

注意点はgoの場合はgo.ScatterSが大文字だったが、pxの場合はpx.scatterと小文字になるという点。ややこしい。

以下では、px.scatterでプロットするだけではなく、fig.update_layoutfig作成後にフォントサイズを変更している。fig.update_layoutに関しては以下。

【plotly&fig作成と更新】add_traceやupdate_layoutの使い方

こんな人にオススメ plotlyでグ} ...

続きを見る

import plotly.express as px
import plotly.io as pio

# x, yを指定してプロット
fig = px.scatter(
    x=[0, 1, 2, 3, 4],  # 横軸の値
    y=[0, 1, 4, 9, 16],  # 縦軸の値
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
# グラフの表示
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_xy"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

データフレームからプロット


データフレームからプロットする場合は、x, yなどのデータをデータフレームのヘッダ名で指定する。作成したデータフレームは以下。

dictkeyで横軸、縦軸となる配列としてx, yを指定し、これをpandasのデータフレームに変換した。

import pandas as pd
import plotly.express as px
import plotly.io as pio

df = pd.DataFrame({'x': [0, 1, 2, 3, 4], 'y': [0, 1, 4, 9, 16]})
print(df)
#    x   y
# 0  0   0
# 1  1   1
# 2  2   4
# 3  3   9
# 4  4  16

このデータフレームのx列、y列をそれぞれプロットの横軸と縦軸に指定することでプロットすることができる。

データフレームからプロットする場合はpx.scatterの引数data_frameを使用する。この引数にデータフレームを入れることで、その他の引数でデータフレームの列名を指定するだけで色んな操作が可能になる。

例えば以下の例だと横軸の値は引数xだが、これをdfx列にしたいからx=’x’とするだけで良くなる。いちいちx=df[’x’]と書かなくてもいい。

# データフレームのヘッダ名からx, yを指定してプロット
fig = px.scatter(
    data_frame=df,  # 使用するデータフレーム
    x='x',  # 横軸の値に設定するデータフレームの列名
    y='y',  # 縦軸に設定するデータフレームの列名
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
# グラフの表示
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_df"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

複数データのプロット

ここまでは1データのプロットを解説した。ただ、多くの場合は複数データのプロットを行うだろう。ということで、ここでは複数データのプロット方法を解説する。

2次元配列で指定するとエラー

import plotly.express as px
import plotly.io as pio

# 複数プロットを2次元配列で指定するのはエラー
fig = px.scatter(
    x=[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4]],
    y=[[0, 1, 4, 9, 16], [10, 12, 14, 19, 16]],
)
# ValueError: Cannot accept list of column references or list of columns for both `x` and `y`.

まずはシンプルに2次元配列で指定するという方法。これはエラーとなる。データは1次元である必要がある。

1データプロットした後のプロットを追加


続いては1データ追加した後にもう1データを追加するという方法。px.scatterで配列からプロットできるのは1データだけ。

なので、初めのプロットに追加していく形でどんどんプロットする。追加する際にはadd_traceadd_scatterを使用。詳細は以下の記事参照。

【plotly&fig作成と更新】add_traceやupdate_layoutの使い方

こんな人にオススメ plotlyでグ} ...

続きを見る

import plotly.express as px
import plotly.io as pio

# 既存のfigにプロットを追記

# 1プロット目
fig = px.scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16],)
# 2プロット目(追加分)
fig.add_scatter(x=[0, 1, 2, 3, 4], y=[10, 12, 14, 19, 16])
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_add_scatter"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

引数modeでプロットの種類を変更


ただし、シンプルに追記しただけだと追加分のプロットの種類が点+線となる。したがって、点をプロットしたいなr追記分は明示的に点で描くように指定する必要がある。

プロットの描き方は引数modeで指定可能。多分、add_tracegoでの書き方に準拠している。なので、引数とかが異なるので注意。goを使った散布図の作成方法は以下。

【plotly&go.Scatter】plotlyの散布図グラフの描き方

こんな人にオススメ plotlyのと{ ...

続きを見る

また、追記分のみ凡例が付くのにも注意が必要。これはpx.scatterの方だとプロットに名前がつかないから。go.Scatterだとデフォルトでtrace0trace1のように名前がつく。

plotlyでは名前がつくプロットにのみ凡例がつくから、結果として追記分(goで書いたプロット)だけ凡例が表示されることとなる。

ここではfig.update_tracesで2プロットに対して凡例を表示するようにする引数showlegend=Trueとして凡例を表示するようにした。そうするとpx.scatterで作成した青のプロットでは凡例に名前がないことがわかる。

import plotly.express as px
import plotly.io as pio

# modeを指定するとプロット形式を変更可能

fig = px.scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16],)
fig.add_scatter(
    x=[0, 1, 2, 3, 4], y=[10, 12, 14, 19, 16],
    mode='markers'  # マーカーだけにする
)
# 凡例を表示
fig.update_traces(showlegend=True)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_add_scatter_markers"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

これらの解決策は、データフレームを使用すること。データフレームを作成しないといけない場合だと作成するのが面倒だが、あると後々便利。

データフレームで分ければ簡単


データフレームを作成し、プロット時にどの列をどのデータとするかを指定するだけでプロットできる。

ここではx, yに加え、2種類のデータを区別するために列nameを追加した。こちらでdata0data1を指定し、データを区別する。

px.scatterdf, x, yでプロットを作成、さらにcolor=’name’とすることで、色分けをしてくれる。色分けするタイミングで凡例に色とプロット名が反映される。

import pandas as pd
import plotly.express as px
import plotly.io as pio

# データフレームがあれば列名を指定するだけ

df = pd.DataFrame(
    {
        'x': [0, 1, 2, 3, 4] + [0, 1, 2, 3, 4],
        'y': [0, 1, 4, 9, 16] + [10, 12, 14, 19, 16],
        'name': ['data0'] * 5 + ['data1'] * 5,
    }
)
print(df)
#    x   y   name
# 0  0   0  data0
# 1  1   1  data0
# 2  2   4  data0
# 3  3   9  data0
# 4  4  16  data0
# 5  0  10  data1
# 6  1  12  data1
# 7  2  14  data1
# 8  3  19  data1
# 9  4  16  data1

fig = px.scatter(
    df, x='x', y='y',
    color='name'  # 色を区別する列名
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_df_2plots"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

データをシンボルや色で区別する

ここまではとりあえずプロットしてきた。ここからは色分けやマーカーのシンボル(形状)を異なるものにしてプロット同士が異なるものだということを強調する方法を説明する。

使用するデータはpxのプリセットデータフレームの「px.data.iris()」。どうやらあやめのデータのようだ。

使用するデータ

import plotly.express as px
import plotly.io as pio

# あやめに関するデータ
df = px.data.iris()
print(df)
#      sepal_length  sepal_width  ...    species  species_id
# 0             5.1          3.5  ...     setosa           1
# 1             4.9          3.0  ...     setosa           1
# 2             4.7          3.2  ...     setosa           1
# 3             4.6          3.1  ...     setosa           1
# 4             5.0          3.6  ...     setosa           1
# ..            ...          ...  ...        ...         ...
# 145           6.7          3.0  ...  virginica           3
# 146           6.3          2.5  ...  virginica           3
# 147           6.5          3.0  ...  virginica           3
# 148           6.2          3.4  ...  virginica           3
# 149           5.9          3.0  ...  virginica           3

# [150 rows x 6 columns]

# ヘッダ名の取得
print(df.columns.values)
# ['sepal_length' 'sepal_width' 'petal_length' 'petal_width' 'species'
#  'species_id']

# 種類のデータ
print(df['species'].unique())
# ['setosa' 'versicolor' 'virginica']

使用するのはplotlyの説明でよく出てくるあやめのデータ。pandasimportしていなくても使用できる。

ただ、得られるデータはpandasのデータフレームで使い勝手もpandasのデータフレームと同じ。

ヘッダ名の指定で色分けが可能


すでに上で色分けについては解説したが、色分けは分けたいデータの入っている列名を指定するだけ。今回はspecies列を指定した。これだけで勝手に色分けしてくれる。

また、マーカーのサイズも引数sizeに列名を指定することで可能。ここではpetal_lengthをマーカーサイズに指定した。

さらに、マウスオーバー時の情報hover_dataも設定。こちらはlistなどで囲った列名(複数可)もしくはデータレームを設定。ここではデータフレーム自体にした。

import plotly.express as px
import plotly.io as pio

df = px.data.iris()
print(df['species'])
# 0         setosa
# 1         setosa
# 2         setosa
# 3         setosa
# 4         setosa
#          ...
# 145    virginica
# 146    virginica
# 147    virginica
# 148    virginica
# 149    virginica
# Name: species, Length: 150, dtype: object

print(df['petal_length'])
# 0      1.4
# 1      1.4
# 2      1.3
# 3      1.5
# 4      1.4
#       ...
# 145    5.2
# 146    5.0
# 147    5.2
# 148    5.4
# 149    5.1
# Name: petal_length, Length: 150, dtype: float64

fig = px.scatter(
    df, x='sepal_width', y='sepal_length',
    color='species',  # species列の名称で色分け
    size='petal_length',  # マーカーのサイズをpetal_lengthで決める
    # hover_data=['petal_width'],  # 列名指定するときはlistかtupleで指定
    hover_data=df,  # データフレームを選択すると全ヘッダ情報が表示される
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_color_str"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

色分けを値にするとカラーバーに


先程は文字列であるspecies列を指定して色分けを行なった。今度は値が入っているpetal_length列で色分けをする。

petal_length列には値が入っているんだけど、この列を指定すると勝手にカラーバーが表示されてプロットされる。これは便利。

import plotly.express as px
import plotly.io as pio

# 数値で色分けすると自動でカラーバーがつく

df = px.data.iris()

fig = px.scatter(
    df, x='sepal_width', y='sepal_length',
    color='petal_length',  # 数値で色分けすると自動でカラーバーで示してくれる
    size='petal_length',  # マーカーサイズも同じ列名で可能
    hover_data=df,  # データフレームを選択すると全ヘッダ情報が表示される
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_color_value"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

color_continuous_scaleでカラースケールの変更


また、カラーバーのカラースケールの色を変えたい場合は、引数color_continuous_scaleにカラースケール名を設定すればいい。

カラースケール名はplotly公式の「Built-in Continuous Color Scales in Python」に例がある。今回はJetを指定した。これだと青から赤で値の強弱が強調されてわかりやすい。

import plotly.express as px
import plotly.io as pio

# カラースケールの変更はcolor_continuous_scale

df = px.data.iris()

fig = px.scatter(
    df, x='sepal_width', y='sepal_length',
    color='petal_length',  # 数値で色分けすると自動でカラーバーで示してくれる
    size='petal_length',  # マーカーサイズも同じ列名で可能
    hover_data=df,  # データフレームを選択すると全ヘッダ情報が表示される
    color_continuous_scale='Jet'  # ここにカラースケールの名称を入れる
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_color_value_Jet"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

マーカーサイズは文字があるとエラー

なお、マーカーサイズも数値で与えるんだけど、マーカーサイズを指定する列が文字列のデータフレーム列だとエラーになる。

# マーカーサイズで文字がある列名を指定するとエラー

df = px.data.iris()
print(df['species'])
# 0         setosa
# 1         setosa
# 2         setosa
# 3         setosa
# 4         setosa
#          ...
# 145    virginica
# 146    virginica
# 147    virginica
# 148    virginica
# 149    virginica
# Name: species, Length: 150, dtype: object

# fig = px.scatter(
#     df, x='sepal_width', y='sepal_length',
#     size='species',  # サイズに文字の列を指定
# )
# # TypeError: unsupported operand type(s) for /: 'str' and 'int'

マーカー(シンボル)の形状を列名で指定

マーカーの形状も列名で指定することが可能。この場合は引数symbolを使用する。引数で指定すると勝手に円形や四角で割り当ててくれる。

import plotly.express as px
import plotly.io as pio

# マーカーの形状を変更

df = px.data.iris()

fig = px.scatter(
    df, x='sepal_width', y='sepal_length',
    size='petal_length',
    symbol='species',  # speciesでマーカーの形状を指定&凡例も自動作成
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_symbol"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

マーカーとカラーバーの両立

しかし、マーカーの形状だけを指定しても(ここではサイズも指定しているけど)同じ色なのでわかりにくい。ということで、colorで数値のデータpetal_lengthを入れてみる。

んだけど、この場合だと凡例とカラーバーがダブってしまう。これはこれでダルい。一応、プロットの表示・非表示は凡例の隙間から押せるけど調整が必要。

import plotly.express as px
import plotly.io as pio

# 凡例とカラーバーの両立だと位置がダブる

df = px.data.iris()

fig = px.scatter(
    df, x='sepal_width', y='sepal_length',
    size='petal_length',  # サイズ
    color='petal_length',  # 色
    symbol='species',  # 形状
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_symbol_color"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

凡例の位置基準を変更


アプローチの仕方はいくつもあるけど、 ここでは凡例の位置を移動させることにする。凡例はレイアウトの項目なので、fig.update_layoutを使う。

legend=dict(x=1, xanchor='right')とすることで、凡例の位置をx=1としつつ横の位置の基準を凡例に右側にすることが可能。

なお、ここではdictの入れ子で作成しているけど、アンダースコア_を使用しても同じ意味。

legend=dict(x=1, xanchor='right')
legend_x=1, legend_xanchor='right'

凡例を移動させて作成したグラフが上のグラフ。凡例とカラーバーが重ならないようになったので見やすい。

import plotly.express as px
import plotly.io as pio

# 凡例の位置と位置基準を変更

fig = px.scatter(
    df, x='sepal_width', y='sepal_length',
    size='petal_length',  # サイズ
    color='petal_length',  # 色
    symbol='species',  # 形状
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
# 凡例の横位置を1にして位置基準を右に設定
fig.update_layout(legend=dict(x=1, xanchor='right'))
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_symbol_color_legend"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

カラーバーを短くする


先程は凡例の位置を移動して重なるのを防いだ。ここでは逆にカラーバーの長さを変えて重ならないようにした。

カラーバーもレイアウトの内容なのでfig.update_layoutで編集する。レイアウトの引数coloraxisの引数colorbarの引数lenで長さを設定可能。ここではlen=0.5とした。

import plotly.express as px
import plotly.io as pio

# カラーバーの長さを変更

df = px.data.iris()

fig = px.scatter(
    df, x='sepal_width', y='sepal_length',
    size='petal_length',  # サイズ
    color='petal_length',  # 色
    symbol='species',  # 形状
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
# カラーバーを短くする
fig.update_layout(coloraxis=dict(colorbar=dict(len=0.5)))
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_symbol_color_barlen"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

エラーバーの追加


エラーバーとは簡単にいうとその値にどれだけの誤差があるのかを示すもの。一般的な誤差という表現とはニュアンス・意味が異なるからややこしいけど、とにかく値のブレ幅っていうイメージ。

エラーバーは引数error_x, error_yで指定することが可能。とりあえずエラーバーのためのデータの作成。今回は適当にデータを作成。e_x列が横軸、e_y列が縦軸のエラーとする。

import plotly.express as px
import plotly.io as pio

df = px.data.iris()

# エラーの値を適当に作成
df['e_x'] = df['sepal_width'] / 100
df['e_y'] = df['sepal_length'] / 100
print(df)
#      sepal_length  sepal_width  petal_length  ...  species_id    e_x    e_y
# 0             5.1          3.5           1.4  ...           1  0.035  0.051
# 1             4.9          3.0           1.4  ...           1  0.030  0.049
# 2             4.7          3.2           1.3  ...           1  0.032  0.047
# 3             4.6          3.1           1.5  ...           1  0.031  0.046
# 4             5.0          3.6           1.4  ...           1  0.036  0.050
# ..            ...          ...           ...  ...         ...    ...    ...
# 145           6.7          3.0           5.2  ...           3  0.030  0.067
# 146           6.3          2.5           5.0  ...           3  0.025  0.063
# 147           6.5          3.0           5.2  ...           3  0.030  0.065
# 148           6.2          3.4           5.4  ...           3  0.034  0.062
# 149           5.9          3.0           5.1  ...           3  0.030  0.059

# [150 rows x 8 columns]

あとはこのデータフレームを使ってこれまで通りグラフを作成するのみ。エラーバーを追加するとホバー情報に各値の誤差が追記される。

fig = px.scatter(
    df, x='sepal_width', y='sepal_length', color='species',
    error_x='e_x', error_y='e_y',  # エラーバーの追加
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_error_xy"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

周辺分布を試す

周辺分布(Marginal Distribution)ってのはプロットの上と右に、メインのプロットから導出されるヒストグラムとかのこと。subplotに近いイメージ。

【px&facet】plotly.expressでsubplotsを描く

こんな人にオススメ plotly.express、px ...

続きを見る

pxの場合はmarginal_xmarginal_yでそれぞれ上と右にグラフを追加できる。追加できるグラフは以下。

  • histgram
  • rug
  • violin
  • box

以下ではhistgramrugviolinboxの組み合わせでグラフを作成。



import plotly.express as px
import plotly.io as pio

# Marginal Distribution(周辺分布)

df = px.data.iris()

# marginalで上・右に追加でグラフを描画可能
# x, yそれぞれrug, box, violin, histogramが選択可能
fig = px.scatter(
    df, x='sepal_length', y='sepal_width',
    marginal_x='histogram',  # x軸に平行にhistogram
    marginal_y='rug',  # y軸に平行にrug
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_marginal_rug_histgram"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

fig = px.scatter(
    df, x='sepal_length', y='sepal_width',
    marginal_x='violin',  # x軸に平行にviolin
    marginal_y='box',  # y軸に平行にbox
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_marginal_violin_box"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

str以外で指定するとエラー

なお、marginal_xmarginal_yは上と右にしか置くことができない。なので多くても2種類の周辺分布になる。欲張って配列にして指定するとエラーになる。

import plotly.express as px

# str以外でで指定するとエラー

df = px.data.iris()

# 以下ではlistにしてみた
fig = px.scatter(
    df, x='sepal_length', y='sepal_width',
    marginal_x='violin',  # x軸に平行にグラフ
    marginal_y=['box', 'histogram'],  # y軸に平行にグラフ
)
# AttributeError: 'NoneType' object has no attribute 'constructor'

色分けもしてみる


さっきは1つのデータだけでプロットしたけど、色分けを追加することも可能。speciesで色分けすると各データごとに周辺分布が作成される。これは便利。

import plotly.express as px
import plotly.io as pio

# speciesで色分けすると分布がわかりやすい

df = px.data.iris()

fig = px.scatter(
    df, x='sepal_length', y='sepal_width',
    marginal_x='histogram',  # x軸に平行にhistogram
    marginal_y='rug',  # y軸に平行にrug
    color='species'
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_marginal_rug_histgram_species"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

数値で色分けするとカラーバーのみ

一方でpetal_lengthで色分けするとカラーバーのみが表示されてあまり変化がない。

import plotly.express as px
import plotly.io as pio

# petal_lengthで色分けすると色が変わるだけ

df = px.data.iris()

fig = px.scatter(
    df, x='sepal_length', y='sepal_width',
    marginal_x='histogram',  # x軸に平行にhistogram
    marginal_y='rug',  # y軸に平行にrug
    color='petal_length',
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_marginal_rug_histgram_petal_length"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

Facetsubplot的な


facetsubplotみたいなもの。厳密には異なるけど、ざっくりは同じ感じ。以下の記事で解説している。

【px&facet】plotly.expressでsubplotsを描く

こんな人にオススメ plotly.express、px ...

続きを見る

指定方法は簡単で列方向にグラフを増やしたいなら引数facet_colで列名を指定するだけ。また、facet_col_wrapで列数を指定することも可能。

ただし、facet_row_wrapという引数はないので注意。列数を基準に複数グラフを作成する。

今回はfacet_colfacet_rowで列と行を指定してグラフを作成した。

import plotly.express as px
import plotly.io as pio

df = px.data.tips()
print(df)
#      total_bill   tip     sex smoker   day    time  size
# 0         16.99  1.01  Female     No   Sun  Dinner     2
# 1         10.34  1.66    Male     No   Sun  Dinner     3
# 2         21.01  3.50    Male     No   Sun  Dinner     3
# 3         23.68  3.31    Male     No   Sun  Dinner     2
# 4         24.59  3.61  Female     No   Sun  Dinner     4
# ..          ...   ...     ...    ...   ...     ...   ...
# 239       29.03  5.92    Male     No   Sat  Dinner     3
# 240       27.18  2.00  Female    Yes   Sat  Dinner     2
# 241       22.67  2.00    Male    Yes   Sat  Dinner     2
# 242       17.82  1.75    Male     No   Sat  Dinner     2
# 243       18.78  3.00  Female     No  Thur  Dinner     2

# [244 rows x 7 columns]

fig = px.scatter(
    df, x='total_bill', y='tip',
    color='smoker',  # 色は喫煙か否かで区別
    facet_col='sex',  # 列は性別で区別
    facet_row='time'  # 行は時間で区別
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_facet"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

pxで最小二乗法

最後はpxで最小二乗法を使用して線形フィッティングをする方法を解説。pxだけでフィッティングもできるのはかなり楽。最小二乗法ってのはフィッティングするための手法のようのなもの。

上のグラフだと左上がりっぽい散布図にこんな傾向って直線が引かれている。pxの場合、trendline='ols'と指定することで直線を引くことが可能。その他にもスムージングや移動平均も可能。

import plotly.express as px
import plotly.io as pio

df = px.data.tips()
print(df)
#      total_bill   tip     sex smoker   day    time  size
# 0         16.99  1.01  Female     No   Sun  Dinner     2
# 1         10.34  1.66    Male     No   Sun  Dinner     3
# 2         21.01  3.50    Male     No   Sun  Dinner     3
# 3         23.68  3.31    Male     No   Sun  Dinner     2
# 4         24.59  3.61  Female     No   Sun  Dinner     4
# ..          ...   ...     ...    ...   ...     ...   ...
# 239       29.03  5.92    Male     No   Sat  Dinner     3
# 240       27.18  2.00  Female    Yes   Sat  Dinner     2
# 241       22.67  2.00    Male    Yes   Sat  Dinner     2
# 242       17.82  1.75    Male     No   Sat  Dinner     2
# 243       18.78  3.00  Female     No  Thur  Dinner     2

# [244 rows x 7 columns]

fig = px.scatter(
    df, x='total_bill', y='tip',
    color='smoker',  # 色は喫煙か否かで区別
    facet_col='sex',  # 列は性別で区別
    facet_row='time'  # 行は時間で区別
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'px-scatter'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_facet"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

なお、実行時に以下のエラーが出た場合はライブラリstatsmodelsを入れることで解決する。

# 以下のエラーが出たら「conda install -c anaconda statsmodels」で
# statsmodelsを入れる(Anacondaの場合)
# ModuleNotFoundError: No module named 'statsmodels'

フィット結果を出力

フィットした結果を取り出すにはpx.get_trendline_resultsを使用する。ただし、中身はこのままだと見ることができない。

# フィット結果
results = px.get_trendline_results(fig)
print(results)
#                                       px_fit_results
# 0  <statsmodels.regression.linear_model.Regressio...

px.get_trendline_resultsで取り出した内容に対し、さらに直線情報の中のフィットした結果を見る必要がある。

summaryと以下に示すようにフィットのざっくりとした内容。いつ取得したのかとかも出てくるから面白い。

paramsはその名の通りフィットしたデータの係数を示すもの。係数の次数が小さいものから並ぶ。

fit_results = results.px_fit_results.iloc[0]
summary = fit_results.summary()  # 係数やR2値などのデータのサマリー
params = fit_results.params  # fit係数

summaryparamsの結果は以下。

print(summary)
#                             OLS Regression Results
# ==============================================================================
# Dep. Variable:                      y   R-squared:                       0.457
# Model:                            OLS   Adj. R-squared:                  0.454
# Method:                 Least Squares   F-statistic:                     203.4
# Date:                Thu, 11 Nov 2021   Prob (F-statistic):           6.69e-34
# Time:                        20:09:30   Log-Likelihood:                -350.54
# No. Observations:                 244   AIC:                             705.1
# Df Residuals:                     242   BIC:                             712.1
# Df Model:                           1
# Covariance Type:            nonrobust
# ==============================================================================
#                  coef    std err          t      P>|t|      [0.025      0.975]
# ------------------------------------------------------------------------------
# const          0.9203      0.160      5.761      0.000       0.606       1.235
# x1             0.1050      0.007     14.260      0.000       0.091       0.120
# ==============================================================================
# Omnibus:                       20.185   Durbin-Watson:                   1.811
# Prob(Omnibus):                  0.000   Jarque-Bera (JB):               37.750
# Skew:                           0.443   Prob(JB):                     6.35e-09
# Kurtosis:                       4.711   Cond. No.                         53.0
# ==============================================================================

# Notes:
# [1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

print(params)
# [0.92026961 0.10502452]

このフィット係数をnumpyでのフィット係数と比較する。numpyでの直線フィットはnp.polyfitが便利。x, yと次数を指定するだけ。

numpyのフィット結果と比較する

【python&フィッティング】polyfitとcurve_fitでfitting

こんな人にオススメ pythonを使{ ...

続きを見る

import numpy as np
import plotly.express as px
import plotly.io as pio

# numpyのフィットでフィット結果を確かめる

df = px.data.tips()
par = np.polyfit(x=df['total_bill'], y=df['tip'], deg=1)
fit = np.poly1d(par)(df['total_bill'])
# 順番が逆だが合っている
print(par)
# [0.10502452 0.92026961]

np.polyfitの場合は字数の大きいものから並ぶので順番が前後するけど値は同じ。なのでpxでサクッとfitしたい時はこれで十分。

データフレームがあれば即席

今回はplotlypxを使用した散布図の描き方について解説した。goの時はデータが複数あっても配列に追加していくことで複数プロットが可能だった。

一方でpxの場合は1プロットに追加するかデータフレームからプロットするかという少々面倒な描き方。データフレームの方がデータがまとまってるしプロットも楽にできるけど、データフレームを知らないと大変。

ということで、pxでプロットするならまずはデータフレームの作成・編集方法から学ぶ方が良いのかとも思う。

多項式関数のグラフ
【辞書&pandas】dict{name: , val: {a: [~], b:[~]}}のpandas化

こんな人にオススメ ネスト ...

続きを見る

関連記事

px

【plolty&棒グラフ】px.barでバーチャートを作成

2022/8/19

こんな人にオススメ plotlyのpxで ...

px

【plotly&ガントチャート】px.timelineでGantt Chartsを作成

2022/8/19

こんな人にオススメ plotlyでガ} ...

px

【plotly&fill】px.areaで積み上げ塗りつぶし

2022/8/19

こんな人にオススメ pxで塗り& ...

px

【plotly&px.scatter】pxでの散布図の描き方

2022/8/19

こんな人にオススメ plotlyの中{ ...

px

【plotly&scatter_matrix】複数種の軸を持つsubplotをpxで描画

2022/8/19

こんな人にオススメ pxにscatter_matrix ...

px

【plotly&3D】px.scatter_3dとpx.line_3Dで3Dグラフを作成

2022/8/19

こんな人にオススメ plotlyのpxで3D& ...

px

【px&facet】plotly.expressでsubplotsを描く

2022/8/19

こんな人にオススメ plotly.express、px ...

px

【px&バブルチャート】plotly.expressで各国の収入と平均寿命の時代変化をアニメーションで

2022/8/19

こんな人にオススメ 今は世 ...

スイッチボット

2022/11/28

【SwitchBotロックレビュー】これからのスタンダードになりうるスマートロック

こんな人にオススメ SwitchBotからスマートロック「SwitchBotロック」が発売された ...

生活に役立つ

2022/11/28

【メガネ厳選】クソ便利に使っているサービスやアイテム達

このページでは執筆者「メガネ」が実際に使って便利だと感じているサ ...

マウス

2022/9/11

【Logicool MX ERGO vs MX Master 3】ERGOをメインにした決定的な理由

こんな疑問・お悩みを持っている人におすすめ 執筆者はLogicoolのハイエンӠ ...

完全ワイヤレスイヤホン(TWS)

2022/11/21

【ながら聴きイヤホン比較】SONY LinkBuds、ambie、BoCoはどれがおすすめ?

こんな人におすすめ 耳を塞がない開放型のイヤホンに完全ワイヤレスӟ ...

macOSアプリケーション

2022/10/15

【M1 Mac】MacBook Proに入れている便利でニッチなアプリを21個紹介する

こんな人におすすめ MacBookを購入してLINEとか必要最低限のアプリは入れた。 ...

完全ワイヤレスイヤホン(TWS)

2022/10/23

【SENNHEISER MOMENTUM True Wireless 3レビュー】高レベルでバランス型の高音質イヤホン

こんな人におすすめ SENNHEISER MOMENTUM True Wireless 3って実際のところどうなの? 評判は良い ...

完全ワイヤレスイヤホン(TWS)

2022/11/21

【SONY WF-1000XM4レビュー】神とゴミのハーフ&ハーフ

こんな人におすすめ SONYのフラグシップモデル「SONY WF-1000XM4」ってどれくらい性 ...

完全ワイヤレスイヤホン(TWS)

2022/8/19

【Nothing ear (1)レビュー】ライトな完成度、アップデートに期待

こんな人にオススメ 完全ワイヤレスイヤホン(TWS)でスケルトンボディ ...

Pythonを学びたいけど独学できる時間なんてない人へのすゝめ

執筆者は大学の研究室・大学院にて独学でPythonを習得した。

でも社会人になったら独学で行うには時間も体力もなくて大変だ。

時間がない社会人だからこそプロの教えを乞うのが効率的。

ここでは色んなタイプに合ったプログラミングスクールの紹介をする。

  • この記事を書いた人

メガネ

ベンチャー企業のWebエンジニア駆け出し。独学のPythonで天文学系の大学院を修了→新卒を1.5年で辞める→転職→今に至る。
常時金欠のガジェット好きでM1 MacBook Pro x Galaxy S22 Ultraの狂人。
人見知りで根暗だったけど、人生楽しもうと思って良い方向に狂う→人生が楽しい

ガジェットのレビューとPythonコードを記事にしています。ぜひ楽しんでください🦊
自己紹介と半生→変わって楽しいの繰り返し

-px
-, , , ,