物理の駅 Physics station by 現役研究者

テクノロジーは共有されてこそ栄える

乳児用の体重計を自作するレシピ

5kgまで1g単位で測定できるキッチンスケールを2個

乳児の身長よりやや長いメッシュパネル

アイリスオーヤマ メッシュ パネル MPP-3060 ブラック

アイリスオーヤマ メッシュ パネル MPP-3060 ブラック

  • 発売日: 2002/08/01
  • メディア: Tools & Hardware

  • 2mm厚、透明アクリル板 メッシュ パネルよりやや小さめ

  • 滑り止め

合計5500円

キッチンスケールの上に、不透明な板を置くと値を読めなくなり、かつ操作できなくなるので、メッシュパネルが良い。

キッチンスケール+滑り止め+メッシュパネル+アクリル板+布+乳児 の順にセットする。

キッチンスケールの値をカメラで撮影して読む。動いて値は変動するが、20~30gの精度で測定できると思う。

なんだけど、既製品を買ったほうが安いし楽だということに作ってから気づいた。

UbuntuでMackerelを動かすときのメモ

ループバックデバイスを無視する

設定 /etc/mackerel-agent/mackerel-agent.conf に以下を追記する

[filesystems]
ignore = "/dev/loop.*"

サービス mackerel-agent を再起動する

sudo systemctl restart mackerel-agent

NVIDIAのデバイスを監視する

まずは nvidia-smi が動くことを確認し、 mackerel-agent-plugins をインストールする

sudo apt install mackerel-agent-plugins

設定 /etc/mackerel-agent/mackerel-agent.conf に以下を追記する

[plugin.metrics.nvidia-smi]
command = "/usr/bin/mackerel-plugin-nvidia-smi"

サービス mackerel-agent を再起動する

sudo systemctl restart mackerel-agent

動作のログは以下で見れる

sudo journalctl -u mackerel-agent.service

再登録するとき

/var/lib/mackerel-agent/id を削除しておく

Pythonで直線同士の最接近距離と最接近点を知る

まずは、

その19 直線同士の最接近距離と最接近点を知る

Pythonへ移植する

import numpy as np

# http://marupeke296.com/COL_3D_No19_LinesDistAndPos.html
def distance_2lines(line1, line2):
    '''
    直線同士の最接近距離と最接近点
    return 直線間の距離, line1上の最近接点、line2上の最近接点
    '''
    line1 = [np.array(line1[0]),np.array(line1[1])]
    line2 = [np.array(line2[0]),np.array(line2[1])]

    if abs(np.linalg.norm(line1[1]))<0.0000001:
        return None,None,None
    if abs(np.linalg.norm(line2[1]))<0.0000001:
        return None,None,None

    p1 = line1[0]
    p2 = line2[0]

    v1 = line1[1] / np.linalg.norm(line1[1])
    v2 = line2[1] / np.linalg.norm(line2[1])

    d1 = np.dot(p2 - p1,v1)
    d2 = np.dot(p2 - p1,v2)
    dv = np.dot(v1,v2)

    if (abs(abs(dv) - 1) < 0.0000001):
        v = np.cross(p2 - p1,v1)
        return np.linalg.norm(v),None,None

    t1 = (d1 - d2 * dv) / (1 - dv * dv)
    t2 = (d2 - d1 * dv) / (dv * dv - 1)

    #外挿を含む最近接点
    q1 = p1 + t1 * v1
    q2 = p2 + t2 * v2

    return np.linalg.norm(q2 - q1), q1, q2

愚直に書いてはみたが、もっといい方法があればこっそり教えてほしい。

次に3次元の直線の描画

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def draw_3dline(lines):
    '''
    3次元の直線を描画する
    '''
    fig = plt.figure()
    ax = Axes3D(fig)
    for line in lines:
        line = np.array([np.array(line[0]),np.array(line[0])+np.array(line[1]),np.array(line[0])-np.array(line[1])])
        ax.plot(line[:,0], line[:,1], line[:,2], "o-", ms=4, mew=0.5)

    # 軸ラベル
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')

    # 表示
    plt.show()
line1 = [[0,0,0],[0,1,0]]
line2 = [[0,0,0],[1,0,0]]
res = distance_2lines(line1,line2)
print(res)
draw_3dline([line1,line2,[(res[1]+res[2])*0.5,[0,0,0]]])

f:id:onsanai:20200227182226p:plain

line1 = [[0,0,0],[0,1,0]]
line2 = [[0,0,0],[0,0,1]]
res = distance_2lines(line1,line2)
print(res)
draw_3dline([line1,line2,[(res[1]+res[2])*0.5,[0,0,0]]])

f:id:onsanai:20200227181921p:plain

少し距離が離れているケース

line1=[[0,0,0],[0,1,0]]
line2=[[0.2,0,0],[0,0,1]]
res = distance_2lines(line1,line2)
print(res)
draw_3dline([line1,line2,[(res[1]+res[2])*0.5,[0,0,0]]])

f:id:onsanai:20200227182318p:plain

並行な直線のケース

line1=[[0,0,0],[1,1,1]]
line2=[[1,0,0],[1,1,1]]
res = distance_2lines(line1,line2)
print(res)
draw_3dline([line1,line2])

f:id:onsanai:20200227182023p:plain

Python+matplotlibの基本設定とsubplotsのサイズや隙間を調整する方法

rcParamsの使い方

論文用のグラフを作るためには、matplotlibを使いこなす必要がある。

全オプションは plt.rcParams.keys() で確認できる。

rdParamsはこのページを参考にした

matplotlibでTimes New Romanが意図せずボールド体になってしまうときの対処法 - Qiita

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

plt.rcParams["font.family"] = "Times New Roman"     #全体のフォントを設定
plt.rcParams["font.size"] = 14                      #フォントの大きさ
plt.rcParams["xtick.direction"] = "in"              #x軸の目盛線が内向き('in')か外向き('out')か双方向か('inout')
plt.rcParams["ytick.direction"] = "in"              #y軸の目盛線が内向き('in')か外向き('out')か双方向か('inout')
plt.rcParams["xtick.minor.visible"] = True          #x軸補助目盛りの追加
plt.rcParams["ytick.minor.visible"] = True          #y軸補助目盛りの追加
plt.rcParams["xtick.major.width"] = 1.0             #x軸主目盛り線の線幅
plt.rcParams["ytick.major.width"] = 1.0             #y軸主目盛り線の線幅
plt.rcParams["xtick.minor.width"] = 1.0             #x軸補助目盛り線の線幅
plt.rcParams["ytick.minor.width"] = 1.0             #y軸補助目盛り線の線幅
plt.rcParams["xtick.major.size"] = 10               #x軸主目盛り線の長さ
plt.rcParams["ytick.major.size"] = 10               #y軸主目盛り線の長さ
plt.rcParams["xtick.minor.size"] = 5                #x軸補助目盛り線の長さ
plt.rcParams["ytick.minor.size"] = 5                #y軸補助目盛り線の長さ
plt.rcParams['xtick.top'] = False                   #x軸の上部目盛り
plt.rcParams['ytick.right'] = False                 #y軸の右部目盛り
plt.rcParams["axes.linewidth"] = 1.0                #囲みの太さ

def gaussian_func(arr, constant, mean, sigma):
    return constant * np.exp(- (arr - mean) ** 2 / (2 * sigma ** 2))/(2*np.pi*sigma**2)**0.5

x = np.linspace(-5, 5, 1000)
y =gaussian_func(x, 1.0, 0, 1)
fig = plt.figure()
ax = fig.add_subplot(111)

ax.plot(x,y,"k-",label="Total")
ax.set_xlim(-5, 5)
ax.set_ylim(0,None)
plt.legend()
plt.ylabel("Probability")
plt.xlabel("Data (cm)")
plt.text(-1.5, 0.2, r'Not fixed!!', size = 20, color = "black")
plt.savefig(f"gaussian.svg")
plt.savefig(f"gaussian.png")
plt.show()

デフォルトのfigureのサイズを指定する

単位はインチ

plt.rcParams['figure.figsize'] = [15, 10]

アスペクト比を設定

アスペクト比を調整 matplotlib.axes.Axes.set_aspect

import matplotlib.pyplot as plt
plt.subplot(1, 2, 1)
plt.plot([0,10],[0,40])
plt.gca().set_aspect('equal')

plt.subplot(1, 2, 2)
plt.plot([0,10],[0,40])
plt.gca().set_aspect(0.25)
plt.show()

上下左右の隙間を設定する

hspacewspacesubplots間の縦と横の隙間。

plt.rcParams["figure.subplot.top"]=0.88
plt.rcParams["figure.subplot.bottom"]=0.11
plt.rcParams["figure.subplot.right"]=0.9
plt.rcParams["figure.subplot.left"]=0.125
plt.rcParams["figure.subplot.hspace"]=0.2
plt.rcParams["figure.subplot.wspace"]=0.2

fig, ax = plt.subplots(2, 2,figsize=(6,5), facecolor='tab:blue', linewidth=10, edgecolor='tab:red')
plt.savefig("temp.png",dpi=300)
plt.show()

fig.subplots_adjust でも設定できる 上下左右の相対位置を端にして、subplots間の隙間も0にしてみた。

fig, ax = plt.subplots(2, 2,figsize=(6,5), facecolor='tab:blue', linewidth=10, edgecolor='tab:red')
fig.subplots_adjust(top=1,bottom=0,right=1,left=0,hspace=0,wspace=0)
plt.savefig("temp.png",dpi=300)
plt.show()

figsizeに合わせて上下左右とsubplots間の隙間を自動調整

通常、設定した上下左右の枠の位置に沿ってグラフは出力されるので、切れてしまうことがある。描画に応じて出力したい場合は以下のコマンドを使う。

plt.tight_layout() # 保存前に使う
#または
plt.savefig("result.png", bbox_inches="tight") #保存時

ちなみに、jupyter labなどを使うと自動的にtight_layoutしたグラフが表示される。

さらに細かくレイアウトを調整

レイアウトの指定なしの場合

fig,ax = plt.subplots(figsize=(6,5), facecolor='tab:blue', linewidth=10, edgecolor='tab:red')
ax.set_xlabel("x")
ax.set_ylabel("y")
plt.savefig("temp.png",dpi=300)
plt.show()

設定どおりの上下左右の隙間が使われるので無駄なスペースが気になる。

上下左右の隙間を数字やラベルに応じて自動調整してほしい場合は、一般的には tight_layout を使う。plt.subplots で指定するか、ファイル出力前にplt.tight_layout()とする。

fig,ax = plt.subplots(figsize=(6,5), tight_layout=True, facecolor='tab:blue', linewidth=10, edgecolor='tab:red')
ax.set_xlabel("x")
ax.set_ylabel("y")
# plt.tight_layout() #これでもでも可
plt.savefig("temp.png",dpi=300)
plt.show()

無駄なスペースが減った。

pad 周囲の隙間、h_padw_padはそれぞれsubplots間の縦と横の隙間である。ただし、目盛りラベルが全て描画されるように調整されるので、h_pad=0w_pad=0で必ずしもsubplots間の隙間がなくなるとは限らない。目盛りラベルに関係なく隙間を完全になくしたい場合はfig.subplots_adjust(hspace=0,wspace=0)を使うべきである。

fig,ax = plt.subplots(2, 2, figsize=(6,5), tight_layout={"pad":0,"h_pad":0,"w_pad":0}, facecolor='tab:blue', linewidth=10, edgecolor='tab:red')
plt.subplots_adjust(wspace=0, hspace=0, top=1, bottom=0, right=1, left=0)
plt.savefig("temp.png",dpi=300)
plt.show()

最近、constrained_layout というモードが追加された。

matplotlib.org

ユーザーが要求した論理レイアウトを可能な限り維持しながら、Figure ウィンドウに収まるようにサブプロットや凡例やカラーバーなどの装飾を自動的に調整します

らしい。

fig,ax = plt.subplots(figsize=(6,5), constrained_layout=True, facecolor='tab:blue', linewidth=10, edgecolor='tab:red')
ax.set_xlabel("x")
ax.set_ylabel("y")
plt.savefig("temp.png",dpi=300)
plt.show()

端のスペースがほぼなくなった。

隙間は、h_padで縦方向の隙間を、w_padで横方向の隙間を、hspacewspaceで それぞれsubplots間の縦と横の隙間を指定できる。

fig,ax = plt.subplots(2, 2, figsize=(6,5), constrained_layout={"hspace":0,"wspace":0,"h_pad":0,"w_pad":0}, facecolor='tab:blue', linewidth=10, edgecolor='tab:red')
plt.savefig("temp.png",dpi=300)
plt.show()

subplotsに共通の軸ラベルを付ける

figに対してfig.supxlabel()fig.supylabel()を行う。

import matplotlib.pyplot as plt
fig,ax = plt.subplots(2, 2, figsize=(6,5), facecolor='tab:blue', linewidth=10, edgecolor='tab:red')
fig.supxlabel('supxlabel',fontsize=14)
fig.supylabel('supylabel',fontsize=14)
plt.tight_layout()
plt.savefig("temp.png",dpi=300)
plt.show()

軸設定 (transform)

初期設定では、テキストを設定するときの座標はデータ transData で定義されている。 軸の相対位置で指示したい場合は、 transAxes とする。

さらに、subplotsを使った場合などで、グラフの相対位置で指示したい場合は、 fig.transFigure とする。

import matplotlib.pyplot as plt
fig, axs = plt.subplots(2, 2,figsize=(6,4))
axs = axs.flat
for ax in axs:
    ax.set_xlim(0,10)
    ax.set_ylim(0,10)
axs[0].text(5.0,5.0,"[5.0,5.0]  (default)",va="center",ha="center")
axs[1].text(5.0,5.0,"[5.0,5.0](transData)",va="center",ha="center",transform=axs[1].transData)
axs[2].text(0.5,0.5,"[0.5,0.5](transAxes)",va="center",ha="center",transform=axs[2].transAxes)
axs[3].text(0.5,0.5,"[0.5,0.5](transData)",va="center",ha="center",transform=axs[3].transData)
plt.text(0.5,0.5,"[0.5,0.5](transFigure)",va="center",ha="center",color="tab:red",transform=fig.transFigure)
plt.show()