カテゴリー

Plotly全般

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

2022年1月8日

こんな人にオススメ

plotlyでグラフを描く時にadd_traceとかupdate_layoutとかあるけど、これらは一体なんなの?

ということで、今回はpythonのplotlyでグラフを描くときに出てくるadd_traceupdate_layoutなどについて解説する。

実はplotlyでグラフを描く際には色んな方法があって、初めはどの方法がどんなどんなプロットになるのかがわかりにくい。実際、執筆者もplotlyを使い始めた時はよくわからなかった。

今回はグラフ描画時のこれらのコードで何ができるのか、どのような挙動になるのかを解説するので、plotly学習のきっかけにしていただけると幸いだ。

なお、今回の記事はplotly公式の「Creating and Updating Figures in Python」の内容をベースに作成している。

python環境は以下。

  • Python 3.10.1
  • plotly 5.4.0
  • plotly-orca 3.4.2
スポンサーリンク
スポンサーリンク

運営者のメガネと申します。TwitterInstagramも運営中。

自己紹介はこちらから、お問い合わせはこちらからお願いいたします。

運営者メガネ

作成したコード全文

下準備(import

import plotly.graph_objects as go
import plotly.io as pio

まずは下準備としてのimport関連。今回はplotlygoを使って解説する。ploltyではgo以外にもpxなるライブラリもあり、こちらはよりサクッとグラフを描くことが可能。

ただ、plotlyグラフ描画のコード内容を知るならgoを使ったほうが細かいのでおすすめ。[pxについての記事](https://megatenpa.com/category/python/plotly/px/)は以下。

go.Figureの引数datalistでプロットデータを格納


まずはこのブログ「M天パ」で使っている方法。予めプロットするデータをlistなどで作成しておき、最後にfigに入れる。

執筆者がplotlyを使い始めた際に一番理解しやすかった方法だ。この方法だとプロットとフィギュアを別々で管理することができる。

今回は上の図のように2種類のプロットを用意し、それぞれを引数plotに格納、最後にfigの引数dataに入れる。行数や手間は多いけど、1ステップがわかりやすいと思う。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

# 全プロットを入れるためのlist
plot = []

# プロットをlistへ格納
d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
plot.append(d1)  # プロットを格納

d2 = go.Scatter(x=x, y=y2, name='y2')  # y2のプロット
plot.append(d2)  # プロットを格納

fig = go.Figure(data=plot)  # Figureの作成
fig.show()  # Figureの表示

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_append_plot"
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")

go.Figureの引数dataに直接プロットデータを格納

続いてはgo.Figureの中に直接プロットデータを入れるという方法。さっきは一旦、変数plotに入れたけど、今回は直接入れる。

ここでのプロットのようにシンプルなグラフを描きたいときはこれでもいいだろう。ただし、go.Scatterの引数が多いグラフを描こうした時は、go.Figure内がゴチャゴチャしてしまうので注意が必要。

グラフの作成のためのコードはさっきと同じなので、できるグラフのさっきと同じ。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

# Figureに直接入れる
fig = go.Figure(
    data=[
        go.Scatter(x=x, y=y1, name='y1'),
        go.Scatter(x=x, y=y2, name='y2')
    ]
)
fig.show()

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

add_traceで1プロットずつ格納

今度はちょっとテイストが異なり、一旦go.Figurefigを作成、そこにfig.add_traceでどんどんプロットを追加する方法。ネットでplotlyのプロット方法を調べると、この方法で書かれた記事が多くヒットする。

ここではy1, y2のプロットを変数d1, d2においてからfig.add_traceに入れているけど、直接fig.add_traceの中にプロットデータを入れてもいい。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure()  # 先のFigureを作成

d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
fig.add_trace(d1)  # figにd1を追加

d2 = go.Scatter(x=x, y=y2, name='y2')  # y2のプロット
fig.add_trace(d2)  # figにd2を追加

fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_add_trace"
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.add_から始まるコードは他にもある。一部は後で解説するが以下だけ種類がある。多すぎる。

# fig.add_一覧
fig.add_annotation
fig.add_bar
fig.add_barpolar
fig.add_box
fig.add_candlestick
fig.add_carpet
fig.add_choropleth
fig.add_choroplethmapbox
fig.add_class
fig.add_cone
fig.add_contour
fig.add_contourcarpet
fig.add_densitymapbox
fig.add_funnel
fig.add_funnelarea
fig.add_heatmap
fig.add_heatmapgl
fig.add_histogram
fig.add_histogram2d
fig.add_histogram2dcontour
fig.add_hline
fig.add_hrect
fig.add_icicle
fig.add_image
fig.add_indicator
fig.add_isosurface
fig.add_layout_image
fig.add_mesh3d
fig.add_ohlc
fig.add_parcats
fig.add_parcoords
fig.add_pie
fig.add_pointcloud
fig.add_sankey
fig.add_scatter
fig.add_scatter3d
fig.add_scattercarpet
fig.add_scattergeo
fig.add_scattergl
fig.add_scattermapbox
fig.add_scatterpolar
fig.add_scatterpolargl
fig.add_scattersmith
fig.add_scatterternary
fig.add_shape
fig.add_splom
fig.add_streamtube
fig.add_sunburst
fig.add_surface
fig.add_table
fig.add_trace
fig.add_traces
fig.add_traits
fig.add_treemap
fig.add_violin
fig.add_vline
fig.add_volume
fig.add_vrect
fig.add_waterfall

add_traceは1プロットの追加のみ

# add_traceで複数プロットを入れようとするとエラー
fig.add_trace([d1, d2])
# ValueError:
#     Invalid element(s) received for the 'data' property of
#         Invalid elements include: [[Scatter({
#     'name': 'y1', 'x': [1, 2, 3], 'y': [1, 3, 2]
# }), Scatter({
#     'name': 'y2', 'x': [1, 2, 3], 'y': [4, 2, 3.5]
# })]]

#     The 'data' property is a tuple of trace instances
#     that may be specified as:
#       - A list or tuple of trace instances
#         (e.g. [Scatter(...), Bar(...)])
#       - A single trace instance
#         (e.g. Scatter(...), Bar(...), etc.)
#       - A list or tuple of dicts of string/value properties where:
#         - The 'type' property specifies the trace type
#             One of: ['bar', 'barpolar', 'box', 'candlestick',
#                      'carpet', 'choropleth', 'choroplethmapbox',
#                      'cone', 'contour', 'contourcarpet',
#                      'densitymapbox', 'funnel', 'funnelarea',
#                      'heatmap', 'heatmapgl', 'histogram',
#                      'histogram2d', 'histogram2dcontour', 'icicle',
#                      'image', 'indicator', 'isosurface', 'mesh3d',
#                      'ohlc', 'parcats', 'parcoords', 'pie',
#                      'pointcloud', 'sankey', 'scatter',
#                      'scatter3d', 'scattercarpet', 'scattergeo',
#                      'scattergl', 'scattermapbox', 'scatterpolar',
#                      'scatterpolargl', 'scattersmith',
#                      'scatterternary', 'splom', 'streamtube',
#                      'sunburst', 'surface', 'table', 'treemap',
#                      'violin', 'volume', 'waterfall']

#         - All remaining properties are passed to the constructor of
#           the specified trace type

#         (e.g. [{'type': 'scatter', ...}, {'type': 'bar, ...}])

fig.add_traceは1プロットの追加にのみ対応している。したがって、上のコードのように複数プロットを入れるとエラーとなる。

複数プロットを同時に追加したいときは次に解説するadd_tracesを使用する。こっちはtracesと複数形になっている。

add_tracesで複数プロットを一気に格納

fig.add_tracesと、traceを複数形のtracesにすることで複数プロットを同時に追加可能。この際、プロットはtuplelistなどで一括りにしないとエラーとなる。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure()  # 先のFigureを作成

d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
d2 = go.Scatter(x=x, y=y2, name='y2')  # y2のプロット
fig.add_traces((d1, d2))  # 複数形にすると複数プロットを追記可能

fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_add_traces"
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")

add_scatter, add_barなどで直接格納


先程のfig.add_一覧に載っているプロットの種類であれば、直接プロットの種類を選択して追加可能。いちいちfig.add_traceの中でプロットの種類を選択しなくてもよくなる。

ここではfig.add_scatterで散布図を、fig.add_barで棒グラフを作成した。fig.add_一覧を再度載せるので、各シチュエーションで使いたいものをピックアップしていただきたい。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure()  # 先のFigureを作成

fig.add_scatter(x=x, y=y1, name='y1')  # scatterを直接追加
fig.add_bar(x=x, y=y2, name='y2')  # barを直接追加
fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_add_scatter_bar"
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.add_一覧
fig.add_annotation
fig.add_bar
fig.add_barpolar
fig.add_box
fig.add_candlestick
fig.add_carpet
fig.add_choropleth
fig.add_choroplethmapbox
fig.add_class
fig.add_cone
fig.add_contour
fig.add_contourcarpet
fig.add_densitymapbox
fig.add_funnel
fig.add_funnelarea
fig.add_heatmap
fig.add_heatmapgl
fig.add_histogram
fig.add_histogram2d
fig.add_histogram2dcontour
fig.add_hline
fig.add_hrect
fig.add_icicle
fig.add_image
fig.add_indicator
fig.add_isosurface
fig.add_layout_image
fig.add_mesh3d
fig.add_ohlc
fig.add_parcats
fig.add_parcoords
fig.add_pie
fig.add_pointcloud
fig.add_sankey
fig.add_scatter
fig.add_scatter3d
fig.add_scattercarpet
fig.add_scattergeo
fig.add_scattergl
fig.add_scattermapbox
fig.add_scatterpolar
fig.add_scatterpolargl
fig.add_scattersmith
fig.add_scatterternary
fig.add_shape
fig.add_splom
fig.add_streamtube
fig.add_sunburst
fig.add_surface
fig.add_table
fig.add_trace
fig.add_traces
fig.add_traits
fig.add_treemap
fig.add_violin
fig.add_vline
fig.add_volume
fig.add_vrect
fig.add_waterfall

update_tracesで既存データを更新

続いてはupdate_tracesupdateと名がついているからわかりやすいが、これは既存のプロットデータ(traces)を更新する。

新規で入れても意味がない

まずは先ほどと同じように空のfigに対して適用してみる。しかし、元から何もプロットデータがない状態なので、グラフをはまっさらのまま。

figをプリントしてもデータ部分には何も入っていないので当たり前。なお、layouttemplateはグラフのテーマに相当する。以下で解説している。

【plotly&グラフテーマ】plotly既存のthemasをグラフ化

続きを見る

import plotly.graph_objects as go
import plotly.io as pio

# update_tracesをプロットの格納に使っても何も表示されない
x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure()  # 先のFigureを作成

d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
fig.update_traces(d1)
d2 = go.Scatter(x=x, y=y2, name='y2')  # y2のプロット
fig.update_traces(d2)

print(fig)
# Figure({
#     'data': [], 'layout': {'template': '...'}
# })

fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_update_tarces_miss"
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")

既存データのアップデートに使用可能

update_tracesは既存のプロットに対して適用されるので、予めfigにプロットを入れておく必要がある。ここでは先ほどと同じようにy1, y2でグラフを作成、その後にupdate_tracesでプロットを線から点に変更した。

fig.update_tracesの引数modego.Scattrerの引数で、プロットの種類を選択できる。ここではmode=’marker’でプロットの種類を点だけにしている。デフォルトは既に見てきたように’lines+markers’

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure()  # 先のFigureを作成
d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
d2 = go.Scatter(x=x, y=y2, name='y2')  # y2のプロット
fig.add_traces((d1, d2))

fig.update_traces(mode='markers')  # プロットのモードをマーカーだけに更新
fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_update_traces"
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_で始まるものは以下。基本的にはプロット関連が多い。

# fig.updateシリーズ
fig.update_annotations
fig.update_coloraxes
fig.update_geos
fig.update_layout
fig.update_layout_images
fig.update_mapboxes
fig.update_polars
fig.update_scenes
fig.update_shapes
fig.update_smiths
fig.update_ternaries
fig.update_traces
fig.update_xaxes
fig.update_yaxes

全プロットに共通した引数じゃないとエラー

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure()  # 先のFigureを作成
d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
d2 = go.Bar(x=x, y=y2, name='y2')  # y2のプロット
fig.add_traces((d1, d2))

# go.Barの棒グラフには引数modeはないからエラー
fig.update_traces(mode='markers')  # プロットのモードをマーカーだけに更新
# ValueError: Invalid property specified for object of type plotly.graph_objs.Bar: 'mode'

# Did you mean "base"?

先程の例だとy1, y2どちらもgo.Scatterで引数modeを編集した。しかし、引数modeがないgo.Barを使用したときはエラーとなる。

上の例だとy2のプロットがgo.Barなので、fig.update_tracesmodeを指定するとエラーとなる。

この状況でy1modeを変更したいなら次で解説する引数selectorを使用しなければいけない。

selectorで更新対象を選択

一部のプロットの引数のみを変更したい場合はupdate_tracesで引数selectorを使用すれば良い。

ここではname=’y1’でプロット名がy1のものを選んでいるが、プロットのtype=’scatter’のようにプロットのタイプで指定することも可能。また、marker_colormodeでも指定可能なので、状況に応じて適切な選択が可能。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure()  # 先のFigureを作成
d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
d2 = go.Bar(x=x, y=y2, name='y2')  # y2のプロット
fig.add_traces((d1, d2))

fig.update_traces(
    mode='markers',
    marker_symbol='star',  # マーカーの形状を四角形に
    marker_size=30,  # マーカーのサイズを30に
    selector=dict(name='y1')  # selectorでどのプロットに対して更新するか選択可能
)
fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_update_traces_selector"
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")

overwriteで引数を上書き

また、update_tracesの引数overwrite=Trueで設定内容を上書きすることが可能。ここでは予めmarker_color=’red’でマーカーの色を赤色にしたfig上書きで不透明度opacity=0.2に変更した。

こうすることで、元々の赤色の設定が上書きによって消え、不透明度だけが反映されることになる。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure(go.Bar(x=x, y=y1, name='y1', marker_color='red'))
print(fig)
# Figure({
#     'data': [{'marker': {'color': 'red'}, 'name': 'y1', 'type': 'bar', 'x': [1, 2, 3], 'y': [1, 3, 2]}],
#     'layout': {'template': '...'}
# })

# 透明度で上書き
fig.update_traces(
    overwrite=True,  # 上書きする
    marker={'opacity': 0.2}  # 透明度を変更
)
print(fig)
# Figure({
#     'data': [{'marker': {'opacity': 0.2}, 'name': 'y1', 'type': 'bar', 'x': [1, 2, 3], 'y': [1, 3, 2]}],
#     'layout': {'template': '...'}
# })

fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_update_traces_overwrite"
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")

アンダースコア_だと追加になる

ただし、overwriteする内容をアンダースコア_で繋いでしまうと、上書きではなく追加になることに注意。公式ではこのアンダースコアについて以下の記述がある。

In the example below, the red color of markers is overwritten when updating marker in update_traces() with overwrite=True. Note that setting instead marker_opacity with the magic underscore would not overwrite marker_color because properties would be overwritten starting only at the level of marker.opacity.

要するに、ここの例だとmarker_opacityで書くとopacityの内容だけが更新され、marker全体には影響がないということ。一方で、marker={'opacity': 0.2}とするとmarker自体をこのように書き換えるので上書きになる。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure(go.Bar(x=x, y=y1, name='y1', marker_color='red'))
print(fig)
# Figure({
#     'data': [{'marker': {'color': 'red'}, 'name': 'y1', 'type': 'bar', 'x': [1, 2, 3], 'y': [1, 3, 2]}],
#     'layout': {'template': '...'}
# })

# アンダースコアを使った省略方法だと上書きじゃなくて追記になる
fig.update_traces(
    overwrite=True,  # 上書きする
    marker_opacity=0.2  # アンダースコアの書き方にすると上書きされない
)
print(fig)
# Figure({
#     'data': [{'marker': {'color': 'red', 'opacity': 0.2}, 'name': 'y1', 'type': 'bar', 'x': [1, 2, 3], 'y': [1, 3, 2]}],
#     'layout': {'template': '...'}
# })

fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_update_traces_overwrite_underscore"
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")

for_each_tracefigを後から追記・修正

ちょっと応用的な内容だけど、一度作成したfigを後から修正する際にはfig.for_each_traceを使用することができる。

これを使うことで、forを使って数行かけて変更しなければいけない内容を1行でサクッと変更することができる。

lambda文で所定の動作を1行で

fig.for_each_tracelambda式とともに使われることが多い、fig内の特定の引数を全て書き換えてくれるというもの。forで全プロットについて書き換えるところを1行で済ませるイメージ。

ここではmarker_symbol=’square’でマーカーシンボルを全て四角形に変更した。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure()  # 先のFigureを作成

d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
d2 = go.Scatter(x=x, y=y2, name='y2')  # y2のプロット
fig.add_traces((d1, d2))  # 複数形にすると複数プロットを追記可能

print(fig)
# Figure({
#     'data': [{'name': 'y1', 'type': 'scatter', 'x': [1, 2, 3], 'y': [1, 3, 2]},
#              {'name': 'y2', 'type': 'scatter', 'x': [1, 2, 3], 'y': [4, 2, 3.5]}],
#     'layout': {'template': '...'}
# })

# マーカーのシンボルをsquareに変更
fig.for_each_trace(lambda t: t.update(marker_symbol='square'))
print(fig)
# Figure({
#     'data': [{'marker': {'symbol': 'square'}, 'name': 'y1', 'type': 'scatter', 'x': [1, 2, 3], 'y': [1, 3, 2]},
#              {'marker': {'symbol': 'square'}, 'name': 'y2', 'type': 'scatter', 'x': [1, 2, 3], 'y': [4, 2, 3.5]}],
#     'layout': {'template': '...'}
# })

fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_for_each_trace"
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")

for文でも追記・修正可能

lambda式とか面倒なものが出てきたけど、結局のところは以下とやっていることは同じ。figの中のdata部分について、全プロットのマーカーシンボルを変更している。

以下ではlambda式を使って全プロットを対象にしていた内容を、forで書いている。パッと見のわかりやすさだforを使った方がいいかもしれない。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure()  # 先のFigureを作成

d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
d2 = go.Scatter(x=x, y=y2, name='y2')  # y2のプロット
fig.add_traces((d1, d2))  # 複数形にすると複数プロットを追記可能

# forを使って1プロットずつ中身を見て、マーカーシンボルを変更することも可能
for num, _ in enumerate(fig['data']):
    fig['data'][num]['marker_symbol'] = 'square'

print(fig)
# Figure({
#     'data': [{'marker': {'symbol': 'square'}, 'name': 'y1', 'type': 'scatter', 'x': [1, 2, 3], 'y': [1, 3, 2]},
#              {'marker': {'symbol': 'square'}, 'name': 'y2', 'type': 'scatter', 'x': [1, 2, 3], 'y': [4, 2, 3.5]}],
#     'layout': {'template': '...'}
# })

fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_for_each_trace_for"
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")

ifを使って条件分岐

さっきまでは全プロットに対して、マーカーを四角形に変更したが、ifを使うことで特定のプロットに対してのみの適用も可能。以下ではy1だけシンボルを四角形にした。

なお、ifで当てはまらない条件についてはelseで処理されるが、特に処理内容がない場合は()を記述する必要がある。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure()  # 先のFigureを作成

d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
d2 = go.Scatter(x=x, y=y2, name='y2')  # y2のプロット
fig.add_traces((d1, d2))  # 複数形にすると複数プロットを追記可能

print(fig)
# Figure({
#     'data': [{'name': 'y1', 'type': 'scatter', 'x': [1, 2, 3], 'y': [1, 3, 2]},
#              {'name': 'y2', 'type': 'scatter', 'x': [1, 2, 3], 'y': [4, 2, 3.5]}],
#     'layout': {'template': '...'}
# })

# y1だけシンボルを変更
fig.for_each_trace(lambda trace: trace.update(marker_symbol='square') if trace.name == 'y1' else ())
print(fig)
# Figure({
#     'data': [{'marker': {'symbol': 'square'}, 'name': 'y1', 'type': 'scatter', 'x': [1, 2, 3], 'y': [1, 3, 2]},
#              {'marker': {'symbol': 'square'}, 'name': 'y2', 'type': 'scatter', 'x': [1, 2, 3], 'y': [4, 2, 3.5]}],
#     'layout': {'template': '...'}
# })

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_for_each_traces_if"
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")

ifを使うならelseは必須

import plotly.graph_objects as go
import plotly.io as pio

fig = go.Figure()  # 先のFigureを作成

d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
d2 = go.Scatter(x=x, y=y2, name='y2')  # y2のプロット
fig.add_traces((d1, d2))  # 複数形にすると複数プロットを追記可能

# elseで行う内容がなくてもelseは書かないといけない
fig.for_each_trace(lambda trace: trace.update(marker_symbol='square') if trace.name == 'y1')
#     fig.for_each_trace(lambda trace: trace.update(marker_symbol='square') if trace.name == 'y1')
#                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# SyntaxError: expected 'else' after 'if' expression

else以下で何も処理することがないからelseを省略しようとするとエラー。必ずelseとセットにする必要がある。

go.Figureの引数layoutlistでレイアウトを格納

ここまでプロットについて書いてきたが、レイアウトについても同様に色んな書き方がある。まずは執筆者がよく使う、一旦他の変数にレイアウト情報を入れるスタイル。

イメージはプロットの時と同じで、何かしらの変数(ここではlayout)で内容を設定してから、go.Figureの引数layoutに入れる。

ここでは横軸・縦軸の軸ラベルを設定してみた。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

# 全プロットを入れるためのlist
plot = []

# プロットをlistへ格納
d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
plot.append(d1)  # プロットを格納

d2 = go.Scatter(x=x, y=y2, name='y2')  # y2のプロット
plot.append(d2)  # プロットを格納

# レイアウトの作成
layout = go.Layout(xaxis_title='x', yaxis_title='Y')
# dataとともにlayoutも入れられる
fig = go.Figure(data=plot, layout=layout)  # Figureの作成
print(fig)
# Figure({
#     'data': [{'name': 'y1', 'type': 'scatter', 'x': [1, 2, 3], 'y': [1, 3, 2]},
#              {'name': 'y2', 'type': 'scatter', 'x': [1, 2, 3], 'y': [4, 2, 3.5]}],
#     'layout': {'template': '...', 'xaxis': {'title': {'text': 'x'}}, 'yaxis': {'title': {'text': 'Y'}}}
# })

fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_append_layout"
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")

update_layoutでレイアウトの更新

レイアウトの場合もupdateが可能。レイアウトはadd_layoutのように追加するスタイルではなく更新するスタイル。なお、annotationなど一部引数についてはaddで追加可能。

update_layoutもその中で軸ラベルの編集を行なった。やっていることは同じ。書き方が異なるだけだ。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure()  # 先のFigureを作成

d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
d2 = go.Scatter(x=x, y=y2, name='y2')  # y2のプロット
fig.add_traces((d1, d2))  # 複数形にすると複数プロットを追記可能
print(fig)
# Figure({
#     'data': [{'name': 'y1', 'type': 'scatter', 'x': [1, 2, 3], 'y': [1, 3, 2]},
#              {'name': 'y2', 'type': 'scatter', 'x': [1, 2, 3], 'y': [4, 2, 3.5]}],
#     'layout': {'template': '...'}
# })

# 既存のfigに軸ラベルを追加
fig.update_layout(xaxis_title='x', yaxis_title='Y')
print(fig)
# Figure({
#     'data': [{'name': 'y1', 'type': 'scatter', 'x': [1, 2, 3], 'y': [1, 3, 2]},
#              {'name': 'y2', 'type': 'scatter', 'x': [1, 2, 3], 'y': [4, 2, 3.5]}],
#     'layout': {'template': '...', 'xaxis': {'title': {'text': 'x'}}, 'yaxis': {'title': {'text': 'Y'}}}
# })

fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_update_layout"
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")

update_xaxes, update_yaxesで直接変更可能

なお、横軸xaxes、縦軸yaxesについてはそれぞれupdate_xaxes, update_yaxesで直接変更可能。fig.upddate_一覧は以下だった。

直接変更することができるから、引数は軸ラベルのテキストを決めるtitleだけでよくなる。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure()  # 先のFigureを作成

d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
d2 = go.Scatter(x=x, y=y2, name='y2')  # y2のプロット
fig.add_traces((d1, d2))  # 複数形にすると複数プロットを追記可能
print(fig)
# Figure({
#     'data': [{'name': 'y1', 'type': 'scatter', 'x': [1, 2, 3], 'y': [1, 3, 2]},
#              {'name': 'y2', 'type': 'scatter', 'x': [1, 2, 3], 'y': [4, 2, 3.5]}],
#     'layout': {'template': '...'}
# })

# figに直接追加も可能
fig.update_xaxes(title='x')
fig.update_yaxes(title='y')
print(fig)
# Figure({
#     'data': [{'name': 'y1', 'type': 'scatter', 'x': [1, 2, 3], 'y': [1, 3, 2]},
#              {'name': 'y2', 'type': 'scatter', 'x': [1, 2, 3], 'y': [4, 2, 3.5]}],
#     'layout': {'template': '...', 'xaxis': {'title': {'text': 'x'}}, 'yaxis': {'title': {'text': 'y'}}}
# })

fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_update_xyaxes"
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")

ピリオド.を使ってプロパティへアクセス

最後にピリオド.を使った変更方法を解説する。figdictのように扱うことができるので、以下のようにピリオドを使用することで深い階層にアクセスすることが可能。

1行目がピリオド使用の方法、2行目がカッコを使ってアクセスする方法。個人的にはカッコを使う方がエディタ上での色が変わるからわかりやすい。ただ、ピリオドの方が短く書くことができる。

fig.layout.title.text = 'text'
fig['layout']['title']['text'] = 'text'

layoutに対してピリオドでアクセス

まずはレイアウトから。figの中にはdatalayoutがあるので(他にもアニメーションで使用するframesがある)、その中のlayoutを.でアクセス。

さらに.でlayoutの中のtitleと、titleの中のtextにもアクセス。最後に= ‘text’とすることで、グラフタイトルを’text’に変更することが可能になる。

ここではグラフタイトルにしたけど、もちろん他の引数にも適用可能。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure()  # 先のFigureを作成

d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
d2 = go.Scatter(x=x, y=y2, name='y2')  # y2のプロット
fig.add_traces((d1, d2))  # 複数形にすると複数プロットを追記可能
print(fig)
# Figure({
#     'data': [{'name': 'y1', 'type': 'scatter', 'x': [1, 2, 3], 'y': [1, 3, 2]},
#              {'name': 'y2', 'type': 'scatter', 'x': [1, 2, 3], 'y': [4, 2, 3.5]}],
#     'layout': {'template': '...'}
# })

fig.layout.title.text = 'text'
# # 意味としては以下と同じ
# fig['layout']['title']['text'] = 'text'
print(fig)
# Figure({
#     'data': [{'name': 'y1', 'type': 'scatter', 'x': [1, 2, 3], 'y': [1, 3, 2]},
#              {'name': 'y2', 'type': 'scatter', 'x': [1, 2, 3], 'y': [4, 2, 3.5]}],
#     'layout': {'template': '...', 'title': {'text': 'text'}}
# })

fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_change_layout_period"
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")

traceに対してピリオドでアクセス

traceの場合はちょっと面倒。というのも、レイアウトのように1つのグラフに1つの対応ではなく、1つのグラフに対して複数のプロットが想定されるから。

したがって、fig.datadataにアクセスした後にどのプロットを選択するのかを選ばないといけない。これについてはピリオドで対応できないので[0]のようにインデックス指定する必要がある。

ここでは0番目、すなわちy1のマーカーのシンボルをsquareに変更した。

import plotly.graph_objects as go
import plotly.io as pio

x = (1, 2, 3)
y1 = (1, 3, 2)
y2 = (4, 2, 3.5)

fig = go.Figure()  # 先のFigureを作成

d1 = go.Scatter(x=x, y=y1, name='y1')  # y1のプロット
d2 = go.Scatter(x=x, y=y2, name='y2')  # y2のプロット
fig.add_traces((d1, d2))  # 複数形にすると複数プロットを追記可能
print(fig)
# Figure({
#     'data': [{'name': 'y1', 'type': 'scatter', 'x': [1, 2, 3], 'y': [1, 3, 2]},
#              {'name': 'y2', 'type': 'scatter', 'x': [1, 2, 3], 'y': [4, 2, 3.5]}],
#     'layout': {'template': '...'}
# })

print(fig.data)  # figの中のdata一覧
# (Scatter({
#     'name': 'y1', 'x': [1, 2, 3], 'y': [1, 3, 2]
# }), Scatter({
#     'name': 'y2', 'x': [1, 2, 3], 'y': [4, 2, 3.5]
# }))
print(fig.data[0])  # dataの0番目=y1
# Scatter({
#     'name': 'y1', 'x': [1, 2, 3], 'y': [1, 3, 2]
# })
print(fig.data[0].marker)  # y1のマーカー
# scatter.Marker()
print(fig.data[0].marker.symbol)  # y1のマーカーのシンボル
# None
fig.data[0].marker.symbol = 'square'  # シンボルをsquareに変更
print(fig.data[0].marker.symbol)
# square

print(fig)
# Figure({
#     'data': [{'marker': {'symbol': 'square'}, 'name': 'y1', 'type': 'scatter', 'x': [1, 2, 3], 'y': [1, 3, 2]},
#              {'name': 'y2', 'type': 'scatter', 'x': [1, 2, 3], 'y': [4, 2, 3.5]}],
#     'layout': {'template': '...'}
# })

fig.show()

# グラフ保存
prefix = 'plotly-creating-updating-figures'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_change_plot_period"
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")

自分に合ったものを

今回はplotlyでプロットを作成する方法について色々と紹介した。今回の内容を全て書けるようになるのが一番だけど、まずは自分に合ったものから取り入れ、そこから派生させる方がハードルが低いからおすすめ。

本記事をきっかけにplotlyで色んな使いやすいグラフを描けるようになっていただけると幸いだ。

関連記事

【plotly&legendまとめ】凡例の引数一覧

続きを見る

【plotly&pattern】棒グラフとかのパターンまとめ

続きを見る

【plotly&ボタン】plotlyのupdatemenusにbuttonsを追加

続きを見る

【plotly&棒グラフ】go.Barでバーチャートを作成

続きを見る

【plotly&fill】goで領域を塗りつぶし

続きを見る

【plotly&スライダー】plotlyのslidersにスライダーを追加

続きを見る

【plotly&3D】goで3Dグラフを作成

続きを見る

【plotly&size, width】Scatterのサイズやlineの太さ一覧表を作成

続きを見る

関連コンテンツ

スポンサーリンク

Amazonのお買い物で損したない人へ

1回のチャージ金額通常会員プライム会員
¥90,000〜2.0%2.5%
¥40,000〜1.5%2.0%
¥20,000〜1.0%1.5%
¥5,000〜0.5%1.0%

Amazonギフト券にチャージすることでお得にお買い物できる。通常のAmazon会員なら最大2.0%、プライム会員なら2.5%還元なのでバカにならない。

ゲットしたポイントは通常のAmazonでのお買い物に使えるからお得だ。一度チャージしてしまえば、好きなタイミングでお買いものできる。

なお、有効期限は10年だから安心だ。いつでも気軽にAmazonでお買い物できる。

Amazonチャージはここから出来るで

もっとお得なAmazon Prime会員はこちらから

30日間無料登録

執筆者も便利に使わせてもらってる

スポンサーリンク

  • この記事を書いた人

メガネ

独学でpythonを学び天文学系の大学院を修了。 ガジェット好きでMac×Android使い。色んなスマホやイヤホンを購入したいけどお金がなさすぎて困窮中。 元々、人見知りで根暗だったけど、人生楽しもうと思って良い方向に狂ったために今も人生めちゃくちゃ楽しい。 pythonとガジェットをメインにブログを書いていますので、興味を持たれましたらちょこちょこ訪問してくだされば幸いです🥰。 自己紹介→変わって楽しいの繰り返し

-Plotly全般
-, , , ,