8
6

More than 3 years have passed since last update.

LaTeX,Pythonのtips in修論

Last updated at Posted at 2021-01-18

筆者(物性物理系M2)が修論を書くのに使った小ネタをテンプレとしてメモしておきます.

LaTeX

環境はpLaTeX,\documentclass[a4paper,10pt]{jsarticle}とします.

preamble
\usepackage[dviout]{graphicx}
\usepackage{here} %[H] オプションを使用する場合

図の挿入

\begin{figure}[ht]
 %オプション h:その場, t:ページ上端, b:ページ下端, p:専用ページを作成
 % H:その場で強制出力
 \centering
 \includegraphics[keepaspectratio, width=0.8\linewidth]{fig1.png}
  %オプション keepaspectratio:アス比を固定, width,height:サイズ指定
  % 0.8\linewidthなど紙幅との比や 8cmなど単位付き長さでの指定
 \caption{キャプション}
 \label{fig:1} %相互参照用のラベル
\end{figure}

昔はTeXで画像を扱うならepsと相場が決まっていましたが,今はPDFが一番速いです.その他の場合でもdvipdfmxでPDFに変換されるのでPNGやJPEGならそのまま使って問題ありません.
http://www.yamamo10.jp/~yamamoto/comp/latex/make_doc/insert_fig/index.php#CONTEMPORARY

\includegraphics...の行を増やせば並ぶだけ適当に並べてくれますが,こちらでちゃんとコントロールして2カラムにしたい場合等は

\begin{figure}[ht]
 \begin{tabular}{cc}
  \begin{minipage}[t]{0.45\hsize}
   \centering
   \includegraphics[keepaspectratio, width=\linewidth]{fig2.png}
   \caption{キャプション1}
   \label{fig:2}
  \end{minipage} &
  \begin{minipage}[t]{0.45\hsize}
   \centering
   \includegraphics[keepaspectratio, width=\linewidth]{fig3.png}
   \caption{キャプション2}
   \label{fig:3}
  \end{minipage}
 \end{tabular}
\end{figure}

のようにtabular環境を使います.

図に文字を回り込ませたいときはwrapfigure環境を使います.
abstructなどページ制限があるときなんかに便利.
普通のfigureと混ぜて使うと出力される順番がおかしくなったりするので注意が必要です.
オプション等の詳細は次を参照. http://www.yamamo10.jp/~yamamoto/comp/latex/make_doc/insert_fig/index.php#WRAPFIG

\begin{wrapfigure}{R}{0.5\hsize}
 \centering
 \includegraphics[keepaspectratio, width=\linewidth]{fig4.png}
 \caption{キャプション3}
 \label{fig:4}
\end{wrapfigure}

表です.罫線を全部引いたりするとダサいのでほどほどにしておきます.

\begin{table}[ht]
  \centering
  \caption{キャプション}
  \begin{tabular}{c|ccc}
    \hline
    X & A & B & C\\
    \hline \hline
    1 & a & b & c \\
    2 & s & t & u \\
    3 & p & q & r \\
    \hline
  \end{tabular}
  \label{tab:1}
\end{table}

{c|ccc}のところは項目数と左右中央寄せ(l,r,c),縦罫線の設定です.
横罫線は\hlineで引きます.

相互参照

図表や数式中に\label{<適当な文字列>}を入れておくと\ref{<その文字列>}で図表番号を出力できます.執筆中に順序を入れ替えたりしても問題ないよう,手でベタ打ちするのではなく相互参照を使いましょう.
そのラベルが図なのか表なのか数式なのかは環境から自動で判断してくれますが,ユーザー側が判別しやすいようにfigやtabなどをprefixにつけておくと良いです.
なお,1度目のタイプセットでlabelの位置やら番号やらを書き出して,それをrefで参照することになるので2回以上のタイプセットが必要になります.目次や数字が入ることでページ数が変化することもありうるので万全を期すならば3回タイプセットしておくと安全です1

図表番号を章立てにする

図表番号はjsarticleでは通し番号が付けられますが,sectionごとにリセットする場合は次のようにします.

preamble
\makeatletter
% sectionが変わるごとにfigureカウンタをリセット
\@addtoreset{figure}{section}
% 図番号の出力を「<章番号>.<図番号>」にする
\renewcommand{\thefigure}{\thesection.\arabic{figure}}
%
\@addtoreset{table}{section}
\renewcommand{\thetable}{\thesection.\arabic{table}}
\makeatother

参考: [LaTeX] 図表数式番号を通し番号にする・章ごとに分ける

参考文献の参照

参考文献管理はthebibliography環境,またはBibTeXを使うのが一般的.
thebibliography環境を使用する場合は

preamble
\usepackage{cite}
\begin{thebibliography}{99}
\bibitem{label1} hogehoge.
\bibitem{label2} fugafuga.
\end{thebibliography} 

のようにして\cite{<ラベル名>}で参照します.
\cite{label1,label2}のように2つ以上並べたり\cite[pp12--34]{label1}のようにページ数などを付記することが可能.

PDFにハイパーリンクを埋め込む

hyperref パッケージを使用すると相互参照にハイパーリンクが張られるので長いPDFを生成する場合,ワンクリックであっちこっち飛べて便利.
リンク文字列の色などの設定が可能.(デフォルトは赤とか緑なのでだいぶ見づらいと思う.)

preamble
\usepackage[dvipdfmx]{hyperref}
\usepackage{pxjahyper}
\hypersetup{
 setpagesize=false,
 bookmarksnumbered=true,
 bookmarksopen=true,
 colorlinks=true,
 linkcolor=black,
 citecolor=black,
}

参考: ハイパーリンク付きLaTeX文書

自作カウンタの参照

自分で定義したカウンタも相互参照することができます.

subscriptという名前のカウンタを作成し,呼ばれたときの挙動を定義しておきます.

preamble
\newcounter{subscript}
\setcounter{subscript}{0}
\renewcommand{\thesubscript}{\arabic{subscript}}
\newcommand{\subscript}{\refstepcounter{subscript}\thesubscript}
$$ T_{\subscript\label{sub:hoge}} = hoge $$
$$ T_{\subscript\label{sub:fuga}} = fuga $$
$$ T_{\subscript\label{sub:piyo}} = piyo $$

$T_{\ref{sub:fuga}}$ はfugaです.

image.png

SI単位

preamble
\usepackage{siunitx}

\si{kg.m/s^2}のように使用.
°は\si{\degree},℃は\si{\degreeCelsius}など

また、$\rm\LaTeX$ では \AAでÅを印字できますが,これは「上リング付きA」2で,テキスト環境で使う想定のものなので\si内で使用するとLaTeX Warning: Command \r invalid in math mode on input line XXのような警告が出ます.
\angstromを使えば警告は出なくなります.

参考:
SI単位(国際単位系) - siunitxパッケージのマクロ
command \r invalid

化学式

上付き,下付きは数式環境でしか使えないが元素記号はローマン体なのでいちいち$\mathrm{H}_2\mathrm{O}$のようにしなければいけなくてとても面倒.
パッケージを使用すると楽.

preamble
\usepackage[version=3]{mhchem}

\ce{SrTiO3}\ce{HSO4-}などのようにすると自動で上付き,下付きなどを適用してくれます(1桁に限る.SO42-等ではどこで区切るか決定できないので自分で上付き,下付きを設定する).
数式環境内でもローマン体にしてくれるし,テキスト環境でも上付き^,下付き_が効く.

$\mathrm{FeSe}_ {1-x} \mathrm{Te}_ {x}$のような変数が入った置換系などで
\ce{FeSe_{$1-x$}Te_{$x$}}のようにすると1-xのマイナスがハイフンになってしまうようなので$\ce{FeSe}_{1-x}\ce{Te}_x$のようにしたほうが良い.

参考: TeXによる化学組版 - TeX Alchemist Online

マクロ内容の確認

このマクロ,どう動作するんだっけ?と気になることがあります.
$\rm\LaTeX$マクロであれなlatex.ltxを開いて検索すれば良いのですが再定義していたりパッケージで定義されたものだったりすると探すのも面倒です.
現環境での定義内容を確認するには,\show<トークン>のようにすればログにマクロを展開した結果が出力されます.

例えば上で出てきた\AAでやってみると

> \AA=macro:
->\r A.
l.11 \show\AA

? 

のように出力されます.Aにアクセント記号\rを付けたものであるということがわかります.
マクロ以外のトークン(例えば&では>alignment tab character &.など)でも可.
またレジスタ数値などを出力する\showtheなど色々なデバッグ用コマンドも用意されています(以下略. 参考: TeX プログラムのデバッグで絶望する前に知るべきこと (1) - マクロツイーター

その他

  • 「1から5まで」のように範囲を書くときは「~」\simではなくen-dash -- を使おう(~はニアリーイコールの記号). LaTeXで論文作成のいろいろ #ダッシュとハイフンの使い分け
  • 強制改行コマンド\\はオプション引数を取ります(改行の行間を指定する).
    $\rm\LaTeX$ 標準の動作では空白や改行を挟んでも[……]があればオプション引数と解釈されるため不用意に[1]とか[p, H] とかを強制改行直後に書くとエラーで停止する可能性があります.(なお、AMSMath系の環境(alignなど)ではこうならないように実装されています.)LaTeX における行区切りの \ とオプション引数

bibliographyを端折る

BibTeXを使わずに3参考文献を書く時は

\begin{thebibliography}{99}
\bibitem{Josephson} B. D. Josephson, Phys. Lett. 1, 251-253 (1962).
\end{thebibliography}

のようにすればよいのですが,このままだと特に書式のないテキストで
[1] B. D. Josephson, Phys. Lett. 1, 251-253 (1962).
のように書き出されます.

私の分野の書式にあわせようとすると
[1] B. D. Josephson, Phys. Lett. 1, 251-253 (1962).
のように雑誌名をイタリック,巻数をボールドにしたいのですが,いちいちB. D. Josephson, \textit{Phys. Lett.} \textbf{1}, 251-253 (1962).と毎度書くのはもちろん,
\newcommand{\paper}[4]{#1 \textit{#2} \textbf{#3} #4}とマクロを定義して\paper{B. D. Josephson,}{Phys. Lett.,}{1,}{251-253 (1962).}とするのもカッコを書くのが面倒4だったので\defを使ってもう少し入力数を減らしてみました.

$\rm\LaTeX$では基本的に\newcommandを使うべきなのですが,\defを使うと便利な場面もあります.
\def特有の機能のうちにパターンマッチングが使えるというものがあり,

\def\paper#1;#2;#3;#4.{#1\textit{#2}\textbf{#3}#4.}

\paper B. D. Josephson,;Phys. Lett.,;1,;251-253 (1962).

のようにすると B. D. Josephson,Phys. Lett.,1,251-253 (1962)がそれぞれ#1,#2,#3,#4 に格納され展開されます.便利ですね.

横着するためだけに($\rm\LaTeX$ではなく)$\rm\TeX$を書かないといけないのであまり真似しないほうが良いと思いますが.

Python

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

あたりは前置きなく使用します.

グラフ

目標はこんな感じのグラフです.

image.png
[出典 : E. Snider, et al. "Room-temperature superconductivity in a carbonaceous sulfur hydride." Nature 586, 373–377 (2020).]

目盛り設定

デフォルトの設定だと目盛りが外向き・補助目盛り無しなので表示させます.

plt.rcParams['font.family'] ='sans-serif' #フォント選択
plt.rcParams['font.size'] = 12 #フォントの大きさ
plt.rcParams["xtick.minor.visible"] = True #補助目盛りの追加
plt.rcParams["ytick.minor.visible"] = True
plt.gca().xaxis.set_tick_params(which='both', direction='in',bottom=True, top=True)
plt.gca().yaxis.set_tick_params(which='both', direction='in',left=True, right=True)

image.png image.png

その他の設定項目.備忘録 Matplotlibのグラフの見た目の調整

マーカーを白抜きにする

markerfacecolor"None"にするとマーカーが枠線だけになる."white"だと後ろが透過しない.
markeredgecolorを設定すれば線と別の色で描画もできる.
散布図plt.scatterの場合はそれぞれ引数名がedgecolorsfacecolorになる.

plt.plot([0, 1, 2], [1, 0, 1], marker="o", markersize=10)
plt.plot([0, 1, 2], [0, 1, 2], marker="s", markerfacecolor="None", markersize=10)
plt.plot([0, 1, 2], [2, 1, 0], marker="^", markeredgecolor="C3", markerfacecolor="white", markersize=10)
plt.scatter([0, 1, 2], [0, 2, 1], marker="v", edgecolors="C4", facecolor='None', s=100)

matplotlib グラフ作成Tips (3) 白抜き記号と矢印

凡例をグラフ外部に表示する

plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left", ncol=2)

matplotlibの凡例(legend)レイアウト関連メモ

image.png

重ねてプロット

第2軸と重ねて書く場合.
プロット色に合わせて軸の色も変えようとすると結構面倒です.

fig = plt.figure()
ax1 = fig.subplots()

plt.rcParams['font.family'] ='sans-serif'
plt.rcParams['font.size'] = 10
plt.rcParams["xtick.minor.visible"] = True
plt.rcParams["ytick.minor.visible"] = True
ax1.xaxis.set_tick_params(which='both', direction='in',bottom=True, top=True)
# 1軸 目盛色の変更
ax1.yaxis.set_tick_params(which='both', direction='in',left=True, color="C0")
# 目盛ラベル色の変更
ax1.tick_params(axis="y", colors="C0")

ax2 = ax1.twinx()
# 2軸 目盛色の変更
ax2.tick_params(axis="y", which='both', direction='in', right=True, color="C1")
# 目盛ラベル色の変更
ax2.tick_params(axis='y', colors="C1")

# 枠線色の変更
ax2.spines['left'].set_color("C0") # ax2のほうが"上"にあるのでax2を変える
ax2.spines['right'].set_color("C1")

ax1.plot([0, 1, 2], [1, 0, 1], marker="o", markersize=10, color="C0")
ax2.plot([0, 1, 2], [0, 1, 2], marker="s", markerfacecolor="None", markersize=10, color="C1")

plt.show()

image.png

[Python]matplotlibで左右に2つの軸があるグラフを書く方法

時系列データを複数縦に並べてプロットしたい,しかもそのうち2つは2軸で重ねて描画したいなんていうときはこんな感じ.

fig = plt.figure(figsize=(8, 6))

plt.rcParams['font.family'] ='sans-serif' #フォント選択
plt.rcParams['font.size'] = 10 #フォントの大きさ
plt.rcParams["xtick.minor.visible"] = True #補助目盛りの追加
plt.rcParams["ytick.minor.visible"] = True
#plt.gca().xaxis.set_tick_params(which='both', direction='in',bottom=True, top=True)
#plt.gca().yaxis.set_tick_params(which='both', direction='in',left=True, right=True)

# 画面を4x1に分割
ax1 = plt.subplot2grid((4,1), (0,0)) # (0,0) の画面に描画
ax2 = plt.subplot2grid((4,1), (1,0)) # (1,0) の画面に描画
ax3 = plt.subplot2grid((4,1), (2,0), rowspan=2)  # (2,0) から2つ縦にぶち抜いた画面に描画
ax4 = ax3.twinx() # ax3に重ねて描画

ax1.xaxis.set_tick_params(which='both', direction='in', bottom=True, top=True, labelbottom=False)
ax1.yaxis.set_tick_params(which='both', direction='in', left=True, right=True)

ax2.xaxis.set_tick_params(which='both', direction='in', bottom=True, top=True, labelbottom=False)
ax2.yaxis.set_tick_params(which='both', direction='in', left=True, right=True)

ax3.xaxis.set_tick_params(which='both', direction='in', bottom=True, top=True)
ax3.yaxis.set_tick_params(which='both', direction='in', color="C2")
ax4.spines['left'].set_color("C2")

ax4.yaxis.set_tick_params(which='both', direction='in', color="C3")
ax4.tick_params(axis='y', colors="C3")
ax4.spines['right'].set_color("C3")


ax1.plot([0, 1, 2], [1, 0, 1], marker="o", color="C0", markersize=10, label="A")
ax1.set_ylabel("A")

ax2.plot([0, 1, 2], [0, 1, 2], marker="s", color="C1", markerfacecolor="None", markersize=10, label="B")
ax2.set_ylabel("B")

ax3.plot([0, 1, 2], [2, 1, 0], marker="^", color="C2", markerfacecolor="white", markersize=10, label="C")
ax3.tick_params(axis='y', colors="C2")
ax3.set_xlabel("x")
ax3.set_ylabel("C", color="C2")

ax4.scatter([0, 1, 2], [0, 2, 1], marker="v", edgecolors="C3", facecolor='None', s=100, label="D")
ax4.set_ylabel("D", color="C3")
ax4.set_ylim(-1,3)

plt.xlim(-0.2, 2.2)
ax1.set_xlim(*plt.xlim()) #ax1,ax2のx軸をあわせる
ax2.set_xlim(*plt.xlim())

plt.show()

image.png

2軸にするのをx軸にしたい場合はtwinx()twiny()にします.

平滑化

ノイズを移動平均で平滑化する場合はnp.convolveが使える.

def gauss(x, a=1, mu=0, sigma=1):
    return a * np.exp(-(x - mu)**2 / (2*sigma**2))

x = np.array(sorted([np.random.rand()*6-3 for _ in range(500)]))
y = np.array([gauss(i)+np.random.randn()*0.05for i in x])

width = 7

plt.plot(x,y)
plt.plot(x, np.convolve(y, np.ones(width)/width, mode='same'), color="red")

image.png

時系列データの場合,未来のデータを見るわけにはいかないのでずらします.

plt.plot(x,y)
plt.plot(x[width-1:], np.convolve(y, np.ones(width)/width, mode='valid'), color="red")

image.png

このパターンはPandasのrolling関数でも書けます.

plt.plot(x, y)
plt.plot(x, pd.Series(y).rolling(11).mean(), color="red")

Pandasだと同様に指数平滑移動平均もできる.

plt.plot(x, y)
plt.plot(x, pd.Series(y).ewm(span=width).mean(), color="red")

波形データならFFTするとか他にも色々ありますね.時系列及び波形データの平滑化3手法(smoothing)

曲線フィット

最小二乗法で曲線のパラメーターフィットを行います.

from scipy.optimize import curve_fit
def gauss(x, a=1, mu=0, sigma=1):
    return a * np.exp(-(x - mu)**2 / (2*sigma**2))

x = np.array(sorted([np.random.rand()*6-3 for _ in range(500)]))
y = np.array([gauss(i, 1, 0, 1)+np.random.randn()*0.05for i in x])

popt, pcov = curve_fit(gauss, x, y)

curve_fit関数に「第1引数にx,残りがパラメーターである関数」,x,y を与えると最適パラメーターと共分散行列が返されます.

共分散行列の対角成分はそれぞれのパラメーターの分散なので平方根を取れば標準偏差が得られます.

plt.plot(x,y)
plt.plot(np.linspace(-3,3,1000), gauss(np.linspace(-3,3,1000), *popt))
plt.show()

perr = np.sqrt(np.diag(pcov))
for i in range(3):
    print(f"{popt[i]:.3f}±{perr[i]:.3f}")
# 1.012±0.005
# 0.004±0.006
# 0.996±0.006

image.png

パラメーターの初期値や範囲を与えてやればそれなりに複雑な関数もフィットできます.

def two_gauss(x, a1, m1, s1, a2, m2, s2, e):
    return gauss(x, a1, m1, s1) + gauss(x, a2, m2, s2) + e
y2 = np.array([two_gauss(i, 1.5, -1, 0.5, 1.2, 0.5, 0.8, 0.1) + np.random.rand()*0.1 for i in x])

p,q = curve_fit(two_gauss, x, y2, [2, -1.5, 0.5, 1.5, 1, 1, 0],
                bounds=((0, -np.inf, 0, 0, -np.inf, 0, 0), (np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf)) )
plt.plot(x,y2)
plt.plot(x, two_gauss(x, *p))
plt.plot(x, gauss(x, p[0], p[1], p[2])+p[6])
plt.plot(x, gauss(x, p[3], p[4], p[5])+p[6])

image.png

曲線で補間する

適切な関数で表せればそれで良いですが,それができず適当な曲線でつなぎたいだけという場合はスプラインでつないでしまいます.

from scipy.interpolate import make_interp_spline, BSpline
x = [0,1,2,3,4,5]
y = [0,3,5,6,6,5]

smooth = make_interp_spline(x, y)
plt.scatter(x, y)
plt.plot(np.linspace(0,5,100), smooth(np.linspace(0,5,100)), color="black", linewidth=0.5)

make_interp_spline(x, y)でx,yを制御点とするB-スプライン曲線を表す関数ができるので適当なxの値でプロットすれば曲線が引けます.

image.png

他の曲線による補間もいろいろあります. Scipy.interpolate を使った様々な補間法

DataFrameの操作

温度を変えながら抵抗を測ってR-Tプロットするというとき,降温時は速度を固定していないので邪魔です.
そんなときに昇温期間だけにトリムするコード.

df = pd.read_csv("data.csv")
df = df.iloc[1:, :] #2行目の単位の行があるとfloatにできないので削除
df = df.astype('float64')

cond = df.index>=df["Temperature"].idxmin()
plt.plot(df[cond]["Temperature"], df[cond]["Resistance"])

トリム条件は&|で繋げられる.(真偽値のarrayの演算なのでbool演算ではなくビット演算)

# 変分はdiffで取れる
cond = (df.index>=df["Temperature"].idxmin()) & (df["Temperature"].diff() > 0.02)

cond = (df.index>=df["Temperature"].idxmin()) | ((df["Time"] > 100) & (df["Time"]<2000))

水平部分の抽出

水平部分のyの値を取ってきたい.

width = 0.01
z = plt.hist(y, bins=np.arange(0, 40, width)-width/2)
plt.ylim(0,50)

threshold=300
print((z[1][:-1]+width/2)[z[0]>threshold])
# [ 2.5  5.  10.  15.  20.  25.  30.  33.  35.  35.5 36.  36.5 37.  37.5]

widththresholdを適当に変えるといい感じになる.

image.png


  1. https://texwiki.texjp.org/?LaTeX%E5%85%A5%E9%96%80%2F%E7%9B%B8%E4%BA%92%E5%8F%82%E7%85%A7%E3%81%A8%E3%83%AA%E3%83%B3%E3%82%AF#h84e81eb 

  2. ノルウェー語などで使用される記号.ドイツ語なんかで言うウムラウト付き文字のようなもの.もっと雑に言えば日本語でいう半濁音みたいな? 

  3. 過去のパワポなどから持ってくるものが多いのでB. D. Josephson, Phys. Lett. 1, 251-253 (1962).というような文字列を持ってくるのが一番楽だったんですよね. 

  4. ブレースってShiftが必要だしキーボードの端にあるしで入力しづらくて好きではないんですよね. 

8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6