忍者ブログ
物理学者(ポスドク)による日々の研究生活のメモ書きです ( python/emacs/html/Japascript/シェルスクリプト/TeX/Mac/C言語/Linux/git/tmux/R/ポケモンGO)
はじめて画像解析をpythonのopen cvを使ってやることになったのでそのメモ


■ パッケージのインストール
conda install opencv
■ 初学者向けの使えそうなリンクメモ

■ 参考 : 【OpenCV/Python】OpenCVで細胞の画像解析をやってみた

■ 参考 : Python, OpenCVで画像ファイルの読み込み、保存(imread, imwrite)

■ 参考 : Python, OpenCV, NumPyで画像を二値化(しきい値処理)

しきい値のいろいろなオプション↓

■ 参考 : 画像のしきい値処理



■ ピクセルの取得

読み込んだ画像は2次元のピクセルへの通し番号とそのピクセルでの色の値が書かれている
ここでは、gray scaleにしてから解析するので、RGBの色情報を0~255に変換してから使う

読み込んだ画像の幅や高さは以下から

参考までに2822x4144の画像で10~22MBだった

■ 参考 : Python, OpenCV, Pillow(PIL)で画像サイズ(幅、高さ)を取得

画像のピクセルは(0, 0)から(height, width)まであるとすると、
(0, 0)の点は画像の左上
左下が(height, 0)
右下が(height, width)
右上が(0, width)
なことに注意

最後にプロットするときは少し反転などを加えないといけない
matplotlibのオプションで、xlimとylimを入れ替えれば良さそう


(2022/09/21 追記)

pngやtiffファイルをカラーで読み込んだ場合は、返り値は3つ
白黒として読み込んだら、返り値は2つ
height, width, _ = img.shape



■ 円を書きたいなら
cv2.circle(img, (190, 35), 15, (255, 255, 255), thickness=-1)
最後のticknessは-1なら塗りつぶし、0より大きい数字ならその太さの線になる
(190, 35) が円の中心
15が円の半径
単位はピクセル

長方形とかの場合は以下から

■ 参考 : Python, OpenCVで図形描画(線、長方形、円、矢印、文字など)




■ 円形のドーナツ型のフィルターを作って黒く塗りつぶしたい

良い例があった

■ 参考 :リング型のマスク画像を作る方法



■ 輪郭を取得する

■ 参考 :Python: OpenCVで画像から輪郭を検出する


■ 参考 :Python, OpenCVで輪郭検出をしてみる


■ 画像に文字を追加する

■ 参考 :画像処理 「OpenCV 4」で文字を描画してみる


■ opencvの色について

open cv上では色は
(255, 255, 255)が白
(0, 0, 0)が黒
(255, 0, 255)がマゼンタ
(255 , 0, 0)が青

cv2で画像を読み込むと色はBGRになっている(普通はRGB)
matplotlibではRGBなので注意が必要
それを踏まえて、matplotlibで表示するときは以下のような換算が必要
img_orig = cv2.cvtColor(img_orig, cv2.COLOR_BGR2RGB)

■ 参考 :Python, OpenCVでBGRとRGBを変換するcvtColor

















PR
(2022/06/06 追記)

やっと必要になって、使ったので追記します
めちゃくちゃ大変でした・・・





まずはcsvから日付の部分を読み込む
日付データは 2022/03/28 というフォーマットになっている
これをdatetime型で読み込めば良さそうだけど、他の部分が実数で読み込まないといけないのでこういう実装にしてる

データを読み込んで文字列にする

/ を - に置換

datetime型として読み込む
本当はこのあとnumpyに戻したかったけど、そうするとdatetime型じゃなくなるので
しょうがないので、リストで扱うことに(ここでハマった。)
fname="hoge.csv"
if os.path.exists(fname):
a = np.loadtxt(fname, unpack=True, dtype="unicode", delimiter=',', skiprows=1)

mmdd=[]
data["date"] = a[1].astype(str)
tmp = np.char.replace(data["date"], "/", "-")
for (i, x) in enumerate(tmp):
mmdd.append(datetime.strptime(x, '%Y-%m-%d'))
# 時間要素があればここを書き換えれば良いと思う・・・

data["T"] = a[2].astype(np.float64)
これさえできればあとは
plt.plot(mmdd, data1)
みたいな感じでプロットすれば良いと思う



1週間ごとに点をx軸に打ちたいときは
plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=7))
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%m-%d"))



datetime64
という型もあるらしくて、そっちで読み込もうとしてみたが、読み込んだあとの取り回しがまったくわからずに諦めた・・・




(ここから元のメモ)
from matplotlib.dates import DateFormatter

set_major_locator(mdates.DayLocator(bymonthday=(range(5, 28, 7))))
set_major_formatter(mdates.DateFormatter("%Y-%m-%d"))


set_major_formatter(DateFormatter('%m/%d\n%H:%M'))
とりあえずこのまま動かんけど、メモだけしとく

bymonthday=(range(5, 28, 7)
は、5~28を1週間ずつメモリを打つ

bymonthday=(range(7)
だと1, 8, 15, 22, 29とかになると思う





(2022/03/12 追記)

関係ありそうな記事を一応メモしておく

■ 参考 : matplotlib.datesで時系列データのグラフの軸目盛の設定をする

■ 参考 : matplotlibでx軸の時刻情報をフォーマットする

■ 参考 : matplotlib.dates










(2023/6/15 追記)

x軸の日付を範囲指定してプロットする範囲を制限したい時
from datetime import datetime

xmin='2022-03-28'
xmax='2022-06-01'
xmin = datetime.strptime(xmin, '%Y-%m-%d')
xmax = datetime.strptime(xmax, '%Y-%m-%d')
plt.xlim([xmin,xmax])









■ 参考 : matplotlib エラーバー付きのグラフを描く

errorbarという関数を使う
xとyにデータを入れて、yerrに縦軸方向のエラーの値を入れる
y_minが下側のエラー、y_maxが上側のエラー
from matplotlib import pyplot as plt
plt.figure(figsize=(10,7))
plt.errorbar(x, y, yerr = [y_min, y_max], capsize=5, fmt='o', markersize=10, ecolor='black', markeredgecolor = "black", color='w')





(2022/03/12 追記)

関係ありそうな記事を追記

■ 参考 :matplotlibで信頼区間(エラーバー)を描画

■ 参考 : Matplotlibで日付データをplot(グラフ)表示




■ 参考 : How to convert an array of strings to an array of floats in numpy?
import numpy as np

fname="hoge.txt"
a = np.loadtxt(fname, unpack=True, dtype=str)

y = a["x"].astype(np.float)
hoge.txtというテキストファイルを読み込む
このときdtypeで指定できる型は1種類のみ、何もしないとfloat64になるはず
これを文字列にすると、aの中身はすべて文字列のarrayになる

aの中のxという要素は実は文字列じゃなくて、数字なのでそれをastypeでfloatに変換して取り出せる






csvデータの読み込みに、import csvとかやっていたが使いにくい・・・
csvの1行目を辞書型のkeyにして、縦方向に読み込むものだと、思っていたら
csvというパッケージではすべて横方向に読み込んでしまうらしい

あれこれやり方を調べていたら、numpyのloadtxtはcsv読み込みにも使えるらしい
import numpy as np

fname="hoge.csv"
a = np.loadtxt(fname, unpack=True, dtype=str, dtype="unicode", delimiter=',', skiprows=1)

これだと、1行目は無視することになってる
たいがいcsvの1行目は、列の説明だと思うので(dateとかtemperatureとか)

本当はそれを辞書型のkeyにして読み込みたかったけどやり方がわからない










とりあえず補間ならなんでもいいけど、スプライン補間とかではなくてできるだけシンプルなのでOK

なので線形補間

■ 参考 : Scipy.interpolate を使った様々な補間法


コード例
from scipy import interpolate # to interpolate

x_out = np.linspace(min(x_in), max(x_in), n_samples)
fit_curve = interpolate.interp1d(x_in, y_in)
y_out = fit_curve(x_out)

x_inとy_inというデータがあるとする
それをx_inの最小値から最大値までn_samplesで等間隔に分けた点で補完する

fit_curveが補間の関数
これにx_outを食わせれば、そのx_outでのyの値がわかる

補間前のデータとの重ね合わせプロットなどは↑の記事を参照











ざっくり調べた感じ2つ方法がある

1つは japanize-matplotlib を使う方法

三重大学の奥村さんが記事にしてる

■ 参考 : プロット

ただし、このパッケージはpipでしかインストールできない
conda-forgeで探したけどない

なのでパス




もう1つは日本語fontを指定する方法

labelに日本語を使いたいときは、

■ 参考 : matplotlib.pyplotの日本語化


この記事のコマンドをpython上で走らせると、matplotlibで使える日本語フォントが表示される
自分のMacで実行してみた結果は以下
from matplotlib import font_manager
for i in font_manager.fontManager.ttflist:
 if ".ttc" in i.fname:
   print(i)
<Font 'PT Serif Caption' (PTSerifCaption.ttc) normal normal 400 normal>
<Font 'Chalkboard' (Chalkboard.ttc) normal normal 400 normal>
<Font 'Avenir' (Avenir.ttc) normal normal book normal>
<Font 'Marker Felt' (MarkerFelt.ttc) normal normal 400 normal>
<Font 'Iowan Old Style' (Iowan Old Style.ttc) normal normal roman normal>
<Font 'Gurmukhi MN' (Gurmukhi MN.ttc) normal normal 400 normal>
<Font 'Palatino' (Palatino.ttc) normal normal 400 normal>
<Font 'Malayalam Sangam MN' (Malayalam Sangam MN.ttc) normal normal 400 normal>
<Font 'Hiragino Sans' (ヒラギノ角ゴシック W8.ttc) normal normal 700 normal>
<Font 'American Typewriter' (AmericanTypewriter.ttc) normal normal 400 normal>
<Font 'Sinhala Sangam MN' (Sinhala Sangam MN.ttc) normal normal 400 normal>
<Font 'Bangla Sangam MN' (Bangla Sangam MN.ttc) normal normal 400 normal>
<Font 'Kefa' (Kefa.ttc) normal normal regular normal>
<Font 'Hoefler Text' (Hoefler Text.ttc) normal normal 400 normal>
<Font 'Menlo' (Menlo.ttc) normal normal regular normal>
<Font 'Didot' (Didot.ttc) normal normal 400 normal>
<Font 'KufiStandardGK' (KufiStandardGK.ttc) normal normal regular normal>
<Font 'PT Serif' (PTSerif.ttc) normal normal 400 normal>
<Font 'Cochin' (Cochin.ttc) normal normal 400 normal>
<Font 'Myanmar MN' (Myanmar MN.ttc) normal normal 400 normal>
<Font 'Hiragino Sans' (ヒラギノ角ゴシック W2.ttc) normal normal 400 normal>
<Font 'Bodoni 72 Oldstyle' (Bodoni 72 OS.ttc) normal normal book normal>
<Font 'Raanana' (Raanana.ttc) normal normal 400 normal>
<Font 'Kohinoor Telugu' (KohinoorTelugu.ttc) normal normal 400 normal>
<Font 'Sana' (Sana.ttc) normal normal regular normal>
<Font 'Hiragino Sans' (ヒラギノ角ゴシック W0.ttc) normal normal 400 normal>
<Font 'Kannada Sangam MN' (Kannada Sangam MN.ttc) normal normal 400 normal>
<Font 'Athelas' (Athelas.ttc) normal normal regular normal>
<Font 'SignPainter' (SignPainter.ttc) normal normal 400 normal>
<Font 'Helvetica Neue' (HelveticaNeue.ttc) normal normal 400 normal>
<Font 'Shree Devanagari 714' (Shree714.ttc) normal normal 400 normal>
<Font 'Times' (Times.ttc) normal normal roman normal>
<Font '.Helvetica Neue DeskInterface' (HelveticaNeueDeskInterface.ttc) normal normal regular normal>
<Font 'Muna' (Muna.ttc) normal normal regular normal>
<Font 'Thonburi' (Thonburi.ttc) normal normal 400 normal>
<Font 'Mshtakan' (Mshtakan.ttc) normal normal 400 normal>
<Font 'Devanagari Sangam MN' (Devanagari Sangam MN.ttc) normal normal 400 normal>
<Font 'InaiMathi' (InaiMathi-MN.ttc) normal normal 400 normal>
<Font 'New Peninim MT' (NewPeninimMT.ttc) normal normal 400 normal>
<Font 'Noteworthy' (Noteworthy.ttc) normal normal light normal>
<Font 'Oriya MN' (Oriya MN.ttc) normal normal 400 normal>
<Font 'Geeza Pro' (GeezaPro.ttc) normal normal regular normal>
<Font 'Savoye LET' (Savoye LET.ttc) normal normal 400 normal>
<Font 'Hiragino Sans' (ヒラギノ角ゴシック W3.ttc) normal normal 400 normal>
<Font 'Superclarendon' (SuperClarendon.ttc) normal normal regular normal>
<Font 'Tamil Sangam MN' (Tamil Sangam MN.ttc) normal normal 400 normal>
<Font 'Khmer MN' (Khmer MN.ttc) normal normal 400 normal>
<Font 'Helvetica' (Helvetica.ttc) normal normal 400 normal>
<Font 'Hiragino Sans GB' (Hiragino Sans GB.ttc) normal normal 400 normal>
<Font 'Bodoni 72' (Bodoni 72.ttc) normal normal book normal>
<Font 'Waseem' (Waseem.ttc) normal normal regular normal>
<Font 'Bangla MN' (Bangla MN.ttc) normal normal 400 normal>
<Font 'PT Sans' (PTSans.ttc) normal normal 400 normal>
<Font 'Hiragino Sans' (ヒラギノ角ゴシック W7.ttc) normal normal 700 normal>
<Font 'Hiragino Maru Gothic Pro' (ヒラギノ丸ゴ ProN W4.ttc) normal normal 400 normal>
<Font 'Chalkboard SE' (ChalkboardSE.ttc) normal normal light normal>
<Font '.Arabic UI Text' (ArabicUIText.ttc) normal normal regular normal>
<Font 'Kannada MN' (Kannada MN.ttc) normal normal 400 normal>
<Font 'Lucida Grande' (LucidaGrande.ttc) normal normal 400 normal>
<Font 'Copperplate' (Copperplate.ttc) normal normal 400 normal>
<Font 'Papyrus' (Papyrus.ttc) normal normal 400 condensed>
<Font 'Al Nile' (Al Nile.ttc) normal normal 400 normal>
<Font 'Lao MN' (Lao MN.ttc) normal normal 400 normal>
<Font 'Baskerville' (Baskerville.ttc) normal normal 400 normal>
<Font 'Sukhumvit Set' (SukhumvitSet.ttc) normal normal 400 normal>
<Font 'Hiragino Sans' (ヒラギノ角ゴシック W4.ttc) normal normal 400 normal>
<Font 'Nadeem' (Nadeem.ttc) normal normal regular normal>
<Font 'Arial Hebrew' (ArialHB.ttc) normal normal 400 normal>
<Font 'Hiragino Sans' (ヒラギノ角ゴシック W1.ttc) normal normal 400 normal>
<Font '.Aqua Kana' (AquaKana.ttc) normal normal 400 normal>
<Font 'Noto Nastaliq Urdu' (NotoNastaliq.ttc) normal normal 400 normal>
<Font 'Hiragino Sans' (ヒラギノ角ゴシック W5.ttc) normal normal 700 normal>
<Font 'Gurmukhi Sangam MN' (Gurmukhi Sangam MN.ttc) normal normal 400 normal>
<Font 'Gujarati MT' (GujaratiMT.ttc) normal normal 400 normal>
<Font 'Kohinoor Devanagari' (Kohinoor.ttc) normal normal regular normal>
<Font 'Gujarati Sangam MN' (Gujarati Sangam MN.ttc) normal normal 400 normal>
<Font 'Hiragino Sans' (ヒラギノ角ゴシック W9.ttc) normal normal 700 normal>
<Font 'Corsiva Hebrew' (Corsiva.ttc) normal normal 400 normal>
<Font 'PT Mono' (PTMono.ttc) normal normal bold normal>
<Font 'Marion' (Marion.ttc) normal normal regular normal>
<Font 'Snell Roundhand' (SnellRoundhand.ttc) normal normal 400 normal>
<Font 'Heiti TC' (STHeiti Light.ttc) normal normal light normal>
<Font 'Hiragino Mincho ProN' (ヒラギノ明朝 ProN.ttc) normal normal 400 normal>
<Font 'Beirut' (Beirut.ttc) normal normal regular normal>
<Font 'Devanagari MT' (DevanagariMT.ttc) normal normal 400 normal>
<Font 'Kohinoor Bangla' (KohinoorBangla.ttc) normal normal 400 normal>
<Font 'Heiti TC' (STHeiti Medium.ttc) normal normal medium normal>
<Font 'Futura' (Futura.ttc) normal normal medium normal>
<Font 'Phosphate' (Phosphate.ttc) normal normal 400 normal>
<Font 'Oriya Sangam MN' (Oriya Sangam MN.ttc) normal normal 400 normal>
<Font 'Seravek' (Seravek.ttc) normal normal 400 normal>
<Font 'Charter' (Charter.ttc) normal normal roman normal>
<Font 'Telugu MN' (Telugu MN.ttc) normal normal 400 normal>
<Font 'Diwan Kufi' (Diwan Kufi.ttc) normal normal regular normal>
<Font 'Songti SC' (Songti.ttc) normal normal black normal>
<Font 'Kailasa' (Kailasa.ttc) normal normal regular normal>
<Font 'Avenir Next Condensed' (Avenir Next Condensed.ttc) normal normal bold condensed>
<Font 'Malayalam MN' (Malayalam MN.ttc) normal normal 400 normal>
<Font 'Damascus' (Damascus.ttc) normal normal regular normal>
<Font 'PingFang HK' (PingFang.ttc) normal normal regular normal>
<Font 'Avenir Next' (Avenir Next.ttc) normal normal bold normal>
<Font 'Euphemia UCAS' (EuphemiaCAS.ttc) normal normal 400 normal>
<Font 'Myanmar Sangam MN' (Myanmar Sangam MN.ttc) normal normal 400 normal>
<Font 'Hiragino Sans' (ヒラギノ角ゴシック W6.ttc) normal normal 700 normal>
<Font 'Sinhala MN' (Sinhala MN.ttc) normal normal 400 normal>
<Font 'ITF Devanagari' (ITFDevanagari.ttc) normal normal book normal>
<Font 'Al Bayan' (AlBayan.ttc) normal normal 400 normal>
<Font '.Arabic UI Display' (ArabicUIDisplay.ttc) normal normal black normal>
<Font 'DecoType Naskh' (DecoTypeNaskh.ttc) normal normal regular normal>
<Font 'Gill Sans' (GillSans.ttc) normal normal 400 normal>
<Font 'Telugu Sangam MN' (Telugu Sangam MN.ttc) normal normal 400 normal>
<Font 'Optima' (Optima.ttc) normal normal regular normal>
<Font 'Tamil MN' (Tamil MN.ttc) normal normal 400 normal>
<Font 'Apple SD Gothic Neo' (AppleSDGothicNeo.ttc) normal normal regular normal>
<Font 'Farah' (Farah.ttc) normal normal regular normal>
<Font 'Baghdad' (Baghdad.ttc) normal normal regular normal>
<Font 'Al Tarikh' (Al Tarikh.ttc) normal normal regular normal>
いっぱい表示されるけど、日本語っぽいのはヒラギノくらいだった
色々と試したけど、Herveticaとヒラギノくらいしか成功しなかった・・・・


これをコードの上の方に書いておけばOK
import matplotlib as mpl
mpl.rc('font', family='Hiragino Sans')
(mpl.rcParams['font.family] のように書いてもいけるらしい)

(自分はなぜかこれを書かなくても日本語が表示されるようになってしまってよくわからないことになった・・・)

または
pylab.ylabel(r"あああああああ",fontsize=30, fontname='Hiragino Sans')
と必要なところだけ書いても良い







labelじゃなくてlegendの場合は、
pylab.legend(loc='upper right', prop={"family" :'Hiragino Sans'})
のように指定する、少し特殊





(2022/03/11 追記)

師匠からコメントをもらったので追記
最近は別のサーバーでjupyter noterbookを立ち上げて使うことがほとんどだから自分にはあまり関係がないけど、Macユーザーの場合は1度書いておけば楽ですね
自分の環境にも ~/.matplotlib というディレクトリはあることは確認
# matplotlibの日本語
macは ~/.matplotlib/matplotlibrc に書いときゃOK

cd ~/.matplotlib
echo "font.family : Hiragino sans" >> matplotlibrc






ndarrayに文字列のリストが詰まっている
その文字列の中にあるキーフレーズが含まれているかどうかを検索して、そのindexを取得して、
その文字列を取り出し、必要な部分のみ切り出したい

最初は1度リストに変換してから、inを使って判定してたけど
ndarrayの検索機能を使ったほうが早いのでは?と思い直した

ndarrayの検索機能といえば、np.whereだな・・・と思ったけど、inは使えないっぽい
==とか大小関係なら使えるが、今回は文字列のndarrayだからだめなのかな?(なんかこういうことは前にもあったような・・・)






■ 参考 : numpy.char.find

numpy.char.findを使えば良さそう

aが文字列のndarray
a_keyが検索するキーワードとして、
b = a[np.char.find(a, a_key) != -1]

これで、bにa_keyが入っているリストができる
あとは思いのままに処理してください。
a_keyが入っている最初の要素がほしいならb[0]で良い

!= -1としているのは、a_keyが入っていない要素には、-1が返ってくるから(a_keyが入ってると0だったと思う)








jqをインストールすれば楽だけど、共有マシンの場合はかんたんにインストールできない

一応、conda環境にインストールするという手もあるが・・・・




ワンライナーで
cat hoge.json | python -m json.tool
jsonファイルに改行やスペースが追加されてて見やすい


とりあえずaliasに登録しといた
alias jq='python -m json.tool'





ただ、jqはjqで便利そうなんだよなぁ・・・
個別の要素を表示したり、要素数を取り出したり・・・

けど、そこまでやるならpythonでやったほうが楽じゃない? という説はある
あと、↑のワンライナーにawkの合せ技で同じことをできるやろうし

■ 参考 : jqコマンド(jsonデータの加工, 整形)の使い方









datetime型の変数 d があるとして、そこから、日時だけを取り出したいとき
返り値は文字列なので注意
base_dir = "/home/hogehoge/public_html/hoge/%s/" % (d.strftime("%Y%m%d"))

■ 関係してそうな記事

■ 参考 : Pythonのdatetimeで日付や時間と文字列を変換(strftime, strptime)


datetimeで取り回す時間は基本的にUTCだけど、それを日本時間に直したいときは↓を参照

■ 過去記事 : 【python3, datetime】現在の日付を取得する + UTCから日本時間(JST)に変換したい














■ X軸の桁数を2桁にしたいとき
plt.gca().xaxis.set_major_formatter(plt.FormatStrFormatter('%.2f'))

■ Y軸の桁数を2桁にしたいとき
plt.gca().yaxis.set_major_formatter(plt.FormatStrFormatter('%.2f'))


■ 参考 : [Python] matplotlib: 論文用に図の体裁を整える


他にも軸にオフセットを付けたりもできるらしい
が、自動的にオフセットの桁数を指定できないという情報を見かけた (ほんとに?)
とりあえず使ったらまた追記






IIRフィルターについてはscipyのドキュメントが詳しいのでそちらを一読がおすすめ

■ 参考 : Signal Processing with SciPy: Linear Filters(Warren Weckesser)

IIRフィルターには3つの表し方の形式がある
・伝達関数
・zero, pole, gain(ZPK方式)
・second order sections (SOS形式)

最近までSOS形式のことをSOSフィルターだと思ってたけど、これはフィルターではないっぽい




使うのはscipyのsosfreqs
これで、SOS形式の周波数応答が書ける

■ 参考 : scipy.signal.sosfreqz

from scipy.signal import butter, sosfreqz
import numpy as np
import matplotlib.pyplot as plt

fs=16384
fs_nyq = fs*0.5
low = 100 / fs_nyq
high = 500 /fs_nyq

sos = butter(20, [low, high], btype="bandpass", output='sos')
w, h = sosfreqz(sos, worN=8000)
plt.plot((fs_nyq/np.pi)*w, np.abs(h))
plt.plot((fs_nyq/np.pi)*w, np.angle(h))
ax = plt.gca()
ax.set_xlabel("frequency [Hz]")
ax.set_xlim([0, 1000])
plt.show()

fs=16384
fs_nyq = fs*0.5
low = 100 / fs_nyq
high = 500 /fs_nyq

sos = butter(5, [low, high], btype="bandpass", output='sos')
w, h = sosfreqz(sos, worN=8000)
plt.plot((fs_nyq/np.pi)*w, np.abs(h))
plt.plot((fs_nyq/np.pi)*w, np.angle(h))
ax = plt.gca()
ax.set_xlabel("frequency [Hz]")
ax.set_xlim([0, 1000])
plt.show()

この例は100Hz ~ 500Hzのバンドパスフィルター
次数は20次と5次
https://coffeepote.tumblr.com/post/675760626378899456

https://coffeepote.tumblr.com/post/675760649133080576


■ 参考 : scipy.signal.butter

■ 参考 : scipy.signal.ellip





フィルターの係数がわかっている場合・・・・
from scipy.signal import butter, sosfreqz, ellip
import numpy as np
import matplotlib.pyplot as plt
import math

import matplotlib.ticker as ptick
from matplotlib.ticker import ScalarFormatter, NullFormatter


import matplotlib as mpl

mpl.rcParams['xtick.labelsize'] = 20
mpl.rcParams['ytick.labelsize'] = 20
mpl.rcParams["axes.labelsize"] = 20
mpl.rcParams["axes.titlesize"] = 20
mpl.rcParams["legend.fontsize"] = 20

# filter coefficient
# order : [b0, b1, b2, a0, a1, a2]
#
label=band pass 0.03-0.1 Hz"
freq_range = [0.02, 0.2]
coeff1 = [1, -1.999998669372317, +0.999999999999999, 1, -1.999946242188092, +0.999946281201766]
coeff2 = [1, -1.999999767511141, +1.000000000000011, 1, -1.999955898604725, +0.999955963180191]
coeff3 = [1, -1.999999999400776, +0.999999999999995, 1, -1.999961099937338, +0.999961120373777]
coeff4 = [1, -1.999999853828710, +0.999999999999960, 1, -1.999976229681027, +0.999976314187963]
coeff5 = [1, -1.999999996570461, +1.000000000000034, 1, -1.999980731688244, +0.999980744035228]
coeff6 = [1, -1.999999994545118, +0.999999999999935, 1, -1.999992076212929, +0.999992085647952]
coeff7 = [1, -1.999999873305222, +1.000000000000034, 1, -1.999992919697037, +0.999993013663749]
coeff8 = [1, -1.999999993706660, +1.000000000000031, 1, -1.999997892111085, +0.999997900596364]

coeff = [coeff1, coeff2, coeff3, coeff4,
coeff5, coeff6, coeff7, coeff8]
sos = np.array(coeff, dtype="float64")
print(coeff)

#
# filter response
#
w, h2 = sosfreqz(sos, worN=1000000) # worN decided the frequency resolution

#
# plot
#

plt.figure(figsize=[12, 6])
plt.plot((fs_nyq/np.pi)*w / factor, np.abs(h), label="hoge", color="magenta")
ax = plt.gca()
ax.set_xlabel("frequency [Hz]")
ax.set_ylabel("frequency response")
ax.set_xlim([1e-4, fs_nyq])
ax.set_title("with correction of down-sampling")
plt.xscale("log")
plt.yscale("log")
plt.legend(loc="lower right")
plt.gca().xaxis.set_major_formatter(plt.FormatStrFormatter('%.2f'))#y軸小数点以下3桁表示
plt.show()


https://coffeepote.tumblr.com/post/675779825695375360








こんな感じ
この例で使ったのは、8個のデータが別のkeyでdataという辞書型に入ってる
nはデータの数
本当はリストの長さになってたけど、めんどくさいんで消した

プロットは8個のデータをsubplotsで並べてプロットする
縦に8個並べるんじゃなくて、2x4で自動的に折り返す感じ
数字を変えたら、他のパターンも可能

q_1p = np.quantile(data[ch], 0.01)
q_99p = np.quantile(data[ch], 0.99)

 q_1p, q_99p = np.percentile(data[ch], q=[1, 99])
は上位1%と上位99%の値を調べる(quantileだと2回呼ばないといけないけど、percentileなら1回で済むので変更)

それを時系列データに同時にプロットする
from matplotlib import pyplot as plt
fig = plt.figure()
n = 8
n2 = int(n/2)
fig, axes = plt.subplots(n2,2, figsize=(30, 15), sharex=True)

k=0
for ch in data.keys():
 ii=n
 k = int(ii / n2)
 i = ii % n2

 axes[i, k].plot(data[ch], label=labels[ii], color="green")
 axes[i, k].legend(loc="upper right")

 #q_1p = np.quantile(data[ch], 0.01)
 #q_99p = np.quantile(data[ch], 0.99)
 q_1p, q_99p = np.percentile(data[ch], q=[1, 99])
 axes[i, k].axhline(y=q_1p, color="m", alpha=0.7, linestyle='--')
 axes[i, k].axhline(y=q_99p, color="m", alpha=0.7, linestyle='--')

axes[0, 0].set_title("time from %s" % time1)
axes[0, 1].set_title("channel = %s" % ch_out)

fig.savefig("./fig/hoge.png")





from matplotlib import pyplot as plt

fig, axes = plt.subplots(2,1, figsize=(10, 12), sharex=True)
ax1 = plt.subplot(2, 1, 1)
ax1.plot(data_freq, data_TF, color="skyblue", marker="o", linestyle="None", label="aaaaa")
ax1.set_xscale('log')
ax1.set_yscale('log')
ax1.set_ylabel('magnitude')
ax1.set_xlim(fmin, fmax)
ax1.set_title("title daup")
ax1.legend(loc="upper right")

ax2 = plt.subplot(2, 1, 2)
ax2.plot(data1, data2, label="coherence (original)")
ax2.set_xscale('log')
ax2.set_xlabel('frequency [Hz]')
ax2.set_ylabel('coherence')
ax2.set_xlim(fmin, fmax)
ax2.legend(loc="lower right")
plt.savefig(fname)
plt.show()






■ 過去記事 : matplotlibの凡例(legend)レイアウト関連メモ

matplotlibでプロットするときにlabel="aaa"と書いて、ax.legend() みたいにlegend機能をオンにすると
最初から図にlegendを付けられる
# ↑のリンクからお借りした

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 101)
y1 = np.sin(x * np.pi)
y2 = np.cos(x * 2 * np.pi) * 0.5

fig = plt.figure()
ax = fig.add_subplot(111)

# labelオプションで凡例に用いる曲線名を指定
ax.plot(x, y1, c="r", label="$\mathrm{sin}(x)$")
ax.plot(x, y2, c="b", label="$0.5 \mathrm{cos}(2x)$")
ax.grid(axis='both')

# 凡例の表示
ax.legend()



labelを最初に付けずに、後から図に付けたくて色々と調べたのでメモ

■ 過去記事 : Legend Demo
import matplotlib.pyplot as plt
import matplotlib.collections as mcol
from matplotlib.legend_handler import HandlerLineCollection, HandlerTuple
from matplotlib.lines import Line2D
import numpy as np

t1 = np.arange(0.0, 2.0, 0.1)
t2 = np.arange(0.0, 2.0, 0.01)

fig, ax = plt.subplots()

# note that plot returns a list of lines. The "l1, = plot" usage
# extracts the first element of the list into l1 using tuple
# unpacking. So l1 is a Line2D instance, not a sequence of lines
l1, = ax.plot(t2, np.exp(-t2))
l2, l3 = ax.plot(t2, np.sin(2 * np.pi * t2), '--o', t1, np.log(1 + t1), '.')
l4, = ax.plot(t2, np.exp(-t2) * np.sin(2 * np.pi * t2), 's-.')

ax.legend((l2, l4), ('oscillatory', 'damped'), loc='upper right', shadow=True)
ax.set_xlabel('time')
ax.set_ylabel('volts')
ax.set_title('Damped oscillation')
plt.show()
よくわからんけど、1つの画面に4種類の描画をしてて(l1~l4)
l2とl4にだけ後からlegendを追加してる


■ 過去記事 : 5. Comparing seismic trends between LIGO sites

自分研究でよく使うgwpyというのだと
plot = Plot(lho, llo, figsize=(12, 6), sharex=True, yscale='log')
ax1, ax2 = plot.axes
for ifo, ax in zip(('Hanford', 'Livingston'), (ax1, ax2)):
ax.legend(['X', 'Y', 'Z'])
ax.text(1.01, 0.5, ifo, ha='left', va='center', transform=ax.transAxes,
fontsize=18)
ax1.set_ylabel(r'$1-3$\,Hz motion [nm/s]', y=-0.1)
ax2.set_ylabel('')
ax1.set_title('Magnitude 7.1 earthquake impact on LIGO')
plot.show()
みたいにしてる
1行目で2種類のプロットをして、それに対して後付でlegendを付けてる

ax1, ax2 = plot.axesで、それにlegendを適用すればいいっぽい




この記事もメモ

■ 過去記事 : Matplotlib legends in subplot


この方法は自分は上手く行かなかったけどメモ
■ 過去記事 : すでに描画されているグラフに凡例(ラベル)をつける方法について





(2022/01/31 追記)

というか普通に、
plot = Plot(data1, data2, data3)
ax = plot.gca()
ax.legend(['data1dayo', 'data2 dayo', 'data3 dayo''])
plot.show()

でいいっぽいな





ndarrayなことを活用しつつ、最大限高速で処理を終わらせたい

ndarrayを区間ごとに分割するのはnp.splitを使えばいい
割り切れない場合は、numpy.array_split()を使うとndarrayをできるだけ等分割で分割できる
numpy.split()は等分割

■ 参考 : NumPy配列ndarrayを分割(split, array_split, hsplit, vsplit, dsplit)
import numpy as np

n_a=len(a)
n_clst=10
n_seg=int(n_a/n_clst)

a_split = np.split(a, n_seg)
みたいにして分割する

aは分割前の1次元のndarray
これを10個ずつ(=n_clst)に分割したい

splitで分割した結果(a_split)はlistの中に小さいndarrayがn_seg個入っている
最初、1つのndarrayの要素数がn_seg個なのかと思って少しハマった
実際は1つのndarrayの要素数は、上の例ではn_clst個






その後分割されたndarrayの中で最大値を見つける
最大値を探すだけだとnp.max()を使えばいい

今回は、最大値になったときのindexを再利用したい
import numpy as np

n_a=len(a)
n_clst=10
n_seg=int(n_a/n_clst)

a_split = np.split(a, n_seg)

for i, x in enumerate(a_split):
 j = np.argmax(x)
 i_max = j + i*n_clst

jが各セグメント(x)の中で、最大値だったときのindex
i_maxが元のndarray(a)での最大値のindex


やはりlistよりもndarrayのほうが圧倒的に早い
それでもさらに速さを求めるなら、cythonとかを使うっぽいね







■ 過去記事 : scipy.signal.find_peaks

scipyにfind_peaksという関数がある

オプションdistanceを設定すると、何サンプルごとに最大値を見つけるかを設定できる

サンプルとかは↑のリンク先にわかりやすくまとめられている









subplotとsubplotsのどっちを使おうか迷ったけど、時代はsuboplotsらしい


■ 参考記事 : matplotlib で散布図 (Scatter plot) を描く


■ 参考記事 : Sample plots in Matplotlib

■ 参考記事 : matplotlibの描画の基本 - figやらaxesやらがよくわからなくなった人向け


■ 参考記事 : subplot? add_subplot? subplots?b


ここまでがmatplotlibのsubplotsの話


散布図を並べたときに空っぽの図をプロットする方法

■ 参考記事 : How can I make a blank subplot in matplotlib?



サンプルコードとサンプルのプロットはそのうち追記する予定






y軸の場合は、以下のようにすればOK(x軸ならy→xに変える)
プロットを書いてから、yticslabelsに空リストを渡せばいい
ax = plt.gca()
ax.set_yticklabels([])
■ 過去記事 : [Matplotlib] 目盛と目盛ラベル、目盛線の設定

■ 過去記事 : matplotlibで軸を消す






wikiによると、
cython(サイソン)は、C言語によるPythonの拡張モジュールの作成の労力を軽減することを目的として開発されたプログラミング言語である。その言語仕様はほとんどPythonのものと同じ (上位互換) だが、Cの関数を直接呼び出したり、C言語の変数の型やクラスを宣言できるなどの拡張が行われている。Cythonの処理系ではソースファイルをCのコードに変換し、コンパイルすればPythonの拡張モジュールになるようにして出力する。

このようにCとPythonをシームレスに取り混ぜて扱うCythonの利点の一つは、既にあるPythonコードを、いくつかの静的な型 (static type) を宣言して律速なループをうまく書き直すだけで、コンパイル後のコードの実行速度がC言語並みに高速化されることである。複雑なC言語インターフェイスを使う必要はない。コーディングのしやすさと可読性はPythonと変わらない、つまりPythonic(英語版)なままである。数値計算/配列操作では、多くの場合実行速度がおおよそ100倍になる。PythonのJITコンパイラであるPsycoの場合はおおよそ4倍である。
要するに
pythonはスクリプト言語なので遅いのがネック
そこをC言語のコードにしてしまって実行時間を早くする
ということらしい

cython化したコードを使う方法は何種類かあるらしい
・pyxコードを別に用意する(setup.pyでコンパイルが必要)
・pxdコードを別に用意する(setup.pyでコンパイルが必要)
・マジック属性を使う形式(コンパイル不要?)
・さらに変数の型も指定する(コンパイル不要?)

■ 過去記事 : Cythonの浅漬け

■ 過去記事 : 深入りしないCython入門







import random
import numpy as np
import matplotlib.pyplot as plt

a = [random.random() for i in range(100)]

val1, base1 = np.histogram(a, bins=100, range=(0.4, 0.8))
みたいな感じでヒストグラムを作る
val1とbase1にはヒストグラムのあるビンのサンプル数とx軸のための値(等ビン幅のリスト)が入っている

len(base1), len(val1)
としてみると、101, 100と返ってくるのでこれをなんとか処理してからプロットする必要がある




この記事がわかりやすい

■ 過去記事 : Matplotlib - Stepped histogram with already binned data




記事がなくなるとわからなくなるのでメモっておく
def plot_binned_data(axes, binedges, data,
*args, **kwargs):
#The dataset values are the bin centres
x = (binedges[1:] + binedges[:-1]) / 2.0
#The weights are the y-values of the input binned data
weights = data
return axes.hist(x, bins=binedges, weights=weights,
*args, **kwargs)


import numpy
import matplotlib.pyplot as plt

#Create a dataset
dataset = numpy.random.normal(size=100)
#Bin the dataset
binedges = numpy.linspace(-5.0, 5.0, num=10)
y, binedges = numpy.histogram(dataset, binedges)

#Plot the dataset
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
plot_binned_data(ax, binedges, y, histtype="step")
plt.show()
2つのヒストグラムを重ね合わせたいときは、plot_binned_data()関数を2回呼べばOK
あとは plot_binned_data() の引数にlabelとかを付けてもOK

↓例
https://coffeepote.tumblr.com/post/657852653517307904






(2023/01/10 追記)

とりあえずここをみる。

■ 参考 : [Python]Matplotlibでヒストグラムを描画する方法


メモ
import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(figsize=[12, 12])

# もし複数枚プロットしたい時はここをいじる
# 2x2の場合は fig.add_subplot(2,2,1)として、最後の数字を1~4で変える(最初のプロットはi=0ではないことに注意)
ax = fig.add_subplot(1,1,1)

# ヒストグラムを取る時の範囲はrange指定する
# 0〜最大値*1.1とかにしておくのが吉
ax.hist(x, bins=50, range=[0, 10])
ax.set_title('hogehoge')
ax.set_xlabel('xlabel')
ax.set_ylabel('histogram')
#fig.show()
fig.savefig("hoge.png")

例えばsubplot(2, 2, 1)のように分割をした時に、プロット全体のタイトルをつけたい時は、
fig.suptitle("graphs")
のようにする
ただ、なぜかtitleとplotの間の隙間がかなり大きくなってしまったので、今回は使わなかった・・・・・

原因はドキュメントを見たらわかった

■ 参考 : subplots
fig.suptitle("graphs", y=0.90)
とy座標を手で調整すればOK
xもあるけど、そっちは0.5でいいだろう










pythonにはガーベッジコレクタという機能がある
使われなくリストや変数に使われているメモリを自動的に解放してくれる機能

これがあるから安心だと思ってたけど
自分のpythonコードをcondorHTに流したところ、めちゃくちゃメモリを使う・・・そしてhold(H)状態になって止まる

原因は不要になったメモリが自動的に開放されていないので、どんどんメモリを食っていくから

解決方法は
del hoge

とかで、使っていないメモリを解放していけばいい




↓ pythonのメモリ管理でとてもわかり易かった記事2つ

■ 過去記事 : 【python】pythonでメモリ不足になったときにすること

■ 過去記事 : PythonのPandasでメモリリーク?リークの可視化と暫定対策







delしたあとで、gc.collect()というのを呼ばないといけないという記事もあった
今回の場合はdelを大量に追加したら改善したので使わなかった

■ 過去記事 : Python でメモリをクリアする

■ 過去記事 : pythonでメモリを解放する必要はありますか。









画像を保存するときにjupyter notebook上にプロットを表示したくないとき
from matplotlib import pyplot as plt
%matplotlib agg


jupyter notebook上にプロットを表示したいとき
(これを書かないとx11が立ち上がってそこでプロットを見せてくる)
from matplotlib import pyplot as plt
%matplotlib inline









jupyter notebookでグラフを書く

できた画像を保存せずに、ドラッグ&ドロップでスライドとかに貼り付ける

画像のフチが透明になってる

便利だとは思うときもあるけど、たまにちょっと不便なときもある


縁の部分を白くしたいときは
fig = plt.figure()
fig.patch.set_facecolor('white')
とすればよい

注意 これは、savefigの前のしないとだめ。めんどくさかったら最初にplt.figure()した直後に書いておくと良い

■ 過去記事 : Matplotlibでグラフの背景色の不透明度を設定する方法


背景を透明にしたいときはsavefigにtransparent=Trueというオプションを付ければいいっぽい

■ 過去記事 : Matplotlib で図の余白のみを透明にする






(2023/01/26 追記)
import matplotlib as mpl
mpl.rcParams['figure.facecolor'] = "white"

これでもOK

というか、こっちの方が簡単










今のところやり方が見つかっていない

arrayじゃなくてリストだと部分内包表記で書くことができる
[c_match for c_match in c_list if "hoge" in c_match]
[c_match for c_match in c_list if "hoge" == c_match]
とか

もしリストの要素数が多い場合は、numpyのarrayでやった方が実行時間が短いと思う

が、良さそうな方法が見つからない
np.where() を使えば良いかな?と思ったけど、これは数字には使えるけど文字列だと完全一致にしか使えないっぽい

■ 過去記事 : numpy.chararray

numpy.chararrayというのもあるらしいが、イマイチ使い方がわからぬ・・・
なんか目的と違う気もする
なんか良さそうな方法が分かったら追記する

余談ですが、numpyについてかなり分かりやすく解説してくれているページがあった
■ 過去記事 : 10. numpyの基本と応用






いつの間にかどっぷりとpythonに飲み込まれている・・・
「pythonが便利」というわけではなくて、スクリプト言語でかつ開発環境がめちゃくちゃ整備されているから便利なんだと思う
pythonくん、決して君自身が素晴らしいとは考えないように!!

その中でもjupyter-notebookはとても便利
コードをemacsで開いて、実行して・・・ということをしなくてもその都度セルごとに修正・実行できる

サーバー側であるポートにjuputer-notebookを開いておいて手元のマシンではそのポートを見れば、
いつでも前回の計算の続きから行うこともできる
接続が切れてもサーバー側ではnotebookは動きっぱなしなので大丈夫
tmuxみたいな使い方もできる





ただ、notebookで自分が1つ不便だと思っているのは、同じノートブックで上の方に出したグラフと比較しにくいこと
最初は同じノートブックを2つ開いたりしてたが、これはconflictが起こったりしてよろしくない
最近はnotebookをhtmlに出力して、ダウンロードして開いて並べて比較
一応動くけど、スマートじゃないし、更新後のグラフと比較したいときはもっかい出力しないといけない


jupyter-labではタブ機能が使えるらしいのでそのあたり改善してるかも・・・
と思って使い始めてみる





■ jupyter-labのインストール
conda install -c conda-forge jupyterlab
動いた
https://coffeepote.tumblr.com/post/653410317777469440/jupyter-lab%E3%81%AF%E3%81%98%E3%82%81%E3%81%BE%E3%81%97%E3%81%9F
起動とか使い方は基本的にjupyter-notebookと同じだと思う
違う点があれば追記していく



■ jupyterlabの設定を変更

詳細は以下を参照

■ 過去記事 : JupyterLabのすゝめ


・ダークモードに変更
・セル内に行数を表示
・JupyterLab extensionで機能を追加
「その前にnodejsをインストールして」と警告が出るのでインストールする
単純に conda でインストールしようとしてもv6~v10までのものしか表示されない
conda install -c conda-forge nodejs
とすれば、v15.14.0がインストールされる

インストールした追加機能は
・toc

他にも便利そうなものがあれば追加していきたい







元々jupyter-labを使い始めたのは、同じコードを並べて比較したいからだった
その機能を見つけたのでメモ

■ 過去記事 :Jupyter Notebook/Lab, VS Code & Colabの編集性能を比較する

タブを右クリックして「New View for Notebook」でOK





(2021/07/06 追記)

このあと1ヶ月も立たずにjupyter labを使うのはやめたw
というのも、ネットワーク越しに使うとめちゃくちゃ重いし、遅い・・・・

ローカルでjupyter labを立ち上げる分には全然遅く感じないから、ネットワーク越しなのが不味そう
ということで、jupyter notebookに戻りまーす♪








普通の累積分布はy軸は0から1に向かって増えていく
今回は1から0に向かって減っていく累積分布を書く
あと、縦軸を0~1の範囲に収まるように規格化する必要がある
import matplotlib.pyplot as plt
import numpy as np

val1, base1 = np.histogram(input1, bins=nbins2)
cumulative1 = np.cumsum(val1)/len(input1) # 規格化してるのはここ
weight1 = np.ones(len(input1))/float(len(input1))

fig = plt.figure(figsize=[12, 10])

plt.plot(base1[:-1], 1-cumulative1, c='blue', label="aaaaaa", linewidth = 3.0)

plt.grid()
plt.yscale('log')
plt.xlabel('xxxx')
plt.ylabel('histogram')
plt.title("title")
plt.legend(loc='upper right')
fig.show()
fig.savefig("hoge.png")






プロフィール
HN:coffee
職業:物理屋(自称)
趣味:映画鑑賞、登山
出身:大阪府の南の田舎
自己紹介:
import MyProfile
import coffee_pote from TWITTER
import amazonのほしい物リスト from WISH_LIST

print "先月子供が産まれました!"

# 最終更新 2022/10/25
カウンター
カウンター カウンター
ブログ内検索
ツイートするボタン
リンク
相互リンク募集中です (Twitterにてお知らせください)

Demo scripts for gnuplot version 5
(gnuplotのさまざまなデモ画像と作り方がまとめられている、眺めているだけでできるようになった気分になれる)

gnuplotスクリプトの解説
(米澤進吾さんの個人ページ、gnuplotと言えばこのかた)

gnuplot のページ
(Takeno Lab、うちのブログがリンクされていたのでリンク返し)

Twitterから映画の評価が分かる & 映画の鑑賞記録が残せる coco
(映画の感想をまとめられるサイト、いつもお世話になっています)

Astronomy Picture of the Day Archive
(天文や宇宙関連の最新の話題について画像とともにNASAが説明しているページ)

今日のほしぞら
(任意の時刻の空で見える星を表示してくれる、国立天文台が管理している)

GNUPLOTとアニメーション
(応用の項目の「見せてあげよう!ラピュタの雷を!!」あたりからすごすぎる)

読書メーター
(読んだ本をリストできる便利なサイト)

flickr難民の写真置き場
(20XX年、flickrは有料化の炎に包まれた。あらゆるflickr無料ユーザーは絶滅したかに見えた。 しかし、tumblr移住民は死に絶えてはいなかった。)

教授でもできるMac OS X へのLaTeX, X11, gccのインストレーションと環境設定
(阪大の山中卓さんのwebページ、タイトルにセンスが溢れている、内容は超充実してる、特にTeX関連、学振DCとかPDの申請書類作成時にはお世話になっております)

英語論文執筆用の例文検索サービス
(とんでもないものを見つけてしまった・・・・ arXivに収録されている 811,761報の 英語論文から,例文を検索するための検索エンジン)


Template "simple02" by Emile*Emilie
忍者ブログ [PR]