よし呟こう

思ったことを呟きます。

Matplotlibでレポート用グラフ作成~よく使うもの~

特定の点・範囲の強調、グラフの中へのグラフの挿入、拡大図の添付、複軸化、(特に)ヒストグラム、軸目盛の調整......

Excelでこのような細かい要望に合ったグラフを作るのはさすがに大変。多少は自由度が高いだろうとPython+matplotlibでグラフを書いています。ところが、今度はいちいち細かいことが多くて覚えられない!(毎回、前回使ったプログラムを探すところから始まる...)。そしてグラフの見た目を変えるのが超大変!

以下では私が今まで使ってきたもので便利だなあと思いながら、覚えられなくて毎回前回使ったプログラムを探すこととなっているものを載せました。要するにメモです。適宜追加していきます。

以下のコードはいつものテンプレート(スタイル関連を除く)なのでこれを基準にメモしました。

from matplotlib import pyplot as plt
from matplotlib import font_manager as fm
from matplotlib import rcParams
from matplotlib import patches
from matplotlib.ticker import ScalarFormatter

fontsize = 25
fig, ax1 = plt.subplots(figsize=(8, 6), constrained_layout=True)


▼環境

 
 
▼コンテンツ

  
    

【便利】ダミープロット

例えばax.plot()に回帰曲線、ax.scatter()に測定点を書いた場合で凡例を表示させると、普通はax.plot()由来の線か、ax.scatter()由来のシンボル(丸とか、三角とか)しか表示されません。ax.plot()のキーワードでmarkerキーワードを使うと、この場合一般の回帰曲線を考えているので、どえらいことになるのは簡単に想像できます。回帰曲線上に測定点のシンボルを載せたような凡例が欲しい!そういう時はダミープロットを使います。

ax1.plot(回帰曲線のx軸データ, 回帰曲線のy軸データ, color)
ax1.scatter(測定点のx軸データ, 測定点のy軸データ, color, marker="o")
ax1.plot([], [], color, marker="o", label="ダミープロット!")

ax.plot()ax.scatter()両方のスタイルに合わせたダミープロットを作ります。markercolorlinestyleを統一する必要があります。
 
 

単位変換した軸を一緒に描画したい

ax.secondary_yaxis([単位を変換した軸をどこに表示するか], functions=(元の単位を目的の単位に変換する関数, 目的の単位から元の単位に変換する関数))を使います。例えば、単位がラジアンで与えられるデータがあって、これをy軸に表示しているとしましょう。このデータに対応するように度数での表示を行いたいとします。このときは次のようにします。

def rad2degree(x):
    return np.rad2deg(x)

def degree2rad(x):
    return np.deg2rad(x)

secondary_ax = ax1.secondary_yaxis(
    "right", functions=(rad2degree, degree2rad))

単位を変換した軸を一緒に載せておくと、考察が捗ることがあるので使っています。ax.secondary_yaxis()はx軸版もありax.secondary_xaxis()で同様のことができます。こちらもよく使います。

ちなみに、逆関数を定義できない領域があるときは事前にax1.set_ylim()等で制限をかけておかないとエラーが出ます。例えば、np.arccos()の定義域は-1から1ですが、そのままプロットすると-2とかまで計算することになって、NaNやInfのデータが生じ、エラーとなります。故に逆関数の定義域については慎重に検討して、すべての実数をとれるわけではないときは、その範囲に合うように表示範囲を狭め、clip_onなどで端の処理をする必要があります。
 
 

画像化と保存、トリミングの手間を省いて、解像度も上げる

やり方はplt.savefigにてpad_inchesキーワードで余白の大きさを指定(小さいほど余白が小さくなります)、dpiキーワードで解像度を指定(大きいほど解像度がよくなります)するだけです。以下の例では、matplotlibではしばしばあるラベルや軸が見切れてしまう現象を回避するためのキーワードのbbox_inchesを入れています。私はpad_inches=0.11程度で満足していますが、もっと小さい値でもいいかもしれません。

plt.savefig("filename.jpg",
            bbox_inches="tight",
            pad_inches=0.11, dpi=300)

ちなみに.pdf.svg(ベクター画像)にも対応しているようです。
 
 

水平位置と垂直位置

図中にテキストを書き込むときに水平位置と垂直位置を指定すると便利がよいことが多いです。簡単に言うと、テキストの書かれた四角い箱:テキストボックスを考えたときに、ボックスのどの値を指定した座標に持ってくるか?を決定するということですね。

ax1.text(x, y, text, fontsize,
         horizontalalignment="left",
         verticalalignment="bottom")

例えばこの場合だと、水平方向をhorizontalalignmentleft、垂直方向をverticalalignmentbottomとしているので、テキストボックスの左下の座標が引数(x, y)で指定した座標になるように描画されます。

水平位置と垂直位置。horizontalalignmentで水平方向を、verticalalignmentで垂直方向を指定。
水平位置と垂直位置。horizontalalignmentで水平方向(left(左)、center(中央)、right(右))を、verticalalignmentで垂直方向(top(上部)、center(中央)、bottom(下部))を指定。デフォルトではどちらもcenterだったはず。

 
 

複数軸グラフ

変数が同じで、しかし全く別のグラフを同時に描画したいときがあります。例えば、吸光スペクトルと蛍光スペクトルは波長という変数は同じですが、強度は任意単位で別物なので、別々に描画します。同じ変数なので1つのグラフに横軸だけ同じにして描画できるとわかりやすくて良いです。この時はax.twinx()を使います。

ただしこれだけではax.legendは元の軸の値しか描画しません(ax1を作って、ax2=ax1.twinx()としてax1.legend()とすると、ax1に描画したもののラベルだけが表示されます)。そこで新しい軸のラベルもまとめて描画するように、次の例でいうところの最後の三行を加えます。

fig, ax1 = plt.subplots(figsize=(8, 6))
ax1.plot(波長, 吸収スペクトルの強度)

ax2 = ax1.twinx()
ax2.plot(波長, 蛍光スペクトルの強度)

handler1, label1 = ax1.get_legend_handles_labels()
handler2, label2 = ax2.get_legend_handles_labels()
ax1.legend(handler1 + handler2, label1 + label2)

ax.get_legend_handles_labels()でラベルを表示するためのhandleと対応するlabelが得られますが、これらを足し合わせてあげるだけです。足し合わせる順番によって、表示される順番が変わります。
 
 

階級分けした後のヒストグラム

例えばすでに4階級に分けた離散データを格納した一次元配列dataを得られたとしましょう。その時は次のようにすればよいです。

ax1.hist(data, bins=4)

連続データの場合も似た感じなので略。ヒストグラムのためにExcelではなくpython + matplotlibを使っているまであります。
 
 

Texを使いたい

ラベルに記号や数式を入れたいときがあります。もちろん「γ」のようにあらかじめ存在している特殊記号を使うのもありですが、$\gamma$のようにできると、つまりTexが使えると非常に便利です。例えば単位の上付き文字をいちいち座標指定するのは馬鹿らしいので$\mathrm{m^2}$のようにできればなんと便利なことか!(Excelではいちいち右クリックが必要でめんどくさい)。これをやるには当該文字列を$でラップします:

ax1.text(x, y, "$\gamma$")

ただ、これだけでは$も含めた文字列だとみなされるのがほとんどなので、さらにrを先頭につけてr構文にしておきます:

ax1.text(x, y, r"$\gamma$")

ところで数式を改行するときはどうすればいいでしょうか。例えば2行に改行するときは、次に示すように2つの変数を用意するのが後で見たときにわかりやすいと思います:

text1 = r"$y = f(x; t)$"
text2 = r"$R^2 = 1.000$"
ax1.text(x, y, text1 + "\n" + text2)

では変数を文字列に組み込みたいときはどうしましょうか。次に示す方法は、直接変数を組み込む方法です。

text1 = r"$y = f(x; t=" + str(100) + r")$"
text2 = r"$R^2 = 1.000$"
ax1.text(x, y, text1 + "\n" + text2)

Texではことあるごとに{}が出てくるので、フォーマット構文やf構文が使えないと思います(使えましたっけ)。したがって直接結合する方法が一番楽なのではないかなと思います。管理がめんどくさくなりますが、確実です。
 
 

スケール関連

わかりやすさを考えて単位を変えることがありますが、単位を変えずに表示したいときがあります。例えば1\,\mathrm{m}10^9\,\mathrm{nm}ですが、これをそのままmatplotlibで表示すると「10e9」のように表示されて、わかりにくい...というか、特定の分野の人が好きそうな表示になります。できれば10のなんちゃら乗として表示したい。そこでmatplotlib.ticker.ScalarFormatterを使います。

ax1.yaxis.set_major_formatter(ScalarFormatter(useMathText=True))

また、対数スケールは次のようにして実現します。例えばy軸を対数スケールにするには

ax1.set_yscale("log")

でよいです。
 
 

描画順番と重なり

matplotlibの描画順番はよくわかりません...。先に描画したはずのものが背面に向かっていたり。。。それを調整できるのがzorderキーワードです。次の例ではラベル"first"のデータの方がラベル"second"のデータよりも上側に(画面手前側に)描画されます。zorderの値が大きいほど画面手前側に描画され、小さいほど画面反対側の方向に描画されます。負の値をとることもできるので、例えばx軸やy軸などはzorder=-1などとしておいてもよいかもしれません。

ax1.plot(x1, y1, label="first", zorder=100)
ax1.plot(x2, y2, label="second", zorder=1)

ところで、matplotlibのfigureの枠に被せたいのだけど...と思われる方もいるかもしれません。どういうことかというと、例えば(0, 0)にデータ点があって、描画範囲を0以上に設定すると、0番目の点がグラフ領域の外黒枠線の下敷きになってしまうのです。これを回避するには、clip_onキーワードを使います。clip_on=Falseで、グラフの枠や余白によって消される部分が消されないようになります(逆に言えば範囲指定を誤ると大変なことになります)。

ax1.scatter(x1, y1, label="first", zorder=100, clip_on=False)
ax1.plot(x2, y2, label="second", zorder=1, clip_on=False)

 
 

軸のメモリやラベルを削除したい

例えば任意単位のもので、メモリが不要!ラベルもいらない!といった要望があったとします。そういうときは次のようにします。

ax1.tick_params(
    labelbottom=False, labelleft=True,
    labelright=False, labeltop=False,
    bottom=False, left=True,
    right=False, top=False
)

この例では、左の軸のメモリとラベル以外のすべてのメモリとラベルが削除されます(表示されません)。

レポートをLatexで書く。私にとっての便利部品集。

お久しぶりです。生きています。

大学の講義のレポートを勝手にLatexで書くようになって早1年が経ちました。私にとってLatexは痒い所に手が届く良いものなのですが、自由度が高い故に色々とやることと方法があって大変。今時素のLatexを書く人はいないと思うのですが、1年間Latexと戯れた中で筆者が便利だと感じたものを述べておきます。......というより、毎回忘れてしまうので忘れ防止にメモしておきたい。

実際使ってみて便利だったものを集めた工夫・部品集です。

あまりLatexについて理解を深めているわけではないので、間違っている点があったらご指摘いただけると幸いです。

なお環境は次の通りです。

  • OS ... Windows 10
  • ドキュメントクラス ... jsarticle
  • 処理系 ... uplatex + dvipdfmx

適宜追加していきます。


コンテンツ

  • 【便利】余白調整
  • 【便利】二段組みとぶち抜き
  • 【便利】ファイルの分割
  • キャプションや表番号などを調整
  • 化学スキームに番号を振る
  • 参考文献の番号を上付きに
  • 図の位置
  • 単位→siunitx、化学式→mhchem
  • URLと漢字
  • 小ネタ系
続きを読む

軸方向に単調なBezier曲線の最小二乗法

最小二乗法を用いて, 指定点を通るようなBezier曲線を求めたい. はじめに, Bezier曲線のパラメータの関係で, 例えばx, y平面を考える場合は, xまたはyについて単調増加(あるいは単調減少)である必要がある. 最後にPythonによって実装を書いておいた.

間違っている可能性があるので注意.


[目次]

  • Bezier曲線の定義
  • Bezier曲線による最小二乗法
  • Pythonで実装
続きを読む

Raspberry Pi 4 便利な機能の導入メモ:AFP/Samba、イヤホン、スクショ、exFAT対応

こんにちはAxifofです。Raspberry Pi 4B (raspi) はにあると便利だな、設定できていると便利だなと私が感じたもののインストールの仕方を書いておきます。ファイル共有システム netatalk、イヤホンジャックの利用設定、scrot でスクショの撮影、exFAT フォーマット HDD への対応を書きました。

この記事は 2020/07/27 のものです。



[目次]

続きを読む

Raspberry Pi 4, デフォルトPython 3.7.3 + OpenCVは構成できた。しかし pyenv + OpenCV はできなかった。

こんにちはAxifofです。Raspberry Pi 4 にて Python3 OpenCV をインストールしたときに詰まった話をします。もともと pyenv を導入したのですが opencv の導入がうまく行きませんでした。当たり前かもしれませんが、管理者権限で実行したものと、管理者権限なしで実行したものの結果は異なることが多いです;pyenv global X.X.Xで設定した pythonsudo pythonの実行結果は、デフォルトでは異なります。ですから、sudo pip3 install pip3 install は全く別の結果を返します。インストールできない!と騒いでいましたが、ただ私の理解不足が原因でした。


[目次]

  • 環境等
  • pyenv の導入と python 3.8.4 のインストール
  • sudo pip3 install で OpenCV の導入に成功
  • 問題発生:インストールしたはずなのに、pyenv の python では cv2 が読み込めない
  • python 3.7.3 の環境で事足りるならそれで十分な可能性あり
続きを読む

Mac OS X shred コマンド導入とデータ削除

Axifof です。ファイル削除、HDDデータ削除の際に、修復不能(と考えられる)方法で削除するために、Mac OS X に shred コマンドを導入する話です。普段 Linux を使っていて、最近 Mac に乗り換えたのですが、shred コマンドが見当たらなかったので GNU Coreutils で導入しました。

brew install coreutils

によって、GNU Coreutils をインストールします。この中に shred コマンドが含まれています。削除したいファイル/フォルダ A, B, C に対して

sudo shred -uvz A B C

のように実行します。


コマンドとその内容は以下の表を参照ください[2]。だいたいこのぐらいのコマンドを覚えておけば良いと思います。

オプション 内容
-v コマンドの実行状況を表示します。
-u 上書き後にファイルを削除します。
-z 上書き後に0で上書きをします。
-n 乱数上書き回数の指定をします。デフォルトでは3です。

表の-n オプションの内容に関して、「デフォルトでは3です」 は、あえて入力しなくても3回は実行されるという意味です。-v オプションは付けておくことをお勧めします。ファイルサイズが大きくなったり、-n オプションで大きな値を設定したときは、画面がフリーズしたように見えて精神衛生上良くないですからね。


HDDなどからファイルを削除する場合、通常のゴミ箱に捨てて、ゴミ箱を空にするような方法では、実はほぼ全てのファイルが復元できてしまいます。ファイル復元ソフトによって、私自身、何度も救われたことがあるのですが、機密書類を削除したPCを手放すときには、復元されないか心配になります。そこで私は機密書類の処分にはこのような方法でデータを消しています。

しかし高度な磁気技術によって、特殊な技能を持つ人にしてみれば、このように悪あがきをしても内容を復元できてしまうようです[1]。ただ、一般人には不可能ですから、安心していいと思います笑。

ところが、聞くところによるとSSDほど高度な記録媒体になるとそもそも削除が難しいらしいです[1]。その場合は最初から暗号化しておけば良いとのことです。ということは SSD オンリーの Macbook を使っている私には、このコマンドはあまり意味がない...?


引用および更なる学習へ

[1] データの完全消去 - Wikipedia データを削除することに関する Wikipedia の記事です。グートマン方式(35回上書き)、国防総省方式など規格があることや、何ができるのかなどがわかります
[2] https://linuxjm.osdn.jp/html/GNU_coreutils/man1/shred.1.html Linux での shred コマンドに関する解説です。GNU Coreutils で使えるものと同じはずです。

Python3 Matplotlib で交点を表示したい:交点近似しよう

Matplotlib はかなり使えるグラフ描画 Python パッケージです。一から自分でプログラムを組んでいくことになるので、確かに自由度は高いのですが、例えば交点を表示するのにも一工夫が必要になります。今回はそんなお話です。

  • 環境
  • 手法 : 近似
続きを読む

Windows/Mac Python3(pdf2image+poppler)でpdfを画像に変換するメモ

Python3 では pdf2image なるパッケージを使うことで、pdfファイルを画像に変換することが可能です。その際には poppler というコーデックを別途でインストールする必要があるのですが、適当にインストールすると pdf2image が poppler を認識してくれません。しかも、WindowsMac で導入に若干の違いがあります。

このメモは pdf2image と poppler の導入から pdf を画像に変換するところまでを書きます。

自己責任でお願いします

  • Axifofの環境
  • セットアップ
    • 1. pdf2image のインストール
    • 2. poppler のインストール
    • 3. poppler の移動
    • 4. pdf2image に path を渡す、pdf を画像に変換する
続きを読む

Mac メモ.app "このMac内"セクションが消えたときのためのメモ

どうもAxifofです。Mac メモ.app のセクションの部分から、"このMac内"セクションが消えたときのための"メモ"です。メモの整理をしているときに、"このMac内"セクションの全データを削除すると(たまに)"このMac内"セクションごと消えてしまうようです。

# 2020/07/14 現在, MacOS Catalina ver. 10.15.5
環境設定 ==>「”このMac内”アカウントを有効にする」

で対処可能なはずです。どうやら"このMac内"という仮想的なアカウントのマウントが解除されてしまうみたいですね。

続きを読む