ポタージュを垂れ流す。

マイペースこうしん(主に旅行)

グラフ作成の備忘録

思い出したら追記する。個人的なメモ

より良いのがあったら教えてください

matplotlib

プロット表示設定

import matplotlib as mpl
mpl.rcParams['font.family'] = 'sans-serif'
mpl.rcParams['font.size'] = 16
mpl.rcParams['xtick.direction'] = 'in'
mpl.rcParams['ytick.direction'] = 'in'
mpl.rcParams['xtick.top'] = True
mpl.rcParams['ytick.right'] = True
mpl.rcParams['agg.path.chunksize'] = 100000
  • フォントをサンセリフ体にする(個人的な好み)
  • フォントサイズを16にする(デフォルトは12)
  • 目盛り線の向きを内向きにする(x軸方向)
  • 目盛り線の向きを内向きにする(y軸方向)
  • 目盛り線を書く(上側)
  • 目盛り線を書く(右側)
  • 大きなデータでplt.savefigした時にエラー吐かないようにするやつ

フォーマッタ

普段google colaboratoryを使っているので、それで使えるフォーマッタ。マジックコマンドを作ってくださっている方がいた。

note.com

google colaboratoryでデフォルトでは使えないフォントを使う

google drive内にfontというフォルダを作り、そこにフォントを入れておく。

フォルダ構成の例:

/content/drive/MyDrive/font/
└── Tsukushi A Round Gothic
    └── TsukushiAMaruGothic.ttc

その後、以下を実行

from google.colab import drive
drive.mount("/content/drive")

!cp -a "drive/MyDrive/font/" "/usr/share/fonts/"

!rm -r /root/.cache/matplotlib/

その後ランタイムを再起動する

プロット例1

f:id:potaxyz:20220212205154p:plain

fig, ax = plt.subplots(figsize=(8, 6))
ax.grid(axis="both", which="major", linestyle="--")
ax.set_xlabel("Energy [MeV]")
ax.set_ylabel("Events [count/s/MeV]")
ax.set_xlim([0.2, 6])
ax.set_yscale("log")
ax.plot(x, y)
plt.savefig("sample.png",dpi=300)

一番スタンダードな図?

一部だけ設定を変える

そのセルに表示される図表だけ設定を変えたい場合

設定をrc_contextに入れておく

COLOR_DARK = "#455a64"
COLOR_LIGHT = "#ffffff"
rc_context={
    "font.family":"Tsukushi A Round Gothic",
    "font.size":18,
    "axes.facecolor":"none",
    "legend.facecolor":COLOR_DARK,
    "text.color":COLOR_LIGHT,
    "axes.labelcolor":COLOR_LIGHT,
    "axes.edgecolor":COLOR_LIGHT,
    "xtick.color":COLOR_LIGHT,
    "ytick.color":COLOR_LIGHT
}
with plt.rc_context(rc_context):
    # 普通にグラフ作る

プロット例2

上を利用してプロット。

f:id:potaxyz:20220212212601p:plain

with plt.rc_context(rc_context):
    fig, ax = plt.subplots(figsize=(10, 8))
    for id in sorted(dict_dataframes.keys()):
        df = dict_dataframes[id]
        ax.plot(df["time_elapsed"],
                df["fit_residual"],
                label="ID {}".format(id))
    ax.grid(axis="both", which="major", linestyle="--")
    ax.minorticks_on()
    ax.set_xlabel("Time[min]")
    ax.set_ylabel("Pressure (baseline subtracted)[hPa]")
    ax.legend(bbox_to_anchor=(1.05, 1), loc="upper left", borderaxespad=0)
    ax.set_xlim(-200, 200)
    ax.set_ylim(-0.6, 2.1)
    plt.savefig("pressure_subtracted.png",
                facecolor="#222222",
                bbox_inches="tight",
                dpi=300)
    #スライドに貼る時はこっちを使う
    #plt.savefig("pressure_subtracted.svg",transparent=True,bbox_inches="tight")
  • minorticks_on()で補助目盛りがつく

プロット例3

f:id:potaxyz:20220212213421p:plain

with plt.rc_context(rc_context):
    id = 13
    df = dict_dataframes[id]
    fig, ax = plt.subplots(figsize=(10, 8))
    ax.minorticks_on()
    ax.grid(axis="both", which="major", linestyle="--", color=COLOR_LIGHT)
    ax.grid(axis="both", which="minor", linestyle="--")
    ax.tick_params(axis="both", which="major", direction="in", length=5)
    ax.tick_params(axis="both", which="minor", direction="in", length=3)
    ax.plot(df["time_elapsed"],
            df["fit_residual"],
            marker="o",
            ls="-",
            color=COLOR_LIGHT,
            markerfacecolor="r",
            markersize=12,
            label="ID {} (baseline subtracted)".format(id))
    ax.set_xlim(-200, 200)
    ax.set_ylim(-0.6, 2.1)
    ax.set_ylabel("Pressure (baseline subtracted)[hPa]")
    ax.set_xlabel("Time[min]")
    ax.legend()
    plt.savefig("13.png",
                facecolor="#222222",
                bbox_inches="tight",
                dpi=300)
    #スライドに貼る時はこっちを使う
    #plt.savefig("13.svg",transparent=True,bbox_inches="tight")

スライドの例

f:id:potaxyz:20220212211054p:plain
スライドの例

最近はMarpというmarkdownでスライド作れるやつを使ってスライドを作成している。テーマはinvert。フォントはmacOSに標準搭載されている筑紫a丸ゴシックを使用している。(かわいいフォントで好き)

プロット例4

f:id:potaxyz:20220212215503p:plain

# from datetime import datetime, timedelta, timezone
# from matplotlib import dates as mdates

cmap = plt.get_cmap("tab10")
baseline = datetime(2022, 1, 15, 20, 40)
w = timedelta(seconds=12000)

fig = plt.figure(figsize=(24, 12))
grid = plt.GridSpec(2, 3, hspace=0)
axs = [fig.add_subplot(grid[i // 3, i % 3]) for i in range(6)]
for i in range(6):
    axs[i].plot(x, y[i], c=cmap(i))
    axs[i].set_ylabel("area{}[cps]".format(i + 1))
    axs[i].set_xlim(baseline - w, baseline + w)
    if i // 3 == 0:
        axs[i].tick_params(labelbottom=False)
    axs[i].xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
    axs[i].axvline(baseline, c="red", linestyle="--")
    axs[i].grid(axis="both", which="major", linestyle="--")
plt.savefig("areas.png",bbox_inches="tight",dpi=300)
#plt.savefig("areas.svg",transparent=True,bbox_inches="tight")
  • cmapでカラーマップの指定ができる。tab10が通常のカラーマップ。
  • 複数の図を並べるにはGridSpecを使うと楽?hspace,wspaceで図表の間隔を調節
  • tick_params(labelbottom=False)でラベルを消す
  • set_major_formatterで時刻軸のフォーマットを変える

プロット例5

f:id:potaxyz:20220212224716p:plain

# import matplotlib.pyplot as plt
# import matplotlib as mpl
# import seaborn as sns
# import numpy as np
# import pandas as pd

fig = plt.figure(figsize=(24, 10))
grid = plt.GridSpec(10, 2, hspace=0, wspace=0.15)
axLs = [fig.add_subplot(grid[i, 0]) for i in range(10)]
axR = fig.add_subplot(grid[:, 1])
for i in range(10):
    axLs[i].plot(df.iloc[:, i])
    axLs[i].set_ylabel(df.columns[i], labelpad=10)
plt.setp(axLs[9].get_xticklabels(), rotation=45)
sns.heatmap(df.corr(),
            annot=True,
            cmap="coolwarm",
            fmt=".2f",
            annot_kws={"size": 14},
            ax=axR,
            center=0)
axR.set_title("correlation")
plt.savefig("sample.png",dpi=300)
  • ヒートマップはseabornを使うと楽
  • sns.heatmapのaxにfig.add_subplotぶち込めばこうやって並べることができる

pickleの利用

めっちゃデカいデータの処理を中断した状態から再開したりとか、ローカルランタイムで処理しておいたものをgoogle driveにアップロードしておいて後で使う、みたいなことができる。処理後のデータ等をpickleという形式にしておいて後で読み込み、データを使うことができる。

# super_big_dataはなんかクソデカデータ
import pickle
with open("super_big_data.pickle", "rb") as pkl:
    pickle.dump(super_big_data,pkl)
super_big_pickle_file="super_big_data.pickle"
with open(super_big_pickle_file, "rb") as pkl:
    super_big_data = pickle.load(pkl)

プロット例6

f:id:potaxyz:20220212233127p:plain

pickle_file="take_time_to_make_np_array.pickle"
with open(pickle_file, "rb") as pkl:
    zz = pickle.load(pkl)[1:].T[1:].T

fig, ax = plt.subplots(figsize=(12, 8))
x = np.log(np.linspace(0, 70, 700 + 1)[1:])
y = np.log(np.linspace(0, 20, 200 + 1)[1:])
z = np.outer(y, x)
S = np.sort(events[0] * events[1])
mappable = ax.pcolormesh(x, y, zz, cmap="Blues_r")
fig.colorbar(mappable, ax=ax, label="z")
ax.scatter(events[0], events[1], c="red", zorder=99, marker="x")
ct = ax.contour(x, y, z, cmap="hsv", levels=S, zorder=90)
ax.clabel(ct, fontsize=14)
for i in range(len(files_and_errortime)):
    ax.annotate("Event {}".format(i + 1), (events[0][i], events[1][i]),
                c="red",
                zorder=99,
                fontsize=14)
ax.set_xlabel("log x")
ax.plot(x,
        exponent * x + constant,
        c="black",
        lw=5,
        label=r"$\log y={}+{}\log x$".format(round(exponent, 2),
                                             round(constant, 2)))
ax.set_ylabel("log y")
ax.set_xlim([0, 4])
ax.set_ylim([0, 3])
ax.legend(loc="lower left")
#plt.savefig("sample.png",dpi=300)
  • 配列zzを作るのにかなり時間がかかるのでpickleで読み込んでくる
  • ax.pcolormeshでz方向が色になるような感じのグラフが作れる
  • contourのclabelの数字の位置の指定はよくわからなかった

plotly

インタラクティブなグラフを作るライブラリは色々あるけどここではplotlyを取り上げる(使ったことあるのがこれだけなので)。

プロット例1

plotlyを使ってインタラクティブなグラフを表示する例(下のグラフは触ってみると動きます)

# import plotly.offline as po
# import plotly.graph_objects as go
# from plotly.subplots import make_subplots
# po.init_notebook_mode()

fig = make_subplots(rows=2, cols=1)
for id in sorted(dict_dataframes.keys()):
    fig.add_trace(
        go.Scatter(
            x=dict_dataframes[id].index,
            y=dict_dataframes[id]["pressure"],
            mode="lines",
            name="id {}".format(id),
        ), 1, 1)
    fig.add_trace(
        go.Scatter(
            x=dict_dataframes[id].index,
            y=dict_dataframes[id]["fit_residual"],
            mode="lines",
            name="id {} (subtracted)".format(id),
        ), 2, 1)
fig.update_layout(yaxis_title_text="Pressure")
fig.update_layout(yaxis2_title_text="Pressure (Baseline Subtracted)")
fig.update_layout(xaxis2_title_text="Time")
fig.update_layout(width=800, height=800)
fig.update_xaxes(matches="x")
fig.update_xaxes(
    type="date",
    range=[datetime(2022, 1, 15, 17, 30),
           datetime(2022, 1, 16, 0, 0)])
fig.add_vrect(
    x0=datetime(2022, 1, 15, 20, 30),
    x1=datetime(2022, 1, 15, 20, 50),
    fillcolor="lightsalmon",
    opacity=0.3,
    layer="below",
    line_width=0,
)
fig.add_vrect(
    x0=datetime(2022, 1, 15, 20, 50),
    x1=datetime(2022, 1, 15, 21, 40),
    fillcolor="lightgreen",
    opacity=0.3,
    layer="below",
    line_width=0,
)
fig.show(renderer="colab") #colaboratoryで使う時はこれで表示

colaboratoryとか自分のパソコン内でpython実行するだけならそのまま実行できるが、こうやってブログにのっけて公開するときはplotlyのページでSign Upする必要がある。

chart-studio.plotly.com

サインインしてsettings > API Keys、Regenerate Keyをしてapi_keyを取得する。その後下を実行する。

import chart_studio
chart_studio.tools.set_credentials_file(username="xxxxx", api_key="xxxxx")
import chart_studio.plotly as py
py.plot(fig, filename="sample", auto_open=True)

colaboratoryで実行するとリンクが取得できるので、iframeのsrcにぶち込んで貼り付けるといい。

gnuplot

texと親和性の高い図をgnuplotで生成する1

あんまり覚えてないけど実験で使ってたのを引っ張ってきた

set terminal epslatex size 14cm,10cm
set output "graph.eps"
set border lw 2
set xlabel "{$x(t)$}"
set ylabel "{$y(t)$}"
set zlabel "{$z(t)$}"
set ztics 10
set mxtics 2 
set mytics 2
set mztics 2
splot "lorenz_equation.txt" u 2:3:4 w l title "Lorenz equation"
quit

lorenz_equation.txtローレンツ方程式を計算した各点のデータ

こんな感じで作ったgnuplotファイル(拡張子がgp)をgnuplot make_graph.gpかなんかで実行してやるとepsファイルとtexファイルが生成される(graph.epsgraph.tex)。epsファイルが表示させたい曲線とか、texファイルに枠の情報が入ってる。texファイルの方は数字の位置とか気に入らなければ目grepしてやればいいと思う。

個人的にはこっちより下の方を使うことが多いが、点データが多すぎると生成されるtexファイルが重くなってしまうので、そういう時はこっちを使っている。

たまに位置ずれが起きたりするのがあんまり好きじゃないポイントではある。

texと親和性の高い図をgnuplotで生成する2

f:id:potaxyz:20220213002456j:plain

あんまり覚えてないけど実験で使ってたのを引っ張ってきた2

こっちは上と比較してepsファイルを出力せずtexファイルだけ生成するもの。

はじめにmacならターミナルを開いて作業フォルダでgnuplotと打ち込んで起動。その後set term tikz createstyleをする(なぜかパイプで渡せないため)。と、なんかいろいろ3つくらいgnuplot-lua-tikz.texみたいなファイルができる。

set terminal tikz size 8cm,6cm
set output "graph.tex"
set border lw 2
set xlabel "{$t$}"
set ylabel "{$u$}"
set mxtics 4
set mytics 4
#set xrange [0:20]
set yrange [0:10]
plot \
    "09.txt" u 1:2 w l lw 2 title "{$u_0=0.9$}",\
    "10.txt" u 1:2 w l lw 2 title "{$u_0=1.0$}",\
    "11.txt" u 1:2 w l lw 2 title "{$u_0=1.1$}"
quit

各txtファイルは数値計算結果が入っている。こいつを実行してやるとgraph.texが出力される。

メインのtexファイルには\usepackage{gnuplot-lua-tikz}を入れておく。あとはgraph.texを読み込みたいところに\include{graph}すればOK。

他の例

f:id:potaxyz:20220213002154p:plain

これはgnuplotファイルを頑張ると並べて表示できるという例

width=0.22
lms0=0.03
rms0=lms0+width
lms1=rms0+0.02
rms1=lms1+width
lms2=rms1+0.02
rms2=lms2+width
lms3=rms2+0.02
rms3=lms3+width

height=0.3
bms2=0.04
tms2=bms2+height
bms1=tms2+0.03
tms1=bms1+height
bms0=tms1+0.03
tms0=bms0+height

#set terminal postscript enhanced color
#set output "kadai3graph.eps"
#set terminal epslatex size 24cm,18cm
#set output "kadai3graph.eps"
set terminal tikz size 24cm,14cm
set output "kadai3graph.tex"

set border lw 2
#set ylabel "{$x(t)$}"
set clip two
set mytics 4 
#set xrange [0:100]
set xtics 20
set logscale y
#set key left top
unset key
set multiplot

##########0

set title "{$n=100$}"

set lmargin screen lms0
set rmargin screen rms0
set tmargin screen tms0
set bmargin screen bms0

set logscale y
set format x ""
set format y "{$%2.1t\\times 10^{%L}$}"
set ylabel "residue"
set yrange [10**(-5):10**0]

stats "kadai3_100.txt" u 3 name "residue100"
set label 1 at graph 0,0.95 left sprintf("\\tiny Average:%e",residue100_mean) tc rgb "red"

plot "kadai3_100.txt" u 1:3 w p pt 2 lt 1 lw 2,\
    residue100_mean lc rgb "red" lw 1 dt 2

unset title

set lmargin screen lms0
set rmargin screen rms0
set tmargin screen tms1
set bmargin screen bms1

set logscale y
set format x ""
set format y "{$%2.1t\\times 10^{%L}$}"
set yrange [10**(-6):10**(-2)]
set ylabel "relative error"

stats "kadai3_100.txt" u 4 name "relativeerror100"
set label 1 at graph 0,0.95 left sprintf("\\tiny Average:%e",relativeerror100_mean) tc rgb "red"

plot "kadai3_100.txt" u 1:4 w p pt 3 lt 1 lw 2,\
    relativeerror100_mean lc rgb "red" lw 1 dt 2

set lmargin screen lms0
set rmargin screen rms0
set tmargin screen tms2
set bmargin screen bms2

set logscale y
set format "%g"
#unset format y
set format y "{$%2.1t\\times 10^{%L}$}"
set xlabel "trials"
set ylabel "time[ms]"
set yrange [10**1:10**4.3]
stats "kadai3_100.txt" u 2 name "time100"
set label 1 at graph 0,0.95 left sprintf("\\tiny Average:%e",time100_mean) tc rgb "red"

plot "kadai3_100.txt" u 1:2 w p pt 4 lt 1 lw 2,\
    time100_mean lc rgb "red" lw 1 dt 2

##########1

set logscale y
set title "{$n=200$}"
set format ""
unset xlabel
unset ylabel

set lmargin screen lms1
set rmargin screen rms1
set tmargin screen tms0
set bmargin screen bms0
set yrange [10**(-5):10**0]

stats "kadai3_200.txt" u 3 name "residue200"
set label 1 at graph 0,0.95 left sprintf("\\tiny Average:%e",residue200_mean) tc rgb "red"

plot "kadai3_200.txt" u 1:3 w p pt 2 lt 2 lw 2,\
    residue200_mean lc rgb "red" lw 1 dt 2

unset title
set logscale y
set lmargin screen lms1
set rmargin screen rms1
set tmargin screen tms1
set bmargin screen bms1

set format ""
set yrange [10**(-6):10**(-2)]

stats "kadai3_200.txt" u 4 name "relativeerror200"
set label 1 at graph 0,0.95 left sprintf("\\tiny Average:%e",relativeerror200_mean) tc rgb "red"

plot "kadai3_200.txt" u 1:4 w p pt 3 lt 2 lw 2,\
    relativeerror200_mean lc rgb "red" lw 1 dt 2

set lmargin screen lms1
set rmargin screen rms1
set tmargin screen tms2
set bmargin screen bms2

set logscale y
set format x "%g"
set format y ""
set xlabel "trials"
set yrange [10**1:10**4.3]

stats "kadai3_200.txt" u 2 name "time200"
set label 1 at graph 0,0.95 left sprintf("\\tiny Average:%e",time200_mean) tc rgb "red"

plot "kadai3_200.txt" u 1:2 w p pt 4 lt 2 lw 2,\
    time200_mean lc rgb "red" lw 1 dt 2

##########2

set logscale y
set title "{$n=400$}"
set format ""
unset xlabel
unset ylabel

set lmargin screen lms2
set rmargin screen rms2
set tmargin screen tms0
set bmargin screen bms0

set yrange [10**(-5):10**0]

stats "kadai3_400.txt" u 3 name "residue400"
set label 1 at graph 0,0.95 left sprintf("\\tiny Average:%e",residue400_mean) tc rgb "red"

plot "kadai3_400.txt" u 1:3 w p pt 2 lt 3 lw 2,\
    residue400_mean lc rgb "red" lw 1 dt 2

unset title
set logscale y
set lmargin screen lms2
set rmargin screen rms2
set tmargin screen tms1
set bmargin screen bms1

set format ""
set yrange [10**(-6):10**(-2)]

stats "kadai3_400.txt" u 4 name "relativeerror400"
set label 1 at graph 0,0.95 left sprintf("\\tiny Average:%e",relativeerror400_mean) tc rgb "red"

plot "kadai3_400.txt" u 1:4 w p pt 3 lt 3 lw 2,\
    relativeerror400_mean lc rgb "red" lw 1 dt 2

set lmargin screen lms2
set rmargin screen rms2
set tmargin screen tms2
set bmargin screen bms2

set logscale y
set format x "%g"
set format y ""
set xlabel "trials"
set yrange [10**1:10**4.3]

stats "kadai3_400.txt" u 2 name "time400"
set label 1 at graph 0,0.95 left sprintf("\\tiny Average:%e",time400_mean) tc rgb "red"

plot "kadai3_400.txt" u 1:2 w p pt 4 lt 3 lw 2,\
    time400_mean lc rgb "red" lw 1 dt 2

##########
set logscale y
set title "{$n=800$}"
set format ""
unset xlabel
unset ylabel

set lmargin screen lms3
set rmargin screen rms3
set tmargin screen tms0
set bmargin screen bms0

set format ""
set yrange [10**(-5):10**0]

stats "kadai3_800.txt" u 3 name "residue800"
set label 1 at graph 0,0.95 left sprintf("\\tiny Average:%e",residue800_mean) tc rgb "red"

plot "kadai3_800.txt" u 1:3 w p pt 2 lt 4 lw 2,\
    residue800_mean lc rgb "red" lw 1 dt 2

unset title
set logscale y
set lmargin screen lms3
set rmargin screen rms3
set tmargin screen tms1
set bmargin screen bms1


set format ""
set yrange [10**(-6):10**(-2)]

stats "kadai3_800.txt" u 4 name "relativeerror800"
set label 1 at graph 0,0.95 left sprintf("\\tiny Average:%e",relativeerror800_mean) tc rgb "red"

plot "kadai3_800.txt" u 1:4 w p pt 3 lt 4 lw 2,\
    relativeerror800_mean lc rgb "red" lw 1 dt 2

set lmargin screen lms3
set rmargin screen rms3
set tmargin screen tms2
set bmargin screen bms2

set logscale y
set format x "%g"
set format y ""
set xlabel "trials"
set yrange [10**1:10**4.3]

stats "kadai3_800.txt" u 2 name "time800"
set label 1 at graph 0,0.95 left sprintf("\\tiny Average:%e",time800_mean) tc rgb "red"

plot "kadai3_800.txt" u 1:2 w p pt 4 lt 4 lw 2,\
    time800_mean lc rgb "red" lw 1 dt 2

unset multiplot
quit

長いね