自由研究3(厚労省の新型コロナの数値分析)

自由研究3(厚労省の新型コロナの数値分析)

目次

1 概要

  • 新型コロナの被害数値、厚労省から出されてるがPDFで処理しにくい
    • 厚労省からcsv形式の情報も出てるがPDFのまとめの数値とは異るデータ

2 関連文書

2.1 コロナ被害関係

2.1.1 厚労省

3 厚労省の過去のPDFデータへのリンク

4 厚労省のPDFファイルから4つの表を抜き出し、データベースに保存

4.1 説明動画


4.2 厚労省のPDFファイルから4つの表を抜き出し、データベースに保存の手順

4.2.1 必要なPythonパッケージのインストール

  1. 処理用の virtualenv を作成して、その環境に入る
    virtualenv corona_kourousyou
    cd corona_kourousyou
    source bin/activate
    
    • tikaをインストール(PDFファイルから文字を取り出すライブラリ)
    pip install tika
    pip install beautifulsoup4
    pip install nkf
    pip install pandas
    pip install matplotlib
    pip install ipython
    

4.2.2 過去の厚労省のPDFファイルをダウンロードして保存する

  • 今回表が4つになった後のPDFファイルのみを処理するので、令和2年12月2日以降のPDFファイルをダウンロード。私はwgetを用いて行なったが、好きなツールでOK
  • 令和3年9月1日までのPDFファイルをダウンロード
wget -m -l 1 https://www.mhlw.go.jp/content/10906000/000702069.pdf https://www.mhlw.go.jp/content/10906000/000704074.pdf https://www.mhlw.go.jp/content/10906000/000706508.pdf https://www.mhlw.go.jp/content/10906000/000710954.pdf https://www.mhlw.go.jp/content/10906000/000713230.pdf https://www.mhlw.go.jp/content/10906000/000716059.pdf https://www.mhlw.go.jp/content/10906000/000719997.pdf https://www.mhlw.go.jp/content/10906000/000724450.pdf https://www.mhlw.go.jp/content/10906000/000729529.pdf https://www.mhlw.go.jp/content/10906000/000734265.pdf https://www.mhlw.go.jp/content/10906000/000737675.pdf https://www.mhlw.go.jp/content/10906000/000741558.pdf https://www.mhlw.go.jp/content/10906000/000744930.pdf https://www.mhlw.go.jp/content/10906000/000748700.pdf https://www.mhlw.go.jp/content/10906000/000751942.pdf https://www.mhlw.go.jp/content/10906000/000755959.pdf https://www.mhlw.go.jp/content/10906000/000759133.pdf https://www.mhlw.go.jp/content/10906000/000764521.pdf https://www.mhlw.go.jp/content/10906000/000767330.pdf https://www.mhlw.go.jp/content/10906000/000769397.pdf https://www.mhlw.go.jp/content/10906000/000771872.pdf https://www.mhlw.go.jp/content/10906000/000775287.pdf https://www.mhlw.go.jp/content/10906000/000776153.pdf https://www.mhlw.go.jp/content/10906000/000779060.pdf https://www.mhlw.go.jp/content/10906000/000782185.pdf https://www.mhlw.go.jp/content/10906000/000785178.pdf https://www.mhlw.go.jp/content/10906000/000787852.pdf https://www.mhlw.go.jp/content/10906000/000790442.pdf https://www.mhlw.go.jp/content/10906000/000793909.pdf https://www.mhlw.go.jp/content/10906000/000796884.pdf https://www.mhlw.go.jp/content/10906000/000800096.pdf https://www.mhlw.go.jp/content/10906000/000803404.pdf https://www.mhlw.go.jp/content/10906000/000807083.pdf https://www.mhlw.go.jp/content/10906000/000809637.pdf https://www.mhlw.go.jp/content/10906000/000813216.pdf https://www.mhlw.go.jp/content/10906000/000816691.pdf https://www.mhlw.go.jp/content/10906000/000818427.pdf https://www.mhlw.go.jp/content/10906000/000820306.pdf https://www.mhlw.go.jp/content/10906000/000823800.pdf https://www.mhlw.go.jp/content/10906000/000826874.pdf

4.2.3 PDFファイルからデータを抽出して、データベースにデータを出力するPythonスクリプトの作成手順

  • pdfのあるディレクトリに移動 ( cd www.mhlw.go.jp/content/10906000/ )
  • 以下の内容で、pdffiltertika.pyを作成
from tika import parser
from bs4 import BeautifulSoup
import re
import sys
import os
import nkf
import pickle
import pandas as pd
import sqlite3
import datetime
#import warnings
#warnings.simplefilter("ignore")
fname=sys.argv[1]
bname,ext=os.path.splitext(fname)
pdf = parser.from_file(fname, xmlContent=True)
xhtml_data = BeautifulSoup(pdf['content'])

# データの整形
def myfilter(data):
  ans=[]
  tans=None
  redatetime=re.compile("令和([0-9]+)年([0-9]+)月([0-9]+)日([0-9]+)時.*")
  for i in data:
    for j in i.text.strip().split("\n"):
      k=re.sub("^[^0-9\.]+","",j.strip())
      if re.match("^[0-9\. ]+$",k):
	if len(k)!=0 and len(k.split())>2:
	  print(k)
	  if len(k.split())>8:
	    ans.append(k.split())
      if j.find("令和")!=-1:
	tmp=nkf.nkf('-Z1w' , j.replace(" ","")).decode('utf-8')
	m=redatetime.match(tmp)
	if m:
	  print(m)
	  print(m.group(0))
	  print(m.group(1))
	  print(m.group(2))
	  print(m.group(3))
	  print(m.group(4))
	  print(m.group())
	  print(tmp)
	  print(j)
	  tans=(m.group(1),m.group(2),m.group(3),m.group(4))
  return (tans,ans)

# 2ページ目の表の処理
t1,ans1=myfilter(xhtml_data.find_all('div', attrs={'class': 'page'})[1].find_all('p'))
# 3ページ目の表の処理
t2,ans2=myfilter(xhtml_data.find_all('div', attrs={'class': 'page'})[2].find_all('p'))

# 文字列を数値化
for i in range(6):
  ans1[i]=list(map(lambda x:int(x),ans1[i]))
for i in range(6,9):
  ans1[i]=list(map(lambda x:float(x),ans1[i]))
for i in range(1):
  ans2[i]=list(map(lambda x:float(x),ans2[i]))
for i in range(1,3):
  ans2[i]=list(map(lambda x:int(x),ans2[i]))

# 資料から抜き出した年月日を数値化
t1=list(map(lambda x:int(x),t1))
t2=list(map(lambda x:int(x),t2))

# 資料から抜き出した年月日をdatetime型に変更
tt=datetime.date(t1[0]+2021-3,t1[1],t1[2])
# 資料から抜き出した年月日を %Y-%m-%d 形式の文字列に変換(ex. 2021-09-01)
tts=datetime.date(t1[0]+2021-3,t1[1],t1[2]).strftime("%Y-%m-%d")

# 変数t1,t2,ans1,ans2をpickeファイルに書き出し
with open(bname+".pickle","wb") as f:
  pickle.dump((t1,t2,ans1,ans2),f)


# データベースファイルの初期化
with sqlite3.connect("covid19_data.db") as conn:
  # テーブルの生成
  conn.execute("create table if not exists pcr(t date, age00 real, age10 real , age20 real , age30 real , age40 real , age50 real , age60 real , age70 real , age80 real, age real)")
  conn.execute("create table if not exists pcr_m(t date, age00 real, age10 real , age20 real , age30 real , age40 real , age50 real , age60 real , age70 real , age80 real, age real)")
  conn.execute("create table if not exists pcr_f(t date, age00 real, age10 real , age20 real , age30 real , age40 real , age50 real , age60 real , age70 real , age80 real, age real)")
  conn.execute("create table if not exists death(t date, age00 real, age10 real , age20 real , age30 real , age40 real , age50 real , age60 real , age70 real , age80 real, age real)")
  conn.execute("create table if not exists death_m(t date, age00 real, age10 real , age20 real , age30 real , age40 real , age50 real , age60 real , age70 real , age80 real, age real)")
  conn.execute("create table if not exists death_f(t date, age00 real, age10 real , age20 real , age30 real , age40 real , age50 real , age60 real , age70 real , age80 real, age real)")
  conn.execute("create table if not exists mortality(t date, age00 real, age10 real , age20 real , age30 real , age40 real , age50 real , age60 real , age70 real , age80 real, age real)")
  conn.execute("create table if not exists mortality_m(t date, age00 real, age10 real , age20 real , age30 real , age40 real , age50 real , age60 real , age70 real , age80 real, age real)")
  conn.execute("create table if not exists mortality_f(t date, age00 real, age10 real , age20 real , age30 real , age40 real , age50 real , age60 real , age70 real , age80 real, age real)")
  conn.execute("create table if not exists severe_r(t date, age real, age00 real, age10 real , age20 real , age30 real , age40 real , age50 real , age60 real , age70 real , age80 real, nc real, investigate real, undisclosed real)")
  conn.execute("create table if not exists severe(t date, age integer, age00 integer, age10 integer , age20 integer , age30 integer , age40 integer , age50 integer , age60 integer , age70 integer , age80 integer, nc integer, investigate integer, undisclosed integer)")
  conn.execute("create table if not exists hospitalization(t date, age integer, age00 integer, age10 integer , age20 integer , age30 integer , age40 integer , age50 integer , age60 integer , age70 integer , age80 integer, nc integer, investigate integer, undisclosed integer)")

# 取り込んだデータを書き出し
with sqlite3.connect("covid19_data.db") as conn:
  conn.execute("insert into pcr values( ?,?,?,?,? ,?,?,?,?,?, ? )", [tts]+ans1[0])
  conn.execute("insert into pcr_m values( ?,?,?,?,? ,?,?,?,?,?, ? )", [tts]+ans1[1])
  conn.execute("insert into pcr_f values( ?,?,?,?,? ,?,?,?,?,?, ? )", [tts]+ans1[2])
  conn.execute("insert into death values( ?,?,?,?,? ,?,?,?,?,?, ? )", [tts]+ans1[3])
  conn.execute("insert into death_m values( ?,?,?,?,? ,?,?,?,?,?, ? )", [tts]+ans1[4])
  conn.execute("insert into death_f values( ?,?,?,?,? ,?,?,?,?,?, ? )", [tts]+ans1[5])
  conn.execute("insert into mortality values( ?,?,?,?,? ,?,?,?,?,?, ? )", [tts]+ans1[6])
  conn.execute("insert into mortality_m values( ?,?,?,?,? ,?,?,?,?,?, ? )", [tts]+ans1[7])
  conn.execute("insert into mortality_f values( ?,?,?,?,? ,?,?,?,?,?, ? )", [tts]+ans1[8])
  conn.execute("insert into severe_r values( ?,?,?,?,? ,?,?,?,?,?, ?,?,?,? )", [tts]+ans2[0])
  conn.execute("insert into severe values( ?,?,?,?,? ,?,?,?,?,?, ?,?,?,? )", [tts]+ans2[1])
  conn.execute("insert into hospitalization values( ?,?,?,?,? ,?,?,?,?,?, ?,?,?,? )", [tts]+ans2[2])

# SQLでテスト用
# select * from death order by t asc;
  • 8個のスペースがtabに置き換わってしまってるので以下で変換(お好きなエディタで置換すればOK)
sed -e "s/\t/        /g" pdffiltertika.py > 1.py
mv 1.py pdffiltertika.py

4.3 作業自動化のためのGNU MakeのMakefileを作成およびデータ抽出

4.3.1 作業自動化のためのGNU MakeのMakefileを作成 手順

  • pdfのあるディレクトリに移動 ( cd www.mhlw.go.jp/content/10906000/ )
  • 以下の内容でMakefile作成
PDF=${wildcard *.pdf}
PICKLE=${PDF:.pdf=.pickle}

all: ${PICKLE}

%.pickle: %.pdf
	python3 pdffiltertika.py $<

4.3.2 データ抽出

  • データベースファイルの削除 と pickleファイルを削除
rm covid19_data.db *.pickle
  • PDFファイルからデータ抽出
make 

make

4.4 この章のまとめ

  • 厚労省のPDFファイルから、表の数値をプログラムで取り出せるようにした。

5 厚労省のPDFファイルから4つの表を抜き出し、データベースに保存したデータのpandasのデータフレームへ取り込み

5.1 説明動画


5.2 厚労省のPDFファイルから4つの表を抜き出し、データベースに保存したデータのpandasのデータフレームへ取り込み手順

5.2.1 Pythonの対話環境起動

  • virtualenv 環境にはいる
source bin/activate
cd  www.mhlw.go.jp/content/10906000/
  • Pythonの対話環境起動
ipython

5.2.2 SQLite3のデータベースファイルからデータ取り出し

  • 以下の名前の変数に時系列データを入れる
    • pcrに陽性数
      • pcr_mに陽性数(男性
      • pcr_fに陽性数(女性
    • deathに死者数の累計
      • death_mに死者数の累計(男性
      • death_fに死者数の累計(女性
    • mortalityに死亡
      • mortality_mに死亡率(男性
      • mortality_fに死亡率(女性
    • severe に重傷者数(累計ではないその時点の)
    • severe_r に重傷化率
    • hospitalization に入院を必要とする人数
import pandas as pd
import sqlite3
import datetime
sql = "select * from death order by t asc"
with sqlite3.connect("covid19_data.db") as conn:
  death=pd.read_sql(sql, conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  death_m=pd.read_sql(sql.replace("death","death_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  death_f=pd.read_sql(sql.replace("death","death_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality=pd.read_sql(sql.replace("death","mortality"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality_m=pd.read_sql(sql.replace("death","mortality_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality_f=pd.read_sql(sql.replace("death","mortality_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr=pd.read_sql(sql.replace("death","pcr"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr_m=pd.read_sql(sql.replace("death","pcr_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr_f=pd.read_sql(sql.replace("death","pcr_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  severe_r=pd.read_sql(sql.replace("death","severe_r"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  severe=pd.read_sql(sql.replace("death","severe"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  hospitalization=pd.read_sql(sql.replace("death","hospitalization"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})

5.2.3 取り込んだデータの確認

#死亡者数の累計表示
death
#1週間毎の死亡者数
death.diff()
#1週間毎の陽性者数あたりの死亡率
death.diff()/pcr.diff()*100.0

5.3 この章のまとめ

  • データベースに格納してあった、時系列データをPythonのpandasのデータフレームに取り出した

6 厚労省のPDFファイルから4つの表を抜き出したデータを色々みてみる(2021/9/1まで)

6.1 説明動画


6.2 厚労省のPDFファイルから4つの表を抜き出したデータを色々いじってみる手順

6.2.1 Pythonの対話環境起動

  • virtualenv 環境にはいる
source bin/activate
cd  www.mhlw.go.jp/content/10906000/
  • Pythonの対話環境起動
ipython

6.2.2 データ取り込み

import pandas as pd
import sqlite3
import datetime
sql = "select * from death order by t asc"
with sqlite3.connect("covid19_data.db") as conn:
  death=pd.read_sql(sql, conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  death_m=pd.read_sql(sql.replace("death","death_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  death_f=pd.read_sql(sql.replace("death","death_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality=pd.read_sql(sql.replace("death","mortality"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality_m=pd.read_sql(sql.replace("death","mortality_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality_f=pd.read_sql(sql.replace("death","mortality_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr=pd.read_sql(sql.replace("death","pcr"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr_m=pd.read_sql(sql.replace("death","pcr_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr_f=pd.read_sql(sql.replace("death","pcr_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  severe_r=pd.read_sql(sql.replace("death","severe_r"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  severe=pd.read_sql(sql.replace("death","severe"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  hospitalization=pd.read_sql(sql.replace("death","hospitalization"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})

6.2.3 最近多い重傷者の変化を調べてみる

  1. 小数点以下の表示桁数を変更
    pd.options.display.precision=3
    
  2. 重傷者数の時系列表示
    severe
    
  3. 重傷者数の変化時系列表示
    1. 重傷者数の1週間の変化を表示
      severe.diff()
      
  4. 重症化率を調べてみる
    severe_r
    
  5. 重傷化率の変化時系列
    1. 重傷者化率の1週間の変化を
      severe_r.diff()
      
  6. 死者数
    1. 死者数の時系列
      death
      
      • 最後の行を表示
      death.tail(1)
      
      • 累積和を計算
      death.tail(1).cumsum(axis=1)
      
      • 累積和の割合を計算
      death.tail(1).cumsum(axis=1)/float(death.tail(1).cumsum(axis=1)["age80"])*100
      
    2. 1週間毎の死者数の時系列
      death.diff()
      
    3. 1週間毎の死者数の4週移動平均
      death.diff().rolling(4).mean()
      
  7. 死者数の変化
    1. 1週間毎の死者数の変化の時系列表示
      death.diff().diff()
      
  8. 死亡率を調べてみる
    1. 1週間毎の死亡率を調べてみる
      death.diff()/pcr.diff()*100
      
    2. 1週間毎の死亡率の1ヶ月の移動平均
      (death.diff()/pcr.diff()*100).rolling(4).mean()
      
  9. 死亡率の変化を調べてみる
    1. 1週間毎の死亡率の変化を調べてみる
      (death.diff()/pcr.diff()*100).diff()
      
    2. 1週間毎の死亡率の1ヶ月の移動平均の差分
      (death.diff()/pcr.diff()*100).rolling(4).mean().diff()
      

7 Matplotlibでグラフ表示1(Matplotlibの基礎確認)

7.1 説明動画


7.2 matplotlibでグラフ表示の手順

7.2.1 Pythonの対話環境起動

  • virtualenv 環境にはいる
source bin/activate
cd  www.mhlw.go.jp/content/10906000/
  • matplotlibがはいってないなら以下でインストール
pip install matplotlib
  • Pythonの対話環境起動
ipython

7.2.2 データ取り込み等

import pandas as pd
import sqlite3
import datetime
import matplotlib.pyplot as plt
import matplotlib
sql = "select * from death order by t asc"
with sqlite3.connect("covid19_data.db") as conn:
  death=pd.read_sql(sql, conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  death_m=pd.read_sql(sql.replace("death","death_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  death_f=pd.read_sql(sql.replace("death","death_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality=pd.read_sql(sql.replace("death","mortality"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality_m=pd.read_sql(sql.replace("death","mortality_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality_f=pd.read_sql(sql.replace("death","mortality_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr=pd.read_sql(sql.replace("death","pcr"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr_m=pd.read_sql(sql.replace("death","pcr_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr_f=pd.read_sql(sql.replace("death","pcr_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  severe_r=pd.read_sql(sql.replace("death","severe_r"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  severe=pd.read_sql(sql.replace("death","severe"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  hospitalization=pd.read_sql(sql.replace("death","hospitalization"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})

7.2.3 重傷者の数をグラフ表示1

severe.plot()
plt.show()

7.2.4 重傷者の数をグラフ表示2 グリッドを追加して表示

severe.plot()
plt.grid()
plt.show()

7.2.5 日本語フォントを指定

  • これしないと文字化けする
  • フォントのフルパスは実際使いたいフォントパスに変更してください。(“/usr/share/fonts/truetype/fonts-japanese-gothic.ttf”は私のUbuntu環境のfontのパスから適当に選択しました)
matplotlib.rcParams["font.family"] = matplotlib.font_manager.FontProperties(fname="/usr/share/fonts/truetype/fonts-japanese-gothic.ttf").get_name()

7.2.6 重傷者の数をグラフ表示3 軸ラベルも追加して表示

severe.plot()
plt.xlabel("年月日")
plt.ylabel("重傷者数(人)")
plt.title("厚労省のPDFから抜き出した重傷者数(人)")
plt.grid()
plt.show()

7.3 この章のまとめ

  • Matplotlibの使い方の基礎確認

8 Matplotlibでグラフ表示2(上下に2つのグラフ表示)

8.1 説明動画


8.2 matplotlibでグラフ表示の手順

8.2.1 Pythonの対話環境起動

  • virtualenv 環境にはいる
source bin/activate
cd  www.mhlw.go.jp/content/10906000/
  • matplotlibがはいってないなら以下でインストール
pip install matplotlib
  • Pythonの対話環境起動
ipython

8.2.2 データ取り込み等

import pandas as pd
import sqlite3
import datetime
import matplotlib.pyplot as plt
import matplotlib
sql = "select * from death order by t asc"
with sqlite3.connect("covid19_data.db") as conn:
  death=pd.read_sql(sql, conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  death_m=pd.read_sql(sql.replace("death","death_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  death_f=pd.read_sql(sql.replace("death","death_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality=pd.read_sql(sql.replace("death","mortality"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality_m=pd.read_sql(sql.replace("death","mortality_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality_f=pd.read_sql(sql.replace("death","mortality_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr=pd.read_sql(sql.replace("death","pcr"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr_m=pd.read_sql(sql.replace("death","pcr_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr_f=pd.read_sql(sql.replace("death","pcr_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  severe_r=pd.read_sql(sql.replace("death","severe_r"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  severe=pd.read_sql(sql.replace("death","severe"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  hospitalization=pd.read_sql(sql.replace("death","hospitalization"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})

8.2.3 重傷者の数をグラフ表示3 軸ラベルも追加して表示

fig = plt.figure()
axes= fig.subplots(2)
severe.plot(ax=axes[0])
death.diff().plot(ax=axes[1])
axes[0].grid()
axes[0].set_xlabel("年月日")
axes[0].set_ylabel("重傷者数(人)")
axes[0].set_title("厚労省PDFから抜き出した数値から作成")
axes[1].grid()
axes[1].set_xlabel("年月日")
axes[1].set_ylabel("1週間毎の死者数(人)")
plt.show()

8.3 この章のまとめ

  • Matplotlibの使い方の基礎、複数のグラフの同時表示のやりかたの確認をした

9 Matplotlibでグラフ表示3(パイチャート)

9.1 説明動画


9.2 matplotlibでグラフ表示の手順

9.2.1 Pythonの対話環境起動

  • virtualenv 環境にはいる
source bin/activate
cd  www.mhlw.go.jp/content/10906000/
  • matplotlibがはいってないなら以下でインストール
pip install matplotlib
  • Pythonの対話環境起動
ipython

9.2.2 データ取り込み等

  • フォントのフルパスは実際使いたいフォントパスに変更してください。(“/usr/share/fonts/truetype/fonts-japanese-gothic.ttf”は私のUbuntu環境のfontのパスから適当に選択しました)
import pandas as pd
import sqlite3
import datetime
import matplotlib.pyplot as plt
import matplotlib
sql = "select * from death order by t asc"
with sqlite3.connect("covid19_data.db") as conn:
  death=pd.read_sql(sql, conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  death_m=pd.read_sql(sql.replace("death","death_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  death_f=pd.read_sql(sql.replace("death","death_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality=pd.read_sql(sql.replace("death","mortality"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality_m=pd.read_sql(sql.replace("death","mortality_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality_f=pd.read_sql(sql.replace("death","mortality_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr=pd.read_sql(sql.replace("death","pcr"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr_m=pd.read_sql(sql.replace("death","pcr_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr_f=pd.read_sql(sql.replace("death","pcr_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  severe_r=pd.read_sql(sql.replace("death","severe_r"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  severe=pd.read_sql(sql.replace("death","severe"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  hospitalization=pd.read_sql(sql.replace("death","hospitalization"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
matplotlib.rcParams["font.family"] = matplotlib.font_manager.FontProperties(fname="/usr/share/fonts/truetype/fonts-japanese-gothic.ttf").get_name()

9.2.3 パイチャート

  1. 死者数の累計
    tmp=death.tail(1).T[:-1]
    tmp.index=["10歳未満","10代","20代","30代","40代","50代","60代","70代","80代以上"]
    tmp.plot(kind='pie', autopct='%1.1f%%',subplots=True)
    plt.title("新型コロナでの死者累計の割合2021/09/01")
    plt.show()
    
  2. 直近重傷者
    tmp2=severe.tail(1).T[1:-3]
    tmp2.index=["10歳未満","10代","20代","30代","40代","50代","60代","70代","80代以上"]
    tmp2.plot(kind='pie', autopct='%1.1f%%',subplots=True)
    plt.title("新型コロナでの重傷者の割合2021/09/01")
    plt.show()
    
  3. 直近1週間の死者
    tmp3=death.diff().tail(1).T[:-1]
    tmp3.index=["10歳未満","10代","20代","30代","40代","50代","60代","70代","80代以上"]
    tmp3.plot(kind='pie', autopct='%1.1f%%',subplots=True)
    plt.title("新型コロナでの直近1週間の死者の割合2021/09/01")
    plt.show()
    
  4. 3つのグラフ同時表示
    fig = plt.figure()
    axes= fig.subplots(1,3)
    tmp.plot(kind='pie',ax=axes[0], autopct='%1.1f%%',subplots=True,legend=True)
    tmp2.plot(kind='pie',ax=axes[1], autopct='%1.1f%%',subplots=True,legend=False)
    tmp3.plot(kind='pie',ax=axes[2], autopct='%1.1f%%',subplots=True,legend=False)
    axes[0].set_title("新型コロナでの死者累計の割合2021/09/01")
    axes[1].set_title("新型コロナでの重傷者の割合2021/09/01")
    axes[2].set_title("新型コロナでの直近1週間の死者の割合2021/09/01")
    plt.show()
    
    1. 東京都福祉保健局(基礎疾患の有無、被害者の平均年齢情報あり)

9.3 この章のまとめ

  • Matplotlibの使い方の基礎、パイチャートの描画

10 新規PDFデータ追加

10.1 説明動画


10.2 データ追加の手順

10.2.1 virtualenv 環境にはいる

source bin/activate

10.2.2 pdfファイル追加

  • 以下は令和3年9月8日のPDFファイルのURLなので、更新された分(というか処理したいPDFを入れて)処理する必要がある
  • 複数ファイル追加もOK
  • ただし、令和2年12月2日より前のPDFファイルはフォーマットが異るため、入れるとエラーになる
  • 今後フォーマットが変更されると同じ処理で上手くデータ追加出来なくなる
wget -m -l 1 https://www.mhlw.go.jp/content/10906000/000830345.pdf

10.2.3 データ追加

  • pdfファイルのあるディレクトリに移動
cd  www.mhlw.go.jp/content/10906000/
  • GNU makeで処理
    • これで新しく追加した分のPDFファイルを処理して、抜き出した情報をデータベースに格納
make

10.3 この章のまとめ

  • 新しくPDFファイルを追加したときの処理方法についての説明

11 主要なデータの確認及びグラフ表示

11.1 説明動画


11.2 主要なデータの確認及びグラフ表示

11.2.1 データ取り込み等

  • フォントのフルパスは実際使いたいフォントパスに変更してください。(“/usr/share/fonts/truetype/fonts-japanese-gothic.ttf”は私のUbuntu環境のfontのパスから適当に選択しました)
  • 以下の名前の変数に時系列データを入れる
    • pcrに陽性数
      • pcr_mに陽性数(男性
      • pcr_fに陽性数(女性
    • deathに死者数の累計
      • death_mに死者数の累計(男性
      • death_fに死者数の累計(女性
    • mortalityに死亡
      • mortality_mに死亡率(男性
      • mortality_fに死亡率(女性
    • severe に重傷者数(累計ではないその時点の)
    • severe_r に重傷化率
    • hospitalization に入院を必要とする人数
import pandas as pd
import sqlite3
import datetime
import matplotlib.pyplot as plt
import matplotlib
sql = "select * from death order by t asc"
with sqlite3.connect("covid19_data.db") as conn:
  death=pd.read_sql(sql, conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  death_m=pd.read_sql(sql.replace("death","death_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  death_f=pd.read_sql(sql.replace("death","death_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality=pd.read_sql(sql.replace("death","mortality"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality_m=pd.read_sql(sql.replace("death","mortality_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  mortality_f=pd.read_sql(sql.replace("death","mortality_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr=pd.read_sql(sql.replace("death","pcr"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr_m=pd.read_sql(sql.replace("death","pcr_m"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  pcr_f=pd.read_sql(sql.replace("death","pcr_f"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  severe_r=pd.read_sql(sql.replace("death","severe_r"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  severe=pd.read_sql(sql.replace("death","severe"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
  hospitalization=pd.read_sql(sql.replace("death","hospitalization"), conn, index_col='t', parse_dates={'Date': '%Y-%m-%d'})
# 日本語フォントの設定
matplotlib.rcParams["font.family"] = matplotlib.font_manager.FontProperties(fname="/usr/share/fonts/truetype/fonts-japanese-gothic.ttf").get_name()
# 小数点以下の表示桁数を変更
pd.options.display.precision=3

11.2.2 死者数、最新から1週間での死者数、重傷者のパイチャート表示

fig = plt.figure()
axes= fig.subplots(1,5)
tmp=death.tail(1).T[:-1]
tmp2=severe.tail(1).T[1:-3]
tmp3=death.diff().tail(1).T[:-1]
tmp4=hospitalization.tail(1).T[1:-3]
tmp.index=["10歳未満","10代","20代","30代","40代","50代","60代","70代","80代以上"]
tmp2.index=["10歳未満","10代","20代","30代","40代","50代","60代","70代","80代以上"]
tmp3.index=["10歳未満","10代","20代","30代","40代","50代","60代","70代","80代以上"]
tmp4.index=["10歳未満","10代","20代","30代","40代","50代","60代","70代","80代以上"]
tmp.plot(kind='pie',ax=axes[0], autopct='%1.1f%%',subplots=True,legend=False)
tmp2.plot(kind='pie',ax=axes[1], autopct='%1.1f%%',subplots=True,legend=False)
tmp3.plot(kind='pie',ax=axes[2], autopct='%1.1f%%',subplots=True,legend=False)
tmp4.plot(kind='pie',ax=axes[3], autopct='%1.1f%%',subplots=True,legend=False)
tmp.plot(kind='pie',ax=axes[4], autopct='%1.1f%%',subplots=True,legend=True)
axes[0].set_title("死者累計の割合")
axes[1].set_title("重傷者の割合")
axes[2].set_title("直近1週間の死者の割合")
axes[3].set_title("入院治療等を要する者")
plt.show()

11.2.3 1週間の死者数の計算およびグラフ表示

  1. 重傷者数
    severe
    
  2. 1週間の死者数
    death.diff()
    
  3. グラフ表示
    fig = plt.figure()
    axes= fig.subplots(2)
    severe.plot(ax=axes[0])
    death.diff().plot(ax=axes[1])
    axes[0].grid()
    axes[0].set_xlabel("年月日")
    axes[0].set_ylabel("重傷者数(人)")
    axes[0].set_title("厚労省PDFから抜き出した数値から作成")
    axes[1].grid()
    axes[1].set_xlabel("年月日")
    axes[1].set_ylabel("1週間毎の死者数(人)")
    plt.show()
    

11.2.4 1週間毎の死亡率

  1. 計算
    death.diff()/pcr.diff()*100
    
  2. グラフ表示
    (death.diff()/pcr.diff()*100).plot()
    plt.title("1週間毎の死者数(人)")
    plt.show()
    

11.2.5 死亡率(その時までの累計での)

  1. データ確認
    mortality
    
  2. グラフ表示
    mortality.plot()
    plt.title("死者率(%)")
    plt.show()
    

11.2.6 重症化率

  1. データ確認
    severe_r
    
  2. グラフ表示
    severe_r.plot()
    plt.title("重症化率(%)")
    plt.show()
    

11.2.7 入院治療等を要する者(人数)

  1. データ確認
    hospitalization
    
  2. グラフ表示
    hospitalization.plot()
    plt.title("入院治療等を要する者(人)")
    plt.show()
    

11.3 この章のまとめ

  • 主要な情報の確認と、グラフ化をおこなった

12 今後

  • 今後文書追加するかも、しないかも

13 この文書のチェンジログ

  • 2021/09/02 初版
  • 2021/09/06 修正
  • 2021/09/08 以下の章を追加
    • Matplotlibでグラフ表示1(Matplotlibの基本確認) の章追加
    • Matplotlibでグラフ表示2(上下に2つのグラフ表示)
    • Matplotlibでグラフ表示3(パイチャート)
  • 2021/09/09 以下の章を追加
    • 新規PDFデータ追加
    • 主要なデータの確認及びグラフ表示

著者: NM Max

Created: 2021-09-09 木 22:55

Validate

自由研究2(厚労省のワクチンの成分がどこに行くのかを調べたPDF資料からの取り込みと、ソート)

自由研究2(厚労省のワクチンの成分がどこに行くのかを調べたPDF資料からの取り込みと、ソート)

1 概要

  • ファイザーワクチンの動物実験のデータがあり、どの臓器にどのくらい行くのかがわかる表がある。
    • PDFファイルで、処理しにくいのだが、多く行く臓器と、行く量がピークとなる時間の表を作成されている方がいたので、それをプログラムでやってみることにしました。

2 関連文書

2.1 厚労省の資料

2.2 使ったPythonパッケージ

3 厚労省のPDFファイルから2つの表を抜き出し、外部ファイルに保存

3.1 説明動画


3.2 厚労省のPDFファイルから2つの表を抜き出し、外部ファイルに保存する手順

3.2.1 仮想環境を用意し作業ディレクトリに入る

virtualenv covid-19
cd covid-19
source bin/activate

3.2.2 必要なパッケージインストール

pip install tabula-py
pip install ipython

3.2.3 元のPDFファイルをダウンロードして作業ディレクトリに保存

wget https://www.pmda.go.jp/drugs/2021/P20210212001/672212000_30300AMX00231_I100_1.pdf

3.2.4 PDFファイルのP.16,17から目的の表の一部を取り出して、ファイルに保存

  1. Pythonの対話環境起動
    ipython
    
  2. プログラムを動かして、表を作成して外部ファイルに保存
    import pandas as pd
    import tabula
    
    # pdfからデータ読み込み
    d0 = tabula.read_pdf("672212000_30300AMX00231_I100_1.pdf",pages="16,17")
    #d0 = tabula.read_pdf("672212000_30300AMX00231_I100_1.pdf",pages="16,17",stream=True)
    #d0 = tabula.read_pdf("672212000_30300AMX00231_I100_1.pdf",pages="16,17",lattice=True)
    
    # カラム名の変更
    d0[0].columns=['Sample','v1','v20','v21']
    d0[1].columns=['Sample','v1','v20','v21']
    
    for i,j in enumerate(d0[0]["v1"].isnull()):
      if j:
        d0[0]["Sample"][i-1]=d0[0]["Sample"][i-1]+" "+d0[0]["Sample"][i]
    for i,j in enumerate(d0[1]["v1"].isnull()):
      if j:
        d0[1]["Sample"][i-1]=d0[1]["Sample"][i-1]+" "+d0[1]["Sample"][i]
    
    
    # NaNのデータ削除
    d1=d0[0][d0[0]["v1"].notnull()]
    d2=d0[1][d0[1]["v1"].notnull()]
    
    # 経過時間名の配列作成
    idx=d2["v1"][1].replace(" h","h").split(" ")
    
    # 表の左側のみ残す
    d11=d1.drop([0,1]).drop(["v20","v21"],axis=1)
    d22=d2.drop([0,1]).drop(["v20","v21"],axis=1)
    
    # 列番号のふりなおし
    d111=d11.reset_index(drop=True)
    d222=d22.reset_index(drop=True)
    
    # データを配列に
    d1111=d111["v1"].str.rsplit(" ",expand=True)
    d2222=d222["v1"].str.rsplit(" ",expand=True)
    
    # 配列データが文字列なので、数値に変換
    for i in range(7):
      d1111[i] = pd.to_numeric(d1111[i])
      d2222[i] = pd.to_numeric(d2222[i])
    
    # 列の名前を経過時間に変更
    d1111.columns=idx
    d2222.columns=idx
    
    # 行毎の最高値と、そのインデックスを調べ、maxとtmaxという列を追加して格納
    tmpmax=d1111.max(axis=1)
    tmptmax=d1111.idxmax(axis=1)
    d1111["max"]=tmpmax
    d1111["tmax"]=tmptmax
    
    # 行毎の最高値と、そのインデックスを調べ、maxとtmaxという列を追加して格納2
    tmpmax=d2222.max(axis=1)
    tmptmax=d2222.idxmax(axis=1)
    d2222["max"]=tmpmax
    d2222["tmax"]=tmptmax
    
    # 一番左にenという列を追加して、英語名を入れる
    d1111.insert(0,"en",d111["Sample"])
    d2222.insert(0,"en",d222["Sample"])
    
    # P.16の表とp.17の表を結合してddという表にまとめる
    dd=pd.merge(d1111,d2222,how="outer")
    
    # 英語名を日本語に翻訳したk、jaという配列作成
    ja = ['脂肪組織', '副腎', '膀胱', '骨(大腿骨)', '骨髄(大腿骨)', '脳', '目', '心臓', '注射部位', '腎臓', '大腸', '肝臓', '肺', 'リンパ節(下顎)', 'リンパ節(腸間膜)', '筋', '卵巣(雌)', '膵臓', '脳下垂体', '前立腺(男性)', '唾液腺', '肌', '小腸', '脊髄', '脾臓', 'お腹', 'テスト(悪)', '胸腺', '甲状腺', '子宮(女性)', '全血', '血漿', '血液:血漿比']
    
    # ddの一番右に日本語名を"ja"という列名で追加
    dd.insert(len(dd.columns),"ja",ja)
    
    # pickleパッケージで、作成した表を外部ファイル seibun_data2.pickle に保存
    import pickle
    with open('seibun_data2.pickle', 'wb') as f:
        pickle.dump(dd,f)
    

3.2.5 作成した表データを表示してみる

                         en    0.25h       1h       2h       4h       8h      24h      48h      max   tmax         ja
0            Adipose tissue    0.057    0.100    0.126    0.128    0.093    0.084    0.181    0.181    48h       脂肪組織
1            Adrenal glands    0.271    1.480    2.720    2.890    6.800   13.800   18.200   18.200    48h         副腎
2                   Bladder    0.041    0.130    0.146    0.167    0.148    0.247    0.365    0.365    48h         膀胱
3              Bone (femur)    0.091    0.195    0.266    0.276    0.340    0.342    0.687    0.687    48h     骨(大腿骨)
4       Bone marrow (femur)    0.479    0.960    1.240    1.240    1.840    2.490    3.770    3.770    48h    骨髄(大腿骨)
5                     Brain    0.045    0.100    0.138    0.115    0.073    0.069    0.068    0.138     2h          脳
6                      Eyes    0.010    0.035    0.052    0.067    0.059    0.091    0.112    0.112    48h          目
7                     Heart    0.282    1.030    1.400    0.987    0.790    0.451    0.546    1.400     2h         心臓
8            Injection site  128.000  394.000  311.000  338.000  213.000  195.000  165.000  394.000     1h       注射部位
9                   Kidneys    0.391    1.160    2.050    0.924    0.590    0.426    0.425    2.050     2h         腎臓
10          Large intestine    0.013    0.048    0.093    0.287    0.649    1.100    1.340    1.340    48h         大腸
11                    Liver    0.737    4.630   11.000   16.500   26.500   19.200   24.300   26.500     8h         肝臓
12                     Lung    0.492    1.210    1.830    1.500    1.150    1.040    1.090    1.830     2h          肺
13  Lymph node (mandibular)    0.064    0.189    0.290    0.408    0.534    0.554    0.727    0.727    48h   リンパ節(下顎)
14  Lymph node (mesenteric)    0.050    0.146    0.530    0.489    0.689    0.985    1.370    1.370    48h  リンパ節(腸間膜)
15                   Muscle    0.021    0.061    0.084    0.103    0.096    0.095    0.192    0.192    48h          筋
16        Ovaries (females)    0.104    1.340    1.640    2.340    3.090    5.240   12.300   12.300    48h      卵巣(雌)
17                 Pancreas    0.081    0.207    0.414    0.380    0.294    0.358    0.599    0.599    48h         膵臓
18          Pituitary gland    0.339    0.645    0.868    0.854    0.405    0.478    0.694    0.868     2h       脳下垂体
19         Prostate (males)    0.061    0.091    0.128    0.157    0.150    0.183    0.170    0.183    24h    前立腺(男性)
20          Salivary glands    0.084    0.193    0.255    0.220    0.135    0.170    0.264    0.264    48h        唾液腺
21                     Skin    0.013    0.208    0.159    0.145    0.119    0.157    0.253    0.253    48h          肌
22          Small intestine    0.030    0.221    0.476    0.879    1.280    1.300    1.470    1.470    48h         小腸
23              Spinal cord    0.043    0.097    0.169    0.250    0.106    0.085    0.112    0.250     4h         脊髄
24                   Spleen    0.334    2.470    7.730   10.300   22.100   20.100   23.400   23.400    48h         脾臓
25                  Stomach    0.017    0.065    0.115    0.144    0.268    0.152    0.215    0.268     8h         お腹
26           Testes (males)    0.031    0.042    0.079    0.129    0.146    0.304    0.320    0.320    48h     テスト(悪)
27                   Thymus    0.088    0.243    0.340    0.335    0.196    0.207    0.331    0.340     2h         胸腺
28                  Thyroid    0.155    0.536    0.842    0.851    0.544    0.578    1.000    1.000    48h        甲状腺
29         Uterus (females)    0.043    0.203    0.305    0.140    0.287    0.289    0.456    0.456    48h     子宮(女性)
30              Whole blood    1.970    4.370    5.400    3.050    1.310    0.909    0.420    5.400     2h         全血
31                   Plasma    3.970    8.130    8.900    6.500    2.360    1.780    0.805    8.900     2h         血漿
32      Blood:Plasma ratioa    0.815    0.515    0.550    0.510    0.555    0.530    0.540    0.815  0.25h     血液:血漿比

3.2.6 表を読み込み、その臓器に行った量の多い順にソート、そして、結果をCSVで出力

import pickle
import pandas as pd
import tabula

# データ読み込み
with open('seibun_data2.pickle', 'rb') as f:
    dd=pickle.load(f)

print(dd.sort_values(["max","tmax"], ascending=False).reset_index(drop=True))
print()
print(dd.sort_values(["max","tmax"], ascending=False).reset_index(drop=True)[["en","max","tmax","ja"]])
print()
print(dd.sort_values(["max","tmax"], ascending=False).reset_index(drop=True)[["max","tmax","ja"]])

# csvファイルとして外部出力
dd.to_csv("seibun_out01.csv")
dd.to_csv("seibun_out02.csv", index=None)
  • 最後に出力した表
        max   tmax         ja
0   394.000     1h       注射部位
1    26.500     8h         肝臓
2    23.400    48h         脾臓
3    18.200    48h         副腎
4    12.300    48h      卵巣(雌)
5     8.900     2h         血漿
6     5.400     2h         全血
7     3.770    48h    骨髄(大腿骨)
8     2.050     2h         腎臓
9     1.830     2h          肺
10    1.470    48h         小腸
11    1.400     2h         心臓
12    1.370    48h  リンパ節(腸間膜)
13    1.340    48h         大腸
14    1.000    48h        甲状腺
15    0.868     2h       脳下垂体
16    0.815  0.25h     血液:血漿比
17    0.727    48h   リンパ節(下顎)
18    0.687    48h     骨(大腿骨)
19    0.599    48h         膵臓
20    0.456    48h     子宮(女性)
21    0.365    48h         膀胱
22    0.340     2h         胸腺
23    0.320    48h     テスト(悪)
24    0.268     8h         お腹
25    0.264    48h        唾液腺
26    0.253    48h          肌
27    0.250     4h         脊髄
28    0.192    48h          筋
29    0.183    24h    前立腺(男性)
30    0.181    48h       脂肪組織
31    0.138     2h          脳
32    0.112    48h          目

3.3 この章のまとめ

4 今後

  • 今後文書追加するかも、しないかも

5 この文書のチェンジログ

  • 2021/09/02 初版

著者: NM Max

Created: 2021-09-07 火 12:12

Validate

自由研究(新型コロナの遺伝子配列、PCR、ワクチンの遺伝子配列)





自由研究(新型コロナの遺伝子配列、PCR、ワクチンの遺伝子配列)

目次

1 概要

  • もともとは、PCR検査でワクチンの遺伝子は陽性になるのかを調べてみたくなって、やりはじめました
    • 最初PCRで調べてる遺伝子の場所を知らなかったので、それを確認するために以下を行いました。(PCR検査では新型コロナの1/300程度しか調べてません)
      • 最初中国の論文で新型コロナの遺伝子配列が調べられました。これを文字列化
        • ちなみに、1ヶ月かそれ以上前に変異種1万種類以上確認されてます。報道は少ない種類のように報道してますが2週間に1度くらいのペースで変異しまくり。
      • PCR検査のマニュアルが感染研にあるので、それに記載されている遺伝子配列が、中国で初めて確認された新型コロナの遺伝子配列のどこなのかを調べた
      • ファイザーワクチンの遺伝子配列が厚労省の文書に書かれていたので、それを文字列化(画像だったので、OCRで処理。正しく変換できてるかは面倒なので、未確認)
      • PCR検査の検査部位の遺伝子配列が、ファイザーワクチンの遺伝子配列に含まれているか確認した(結果含まれてないようです。)
        • 多少ちがってても増殖できることもあるらしいので、PCR検査で陽性になるかどうかを調べれたわけではありませんが、PCR検査で検査してる部分の遺伝子配列に完全に一致する遺伝子配列は存在してないと思われます。

2 関連文書

3 新型コロナ(一番最初の中国論文の)の遺伝子配列を文字列化して変数に保存

3.1 説明動画


3.2 新型コロナ(一番最初の中国論文の)の遺伝子配列を文字列化して変数に保存をおこなう手順

3.2.1 まず遺伝子配列が記載されているページをChomeで開き、外部ファイルに保存します。

3.2.2 BeautifulSoupが必要なので入ってなかったら入れる

  • Pipでインストールするなら多分以下
pip install beautifulsoup4
  • あるいはUbuntuでパッケージでインストールするなら以下のコマンド
sudo apt install python3-bs4

3.2.3 IPythonの起動

ipython3

or

ipython

3.2.4 データ処理

  • BeautifulSoupと正規表現用のreパッケージ読み込み
from bs4 import BeautifulSoup
import re
  • 先程保存したHTMLファイルを読み込む
soup = BeautifulSoup(open('Severe acute respiratory syndrome coronavirus 2 isolate Wuhan-Hu-1, co - Nucleotide - NCBI.html'), 'html.parser')
  • 遺伝子配列のある部分をクラス指定で取り出す
    • このクラス名で取り出せる事は元のHTMLをChromeで開き、デベロッパーツールで調べておいた
soup.find_all(text=True,class_="ff_line")
  • 上手く取り出せているので、1つめを文字列化してみる
soup.find_all(text=True,class_="ff_line")[0].text
  • 色々不必要な文字列が含まれてるので、小文字のアルファベット以外を除いてみる
re.sub(r"[^a-z]","",soup.find_all(text=True,class_="ff_line")[0].text)
  • mapを利用して、全部の要素に今の処理を実行
list(map(lambda x: re.sub(r"[^a-z]","",x.text),soup.find_all(text=True,class_="ff_line")))
  • 全部の要素に今の処理を行い結合したものを変数xxに保存
xx=''.join(list(map(lambda x: re.sub(r"[^a-z]","",x.text),soup.find_all(text=True,class_="ff_line"))))
  • 作成した遺伝子配列を表示してみる
print(xx)
  • 作成した遺伝子配列の長さを表示してみる
print("len(xx)")
print(len(xx))

3.3 この章のまとめ

  • 新型コロナウィルスの遺伝子配列(一番最初の中国論文)を文字列にして、変数に入れる処理を行なった

4 PCR検査マニュアルにある遺伝子配列を確認その1(感染研・地衛研専用のマニュアル)

4.1 説明動画


4.2 PCR検査マニュアルにある遺伝子配列を確認1 手順

4.2.1 IPythonを起動

ipython3

4.2.2 以下のコマンドを実行し、新型コロナウィルスの中国論文の遺伝子配列を変数に代入

from bs4 import BeautifulSoup
import re
soup = BeautifulSoup(open('Severe acute respiratory syndrome coronavirus 2 isolate Wuhan-Hu-1, co - Nucleotide - NCBI.html'), 'html.parser')
xx=''.join(list(map(lambda x: re.sub(r"[^a-z]","",x.text),soup.find_all(text=True,class_="ff_line"))))
print(len(xx))

4.2.3 逆順にする関数myrevと、ペアの遺伝子配列にする関数myconvを定義

def myrev(s):
    return ''.join(list(reversed(s)))

def myconv(s):
    return s.upper().replace("C","g").replace("G","c").replace("A","t").replace("T","a")

4.2.4 PCRの検査マニュアルに記載されている位置の遺伝子配列の確認(リアルタイムPCRの検査部分を確認) その1

  1. NIID-N2 セット 29125-29144 の範囲表示
    print(xx[29125-1:29144])
    
  2. NIID-N2 セット 29282-29263 の範囲表示
    print(xx[29263-1:29282])
    
    • これを逆順にしてペアの配列を表示
    print(myrev(myconv(xx[29263-1:29282])))
    
  3. NIID-N2 セット 29222-29241 の範囲表示
    print(xx[29222-1:29241])
    
  4. NIID-S ver.2 (S2)セット 24722-24742 の範囲表示
    print(xx[24722-1:24742])
    
  5. NIID-S ver.2 (S2)セット 24870-24851 の範囲表示
    print(xx[24851-1:24870])
    
    • これを逆順にしてペアの配列を表示
    print(myrev(myconv(xx[24851-1:24870])))
    
  6. NIID-S ver.2 (S2)セット 24793-24816 の範囲表示
    print(xx[24793-1:24816])
    

4.2.5 PCRの検査マニュアルに記載されている位置の遺伝子配列の確認(リアルタイムPCRの検査部分を確認) その2

  • re.finditerを使って探索
  1. NIID-N2 セット
    print(list(re.finditer("AAATTTTGGGGACCAGGAAC".lower(),xx)))
    print(list(re.finditer(myconv(myrev("TGGCACCTGTGTAGGTCAAC")).lower(),xx)))
    print(list(re.finditer("ATGTCGCGCATTGGCATGGA".lower(),xx)))
    
  2. NIID-S ver.2 (S2)セット
    print(list(re.finditer("CAGTCAGCACCTCATGGTGTA".lower(),xx)))
    print(list(re.finditer(myconv(myrev("AACCAGTGTGTGCCATTTGA")).lower(),xx)))
    print(list(re.finditer("TGCTCCTGCCATTTGTCATGATGG".lower(),xx)))
    

4.2.6 PCRの検査でチェックしている遺伝子配列の長さ

  • それぞれの長さの表示
print(list(map(lambda x:len(x),["AAATTTTGGGGACCAGGAAC","TGGCACCTGTGTAGGTCAAC","ATGTCGCGCATTGGCATGGA"])))
print(sum(list(map(lambda x:len(x),["AAATTTTGGGGACCAGGAAC","TGGCACCTGTGTAGGTCAAC","ATGTCGCGCATTGGCATGGA"]))))
print(list(map(lambda x:len(x),["CAGTCAGCACCTCATGGTGTA","AACCAGTGTGTGCCATTTGA","TGCTCCTGCCATTTGTCATGATGG"])))
print(sum(list(map(lambda x:len(x),["CAGTCAGCACCTCATGGTGTA","AACCAGTGTGTGCCATTTGA","TGCTCCTGCCATTTGTCATGATGG"]))))

4.3 この章のまとめ

  • 前の章の遺伝子配列で、PCR検査で検査している遺伝子配列を調べてみた(製品によって異る部分を調べているものがあります。)
  • 全長3万弱の遺伝子のほんのちょっとの部分しか調べていないことを確認

5 PCR検査マニュアルにある遺伝子配列を確認その2

5.1 説明動画


5.2 PCR検査マニュアルにある遺伝子配列を確認2 手順

5.2.1 ベースとなる新型コロナの遺伝子配列が旧バージョンなのでそれをダウンロード

5.2.2 IPythonを起動

ipython3

5.2.3 以下のコマンドを実行し、新型コロナウィルスの中国論文の遺伝子配列を変数に代入

  • xxにMN908947.3(最新版)
  • xx2にMN908947.1(旧バージョン)
from bs4 import BeautifulSoup
import re

def myrev(s):
    return ''.join(list(reversed(s)))

def myconv(s):
    return s.upper().replace("C","g").replace("G","c").replace("A","t").replace("T","a")

soup = BeautifulSoup(open('Severe acute respiratory syndrome coronavirus 2 isolate Wuhan-Hu-1, co - Nucleotide - NCBI.html'), 'html.parser')
xx=''.join(list(map(lambda x: re.sub(r"[^a-z]","",x.text),soup.find_all(text=True,class_="ff_line"))))
print(len(xx))

soup2 = BeautifulSoup(open('Wuhan seafood market pneumonia virus isolate Wuhan-Hu-1, complete geno - Nucleotide - NCBI.html'), 'html.parser')
xx2=''.join(list(map(lambda x: re.sub(r"[^a-z]","",x.text),soup2.find_all(text=True,class_="ff_line"))))
print(xx2)
print("len(xx2)")
print(len(xx2))

5.2.4 探索部分を関数に定義

def mycheck(xx,x1="CACATTGGCACCCGCAATC",x2="GAGGAACGAGAAGAGGCTTG",x3="ACTTCCTCAAGGAACAACATTGCCA"):
  s=xx.upper()
  return(list(re.finditer(x1.upper(),s)),list(re.finditer(myconv(myrev(x2.upper())).upper(),s)) ,list(re.finditer(x3.upper(),s)))

def mycheck2(xx):
  return mycheck(xx,"AAATTTTGGGGACCAGGAAC","TGGCAGCTGTGTAGGTCAAC","ATGTCGCGCATTGGCATGGA")

5.2.5 それぞれの長さの表示

  • Nセット
print(list(map(lambda x:len(x),["CACATTGGCACCCGCAATC","GAGGAACGAGAAGAGGCTTG","ACTTCCTCAAGGAACAACATTGCCA"])))
print(sum(list(map(lambda x:len(x),["CACATTGGCACCCGCAATC","GAGGAACGAGAAGAGGCTTG","ACTTCCTCAAGGAACAACATTGCCA"]))))
  • N2セット
print(list(map(lambda x:len(x),["AAATTTTGGGGACCAGGAAC","TGGCAGCTGTGTAGGTCAAC","ATGTCGCGCATTGGCATGGA"])))
print(sum(list(map(lambda x:len(x),["AAATTTTGGGGACCAGGAAC","TGGCAGCTGTGTAGGTCAAC","ATGTCGCGCATTGGCATGGA"]))))

5.2.6 それぞれの長さの全体にしめる割合を確認

  • Nセット
# Nセット
print(len(xx2)/sum(list(map(lambda x:len(x),["CACATTGGCACCCGCAATC","GAGGAACGAGAAGAGGCTTG","ACTTCCTCAAGGAACAACATTGCCA"]))))
  • N2セット
# N2セット
print(len(xx2)/sum(list(map(lambda x:len(x),["AAATTTTGGGGACCAGGAAC","TGGCAGCTGTGTAGGTCAAC","ATGTCGCGCATTGGCATGGA"]))))
  • NセットとN2セット
# NセットとN2セット
print(len(xx2)/(sum(list(map(lambda x:len(x),["AAATTTTGGGGACCAGGAAC","TGGCAGCTGTGTAGGTCAAC","ATGTCGCGCATTGGCATGGA"])))+sum(list(map(lambda x:len(x),["AAATTTTGGGGACCAGGAAC","TGGCAGCTGTGTAGGTCAAC","ATGTCGCGCATTGGCATGGA"])))))

5.2.7 PCRの検査マニュアルに記載されている位置の遺伝子配列の確認(リアルタイムPCRの検査部分を確認) その1

  • N1セットのチェック
    • なぜか、1つ場所がズレてる。原因は不明。遺伝子配列は存在してる
# 28723-28741
# 28850-28831
# 28770-28794
mycheck(xx2)
  • N2セットのチェック
    • なぜか、1つ場所がズレてる。原因は不明。遺伝子配列は存在してる
# 29142-29161
# 29299-29280
# 29239-29258
mycheck2(xx2)

5.3 この章のまとめ

  • 通常のPCR検査のマニュアルにあるチェック部分の遺伝子配列を調べた

6 ファイザーワクチンのmRNAの遺伝子配列を文字列化して変数に格納

6.1 説明動画


6.2 ファイザーワクチンのmRNAの遺伝子配列を文字列化して変数に格納 手順

6.2.1 ファイザーの遺伝子配列情報が記載されてる書類をダウンロード

  • 審議結果報告書(ファイザーの遺伝子配列情報が記載されてる) https://www.mhlw.go.jp/content/10601000/000739089.pdf
  • Yが特殊で”一メチルシュウドウウリジン”というのがいれられていて、通常のmRNAではない。長寿命になるように工夫されている。(報道のように普通のmRNAじゃなく、長寿命化)

6.2.2 PDFファイルから、遺伝子情報のあるページを抜き出し

  • 000739089-04.ppm 000739089-05.ppm 000739089-06.ppm のファイルが生成される。画像フォーマットはppm
pdftoppm -l 6 -f 4 000739089.pdf 000739089

6.2.3 画像ファイルから余計な部分を除去

  • 私はGIMPを用いて切り抜きしました。他の画像処理ツールでもOK

6.2.4 OCRソフト( tesseract )で文字列化

  • psmオプションつけないと、列毎の文字列になってしまい、後処理が面倒になる
  • 000739089-04.txt 000739089-05.txt 000739089-06.txt という3つのテキストファイルが生成される。
tesseract -l eng  --psm 4 000739089-04.png 000739089-04
tesseract -l eng  --psm 4 000739089-05.png 000739089-05
tesseract -l eng  --psm 4 000739089-06.png 000739089-06

6.2.5 Python起動

ipython3

or

ipython

6.2.6 OCRソフト( tesseract )で文字列化

import re
yy=""
with open("000739089-04.txt") as f:
    yy+=re.sub(r"[^a-zA-Z]","",f.read())
with open("000739089-05.txt") as f:
    yy+=re.sub(r"[^a-zA-Z]","",f.read())
with open("000739089-06.txt") as f:
    yy+=re.sub(r"[^a-zA-Z]","",f.read())

6.2.7 文字列の確認

  1. 文字列を表示してみる(確認)
    print(yy)
    
  2. 文字列に含まれている文字を確認(確認)
    print(set(yy))
    
  3. 文字列の長さを確認(確認)
    • 文書によると4284
    # 4284
    print(len(yy))
    

6.3 この章のまとめ

  • ファイザーワクチンのmRNAの遺伝子配列を文字列化

7 ファイザーワクチンのmRNAの遺伝子配列にPCR検査している遺伝子配列が含まれているか確認

7.1 説明動画


7.2 ファイザーワクチンのmRNAの遺伝子配列にPCR検査している遺伝子配列が含まれているか確認 手順

7.2.1 Pythonの対話環境起動

ipython3

or

ipython

7.2.2 新型コロナの遺伝子配列の読み込み,今まで使った関数の定義

from bs4 import BeautifulSoup
import re

soup = BeautifulSoup(open('Severe acute respiratory syndrome coronavirus 2 isolate Wuhan-Hu-1, co - Nucleotide - NCBI.html'), 'html.parser')
xx=''.join(list(map(lambda x: re.sub(r"[^a-z]","",x.text),soup.find_all(text=True,class_="ff_line"))))
print(len(xx))

soup2 = BeautifulSoup(open('Wuhan seafood market pneumonia virus isolate Wuhan-Hu-1, complete geno - Nucleotide - NCBI.html'), 'html.parser')
xx2=''.join(list(map(lambda x: re.sub(r"[^a-z]","",x.text),soup2.find_all(text=True,class_="ff_line"))))

yy=""
with open("000739089-04.txt") as f:
    yy+=re.sub(r"[^a-zA-Z]","",f.read())
with open("000739089-05.txt") as f:
    yy+=re.sub(r"[^a-zA-Z]","",f.read())
with open("000739089-06.txt") as f:
    yy+=re.sub(r"[^a-zA-Z]","",f.read())

def myrev(s):
    return ''.join(list(reversed(s)))

def myconv(s):
    return s.upper().replace("C","g").replace("G","c").replace("A","t").replace("T","a")

def mycheck(xx,x1="CACATTGGCACCCGCAATC",x2="GAGGAACGAGAAGAGGCTTG",x3="ACTTCCTCAAGGAACAACATTGCCA"):
  s=xx.upper()
  return(list(re.finditer(x1.upper(),s)),list(re.finditer(myconv(myrev(x2.upper())).upper(),s)) ,list(re.finditer(x3.upper(),s)))

def mycheck1(xx):
  return mycheck(xx,x1="CACATTGGCACCCGCAATC",x2="GAGGAACGAGAAGAGGCTTG",x3="ACTTCCTCAAGGAACAACATTGCCA")

def mycheck2(xx):
  return mycheck(xx,"AAATTTTGGGGACCAGGAAC","TGGCAGCTGTGTAGGTCAAC","ATGTCGCGCATTGGCATGGA")

def mycheck01(xx):
  return mycheck(xx,"AAATTTTGGGGACCAGGAAC","TGGCACCTGTGTAGGTCAAC","ATGTCGCGCATTGGCATGGA")

def mycheck02(xx):
  return mycheck(xx,"CAGTCAGCACCTCATGGTGTA","AACCAGTGTGTGCCATTTGA","TGCTCCTGCCATTTGTCATGATGG")
  • check1(通常のPCR検査)とcheck02(研究所用)は同じ遺伝子配列を調べているようです。

7.2.3 チェック関数の動作確認

print(mycheck01(xx))
print(mycheck02(xx))
print(mycheck1(xx))
print(mycheck2(xx))

7.2.4 ワクチンの遺伝子配列のYの文字をTに変換

  • Yが特殊で”一メチルシュウドウウリジン”なので、Tに変更して別変数に入れる
yyy=yy.replace("Y","T")

7.2.5 ワクチンの遺伝子配列にPCR検査で調べている遺伝子配列があるかチェック

print(mycheck01(yyy))
print(mycheck02(yyy))
print(mycheck1(yyy))
print(mycheck2(yyy))
  • 逆順にして確認
print(mycheck01(myrev(yyy)))
print(mycheck02(myrev(yyy)))
print(mycheck1(myrev(yyy)))
print(mycheck2(myrev(yyy)))

7.3 チェック結果

  • ファイザーワクチンのmRNAの遺伝子配列内にPCR検査で調べている遺伝子配列は見つからなかった
    • 多少ずれてても増幅すると聞いているので、このチェックがPCR検査で陽性にならないかどかのチェックにはなってないと思います。
    • 新型コロナの遺伝子の一部が含まれてると聞いていたのに、なぜ含まれないのか、理由は不明。
    • PCR検査で陽性にならないように、同義の遺伝子配列にする等の工夫がなされてるのかも?そこ調べてません。
      • 同義置換して一致するか確認してみるのも面白そう
    • ワクチンの遺伝子配列が正しくOCRで変換できてるかは、面倒だったので未確認なので、そこらあるかも

7.4 この章のまとめ

  • ファイザーワクチンのmRNAの遺伝子配列内にPCR検査で調べている遺伝子配列そのものは見つからなかった

8 PCR検査で調べている遺伝子配列が 新型コロナの MN908947.3(最新バージョン),MN908947.1(昔のバージョン)に存在するか確認

8.1 説明動画


8.2 PCR検査で調べている遺伝子配列が 新型コロナの MN908947.3(最新バージョン),MN908947.1(昔のバージョン)に存在するか確認 の手順

  • 前の章のプログラムを動かして準備完了

8.2.1 チェック関数の動作確認

  1. xxにMN908947.3(最新版)も前の章やったが、再度やっておく
    print(mycheck01(xx))
    print(mycheck02(xx))
    print(mycheck1(xx))
    print(mycheck2(xx))
    
  2. xx2にMN908947.1(旧バージョン)
    • check01の2番目のTGGCACCTGTGTAGGTCAACがマッチしてない。MN908947.1(旧バージョン)にはこの遺伝子配列そのものは無いようだ。
    print(mycheck01(xx2))
    print(mycheck02(xx2))
    print(mycheck1(xx2))
    print(mycheck2(xx2))
    

8.3 この章のまとめ

  • 研究所でのPCR検査で用いる遺伝子配列群1の終了用の遺伝子配列が、新型コロナの遺伝子配列 MN908947.1(旧バージョン)に含まれていない事を確認した。
    • 研究所用のマニュアルの遺伝子配列をこれに選択した理由があるはずだが、理由は不明。
  • 通常検査用のプライマー配列そのものは、新型コロナの遺伝子配列 MN908947.3(最新バージョン)には含まれていない。しかし、マニュアルには検出感度に問題無いとの記載あり。
    • 遺伝子配列が多少異なっても増幅するとは聞いていたが、こちらも最新バージョンの遺伝子配列をベースにせずに、旧バージョンの遺伝子配列からプライマーを決めた理由は良くわからない。

9 ファイザーワクチンのmRNAの遺伝子配列にPCR検査している遺伝子配列に似てる遺伝子配列が含まれているか確認1

  • 審議結果報告書(ファイザーの遺伝子配列情報が記載されてる) https://www.mhlw.go.jp/content/10601000/000739089.pdf
  • PCR検査で調べている遺伝子配列と1文字違いの遺伝子配列がファイザーの遺伝子配列に含まれているか調べてみる

9.1 説明動画


9.2 ファイザーワクチンのmRNAの遺伝子配列にPCR検査している遺伝子配列に似てる遺伝子配列が含まれているか確認1 の手順

  • Pythonの対話環境を起動して以下を実行
from bs4 import BeautifulSoup
import re

# 新型コロナの遺伝子配列読み込み 変数xx MN908947.3 最新バージョン
soup = BeautifulSoup(open('Severe acute respiratory syndrome coronavirus 2 isolate Wuhan-Hu-1, co - Nucleotide - NCBI.html'), 'html.parser')
xx=''.join(list(map(lambda x: re.sub(r"[^a-z]","",x.text),soup.find_all(text=True,class_="ff_line"))))
print(len(xx))

# 新型コロナの遺伝子配列読み込み 変数xx2 MN908947.1 旧タイプ
soup2 = BeautifulSoup(open('Wuhan seafood market pneumonia virus isolate Wuhan-Hu-1, complete geno - Nucleotide - NCBI.html'), 'html.parser')
xx2=''.join(list(map(lambda x: re.sub(r"[^a-z]","",x.text),soup2.find_all(text=True,class_="ff_line"))))

# ファイザーワクチンの遺伝子配列を 変数yyに
yy=""
with open("000739089-04.txt") as f:
    yy+=re.sub(r"[^a-zA-Z]","",f.read())
with open("000739089-05.txt") as f:
    yy+=re.sub(r"[^a-zA-Z]","",f.read())
with open("000739089-06.txt") as f:
    yy+=re.sub(r"[^a-zA-Z]","",f.read())

# ファイザーワクチンの遺伝子配列を 変数yyyに("一メチルシュウドウウリジン" YをTに変換)
yyy=yy.replace("Y","T")

# 関数群
# 文字列を逆順に変換
def myrev(s):
    return ''.join(list(reversed(s)))

# CとG、AとTを入替え
def myconv(s):
    return s.upper().replace("C","g").replace("G","c").replace("A","t").replace("T","a")

# チェック関数
def mycheck(xx,x1="CACATTGGCACCCGCAATC",x2="GAGGAACGAGAAGAGGCTTG",x3="ACTTCCTCAAGGAACAACATTGCCA"):
  s=xx.upper()
  return(list(re.finditer(x1.upper(),s)),list(re.finditer(myconv(myrev(x2.upper())).upper(),s)) ,list(re.finditer(x3.upper(),s)))

# チェック関数1 通常のPCR検査で調べる遺伝子配列群1
def mycheck1(xx):
  return mycheck(xx,x1="CACATTGGCACCCGCAATC",x2="GAGGAACGAGAAGAGGCTTG",x3="ACTTCCTCAAGGAACAACATTGCCA")

# チェック関数2 通常のPCR検査で調べる遺伝子配列群2
def mycheck2(xx):
  return mycheck(xx,"AAATTTTGGGGACCAGGAAC","TGGCAGCTGTGTAGGTCAAC","ATGTCGCGCATTGGCATGGA")

# チェック関数01 研究所でのPCR検査で用いる遺伝子配列群1
def mycheck01(xx):
  return mycheck(xx,"AAATTTTGGGGACCAGGAAC","TGGCACCTGTGTAGGTCAAC","ATGTCGCGCATTGGCATGGA")

# チェック関数02 研究所でのPCR検査で用いる遺伝子配列群2
def mycheck02(xx):
  return mycheck(xx,"CAGTCAGCACCTCATGGTGTA","AACCAGTGTGTGCCATTTGA","TGCTCCTGCCATTTGTCATGATGG")

# 元の文字列 s の index 番目の文字列を newstringに置き換える関数 
def myreplace(s,index,newstring):
  return s[:index] + newstring + s[index + 1:]

# 元の文字列 s の1文字を"."に置き換えて出来る文字列を生成する関数
def mymake1replace(s):
  ans=[]
  for i in range(len(s)):      
      ans.append(myreplace(s,i,"."))
  return ans

# mycheckv2で利用する関数
def bmycheckv2(tt,ss):
  return (tt,list(re.finditer(tt,ss)))

# mycheckv2で利用する関数
def brmycheckv2(tt,ss):
  ttt=myrev(myconv(tt).upper())
  return (ttt,list(re.finditer(ttt,ss)))

# 遺伝子配列sに tという遺伝子配列、tの1文字違いの文字列が含まれているか検索する関数
def mycheckv2(s,t):
  ss=s.upper()
  tt=t.upper()
  ans1=[]
  ans2=[]
  for i in mymake1replace(tt):
    t1,t2 = bmycheckv2(i,ss)
    if len(t2)!=0: 
      ans1.append((t1,t2))
    tt1,tt2 = brmycheckv2(i,ss)
    if len(tt2)!=0: 
      ans1.append((tt1,tt2))
  return (ans1,ans2)

#ヒットしない文字列を filter


cs1=("CACATTGGCACCCGCAATC","GAGGAACGAGAAGAGGCTTG","ACTTCCTCAAGGAACAACATTGCCA")
cs2=("AAATTTTGGGGACCAGGAAC","TGGCAGCTGTGTAGGTCAAC","ATGTCGCGCATTGGCATGGA")
cs3=("AAATTTTGGGGACCAGGAAC","TGGCACCTGTGTAGGTCAAC","ATGTCGCGCATTGGCATGGA")
cs4=("CAGTCAGCACCTCATGGTGTA","AACCAGTGTGTGCCATTTGA","TGCTCCTGCCATTTGTCATGATGG")

### 動作確認
# 研究所用の検査マニュアル 新型コロナの遺伝子配列読み込み 変数xx MN908947.3 最新バージョン
for i in cs3:
  print("########## "+i)
  print(mycheckv2(xx,i))
  print()
  print()

for i in cs4:
  print("########## "+i)
  print(mycheckv2(xx,i))
  print()
  print()

# 通常の検査マニュアル 新型コロナの遺伝子配列読み込み 変数xx2 MN908947.1 旧バージョン
for i in cs1:
  print("########## "+i)
  print(mycheckv2(xx2,i))
  print()
  print()

for i in cs2:
  print("########## "+i)
  print(mycheckv2(xx2,i))
  print()
  print()

# 2番目のプライマーが発見出来ない組み合わせ # cs2 通常の検査用マニュアル
for i in cs2:
  print("########## "+i)
  print(mycheckv2(xx,i))
  print()
# 
# 2番目のプライマーが発見出来ない組み合わせ # cs3 研究所用のマニュアル

for i in cs3:
  print("########## "+i)
  print(mycheckv2(xx2,i))
  print()


for i in cs1:
    print("########## "+i)
    print(mycheckv2(yyy,i))
    print()
    print()

for i in cs2:
    print("########## "+i)
    print(mycheckv2(yyy,i))
    print()
    print()

for i in cs3:
    print("########## "+i)
    print(mycheckv2(yyy,i))
    print()
    print()

for i in cs4:
    print("########## "+i)
    print(mycheckv2(yyy,i))
    print()
    print()

9.3 この章のまとめ

  • PCR検査で調べている遺伝子配列と1文字違いの遺伝子配列もファイザーの遺伝子配列から見つけることは出来なかった。
    • 元のOCRでの変換が正しいとして

10 今後

  • 今後文書追加するかも、しないかも

11 この文書のチェンジログ

  • 2021/08/16 初版
  • 2021/08/17 PCR検査マニュアルにある遺伝子配列を確認その1(感染研・地衛研専用のマニュアル) の章,PCR検査マニュアルにある遺伝子配列を確認その2 の章を追加
  • 2021/08/18 PCR検査マニュアルにある遺伝子配列を確認その2 の章を修正
  • 2021/08/18 ファイザーワクチンのmRNAの遺伝子配列を文字列化して変数に格納 の章追加
  • 2021/08/18 ファイザーワクチンのmRNAの遺伝子配列にPCR検査している遺伝子配列が含まれているか確認 の章追加
  • 2021/09/03 PCR検査で調べている遺伝子配列が 新型コロナの MN908947.1(昔のバージョン)に存在するか確認 の章, ファイザーワクチンのmRNAの遺伝子配列にPCR検査している遺伝子配列に似てる遺伝子配列が含まれているか確認1 の章追加

著者: NM Max

Created: 2021-09-05 日 09:21

Validate

CMake入門

CMake入門

目次

1 概要

3 CMakeのインストール

  • Download https://cmake.org/download/ から、お使いのOS用のものをダウンロードしてインストール
    • Ubuntuなら以下のコマンドでインストール可能
sudo apt install cmake
  • この動画のシリーズではhttps://youtu.be/SWNKrXFkJpoで作成したDocker Imageを利用していきます。(CMakeやC++コンパイラ、その他必要なものはいっているため)
    • どのOSでもDockerを利用して同じ操作可能
    • ご自分のOSに直接CMakeをインストールして、Docker使わずやってもOK。(ほぼ同じ手順となります。)

3.1 説明動画


3.2 この章のまとめ

  • CMakeのインストール方法について説明
    • ダウンロードサイトから、ダウンロードしてインストール
  • どのOSでも共通で利用できる環境をDockerで解説してきます。
  • Dockerの環境の準備が面倒なら、必要なツールをインストールして直接やってもよい

4 C++ソースから実行ファイルの作成(シンプル)

4.1 以下の操作を行っている動画


4.2 C++ソースから実行ファイルの作成の手順

4.2.1 Dockerイメージの起動

  • ホストの/work/CMakeと、Dockerイメージ内の/home/user/Cディレクトリを共有するコマンドで起動
    • Dockerイメージはhttps://youtu.be/SWNKrXFkJpoで作成したものを利用してます。Docker使わず、直接ご利用のOSにCMakeやコンパイラ入れてやってもOK
docker run -it --rm -v /work/CMake:/home/user/C mypybind11

4.2.2 C++ソースの用意

  • Hello Worldと出力する例を作成
  • ファイル名はhelloworld.cpp
#include <iostream>

int main() {
  std::cout << "Hello world!" << std::endl;
  return 0;
}

4.2.3 CMakeLists.txtの用意

cmake_minimum_required(VERSION 3.4...3.18)
project(helloworld LANGUAGES CXX VERSION 1.0)
add_executable(helloworld helloworld.cpp)

4.2.4 コンパイル

  • ビルドするディレクトリに移動
mkdir build
cd build
  • cmakeを実行
cmake ..
  • GNU Makeを実行しコンパイル
make

4.2.5 動作確認

./helloworld

4.3 この章のまとめ

  • 簡単なC++のソースファイルから実行ファイルをコンパイルして動かしてみた

5 C++でライブラリの作成

5.1 以下の操作を行っている動画


5.2 C++でライブラリの作成の手順

5.2.1 Dockerイメージの起動

  • ホストの/work/CMakeと、Dockerイメージ内の/home/user/Cディレクトリを共有するコマンドで起動
    • Dockerイメージはhttps://youtu.be/SWNKrXFkJpoで作成したものを利用してます。Docker使わず、直接ご利用のOSにCMakeやコンパイラ入れてやってもOK
docker run -it --rm -v /work/CMake:/home/user/C mypybind11

5.2.2 C++ソースの用意

  • Hello Worldと出力する例を作成
  • ファイル名はmyadd.hpp
int myadd(const int &i, const int &j);
  • ファイル名はmyadd.cpp
    • 2つの引数をうけとり、足して返す関数
int myadd(const int &i, const int &j) {
  return i+j;
}

5.2.3 CMakeLists.txtの用意

cmake_minimum_required(VERSION 3.4...3.18)
project(myadd LANGUAGES CXX)
add_library(myadd myadd.cpp myadd.hpp)

5.2.4 コンパイル

  • ビルドするディレクトリに移動
mkdir build
cd build
  • cmakeを実行
cmake ..
  • GNU Makeを実行しコンパイル
make

5.2.5 コンパイル2 動的ライブラリ作成

  1. 方法1
    • あるいは cmake .. でも動的ライブラリを生成したい場合CMakeLists.txtのadd_libraryを以下のようにしても良い
      • 静的ライブラリの場合は SHARED を STATIC におきかえ
    add_library(myadd SHARED myadd.cpp myadd.hpp)
    
  2. 方法2-1
    cmake -DBUILD_SHARED_LIBS=TRUE ..
    
  3. 方法2-2
    • add_library(myadd myadd.cpp myadd.hpp) の行の前にsetで、環境変数をセット
    set(BUILD_SHARED_LIBS TRUE)
    add_library(myadd myadd.cpp myadd.hpp)
    

5.2.6 動作確認

  • 動作確認は省略します。このライブラリを利用する実行ファイルを作成してみてください。

5.3 この章のまとめ

  • 簡単なC++のソースファイルからライブラリをコンパイルして生成した。

6 C++でライブラリを作成し、それを利用した実行ファイルも作成

6.1 以下の操作を行っている動画


6.2 C++でライブラリの作成の手順

6.2.1 Dockerイメージの起動

  • ホストの/work/CMakeと、Dockerイメージ内の/home/user/Cディレクトリを共有するコマンドで起動
    • Dockerイメージはhttps://youtu.be/SWNKrXFkJpoで作成したものを利用してます。Docker使わず、直接ご利用のOSにCMakeやコンパイラ入れてやってもOK
docker run -it --rm -v /work/CMake:/home/user/C mypybind11

6.2.2 C++ソースの用意

  • 前の章のファイルに追加して、main.cppを追加
#include "myadd.hpp"
#include <iostream>

int main() {
  std::cout << myadd(1,2) << std::endl;
  return 0;
}

6.2.3 CMakeLists.txtの作成

cmake_minimum_required(VERSION 3.4...3.18)
project(myadd LANGUAGES CXX)
add_library(myadd SHARED myadd.cpp myadd.hpp)
add_executable(main main.cpp)
target_link_libraries(main myadd)

6.2.4 コンパイル

  • ビルドするディレクトリでコンパイル
  • cmakeを実行
cmake ..
  • GNU Makeを実行しコンパイル
make

6.2.5 動作確認

./main

6.3 この章のまとめ

  • 前章のライブラリをリンクして実行ファイルを作成するように、ファイルを追加したり、修正した

7 外部にあるライブラリをリンクして実行ファイルを作成1

7.1 以下の操作を行っている動画


7.2 外部にあるライブラリをリンクして実行ファイルを作成1 の手順

7.2.1 Dockerイメージの起動

  • ホストの/work/CMakeと、Dockerイメージ内の/home/user/Cディレクトリを共有するコマンドで起動
    • Dockerイメージはhttps://youtu.be/SWNKrXFkJpoで作成したものを利用してます。Docker使わず、直接ご利用のOSにCMakeやコンパイラ入れてやってもOK
docker run -it --rm -v /work/CMake:/home/user/C mypybind11

7.2.2 C++ソースの用意

  • 前の章のmain.cppはそのまま利用

7.2.3 CMakeLists.txtの作成

cmake_minimum_required(VERSION 3.4...3.18)
project(ex004 LANGUAGES CXX VERSION 1.0)
link_directories(../ex003/build/)
find_library(myadd NAMES myadd PATHS ../ex003/build REQUIRED)
message(${myadd})
add_executable(ex004 main.cpp)
include_directories(../ex003/)
target_link_libraries(ex004 PUBLIC myadd)
#set(CMAKE_VERBOSE_MAKEFILE TRUE)

7.2.4 コンパイル

  • ビルドするディレクトリに移動
mkdir build
cd build
  • cmakeを実行
cmake ..
  • GNU Makeを実行しコンパイル
make

7.2.5 動作確認

./main

7.3 この章のまとめ

  • 外部の自作ライブラリを利用して、実行ファイルを作成するのをやってみた。(インクルードパスの設定と、外部ライブラリの指定)

8 外部にあるライブラリをリンクして実行ファイルを作成2

  • mライブラリを使う例
  • Dockerイメージはhttps://youtu.be/SWNKrXFkJpoで作成したものを利用してます。Docker使わず、直接ご利用のOSにCMakeやコンパイラ入れてやってもOK

8.1 以下の操作を行っている動画


8.2 外部にあるライブラリをリンクして実行ファイルを作成2 の手順

  • C++ソース example.cpp
#include <cmath>
#include <iostream>

int main() {
  std::cout << "sin(1)=" << sin(1) << std::endl;
  std::cout << "sin(0)=" << sin(0) << std::endl;
  std::cout << "cos(1)=" << cos(1) << std::endl;
  std::cout << "cos(0)=" << cos(0) << std::endl;
  return 0;
}
  • CMakeの設定ファイル CMakeLists.txt
cmake_minimum_required(VERSION 3.4...3.18)
project(ex006-01 LANGUAGES CXX VERSION 1.0)
find_library(m NAMES m REQUIRED)
message(${m})
add_executable(ex006-01 example.cpp)
target_link_libraries(ex006 PUBLIC m)
#set(CMAKE_VERBOSE_MAKEFILE TRUE)
  • コンパイルは前章と同じ手順

8.3 この章のまとめ

  • mライブラリを使う例をやってみた

9 外部にあるライブラリをリンクして実行ファイルを作成2

  • mライブラリを使う例
  • Dockerイメージはhttps://youtu.be/SWNKrXFkJpoで作成したものを利用してます。Docker使わず、直接ご利用のOSにCMakeやコンパイラ入れてやってもOK

9.1 以下の操作を行っている動画


9.2 外部にあるライブラリをリンクして実行ファイルを作成2 の手順

  • C++ソース example.cpp
#include <cmath>
#include <iostream>

int main() {
  std::cout << "sin(1)=" << sin(1) << std::endl;
  std::cout << "sin(0)=" << sin(0) << std::endl;
  std::cout << "cos(1)=" << cos(1) << std::endl;
  std::cout << "cos(0)=" << cos(0) << std::endl;
  return 0;
}
  • CMakeの設定ファイル CMakeLists.txt
cmake_minimum_required(VERSION 3.4...3.18)
project(ex006-01 LANGUAGES CXX VERSION 1.0)
find_library(m NAMES m REQUIRED)
message(${m})
add_executable(ex006-01 example.cpp)
target_link_libraries(ex006 PUBLIC m)
#set(CMAKE_VERBOSE_MAKEFILE TRUE)
  • コンパイルは前章と同じ手順

9.3 この章のまとめ

  • mライブラリを使う例をやってみた

10 外部にあるライブラリをリンクして実行ファイルを作成3

  • OpenCVライブラリを使う例
  • Dockerイメージはhttps://youtu.be/SWNKrXFkJpoで作成したものを利用してます。Docker使わず、直接ご利用のOSにCMakeやコンパイラ入れてやってもOK

10.1 以下の操作を行っている動画


10.2 外部にあるライブラリをリンクして実行ファイルを作成3 の手順

10.2.1 事前準備

  • OpenCVライブラリのインストール
    • 相当時間かかります。
sudo apt update
sudo apt install libopencv-dev 

10.2.2 C++ソース example.cpp 作成

  • 実行時のカレントディレクトリにある1.jpgを読み込んで、2.pngとして書き出すプログラム
#include <opencv2/opencv.hpp>
int main()
{
  cv::Mat image = cv::imread( "1.jpg");
  cv::imwrite("2.png",image);
  return 0;
}

10.2.3 CMakeの設定ファイル CMakeLists.txt 作成

cmake_minimum_required(VERSION 3.4...3.18)
project(ex006-2 LANGUAGES CXX VERSION 1.0)
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
message(${OpenCV_INCLUDE_DIRS})
add_executable(ex006-2 example.cpp)
target_link_libraries( ex006-2 ${OpenCV_LIBS} )
#set(CMAKE_VERBOSE_MAKEFILE TRUE)
  • コンパイルは前章と同じ手順

10.3 この章のまとめ

  • OpenCVライブラリを使う例をやってみた

11 外部にあるライブラリをリンクして実行ファイルを作成4

11.1 以下の操作を行っている動画


11.2 外部にあるライブラリをリンクして実行ファイルを作成4 の手順

11.2.1 装備されているリストを確認

cmake --help-module-list

11.2.2 C++ソース example.cpp 作成

11.2.3 CMakeの設定ファイル CMakeLists.txt 作成

cmake_minimum_required(VERSION 3.4...3.18)
project(ex006-3 LANGUAGES CXX VERSION 1.0)
find_package (Python COMPONENTS Development REQUIRED )
include_directories( ${Python_INCLUDE_DIRS} )
message(${Python_INCLUDE_DIRS})
add_executable(ex006-3 example.cpp)
target_link_libraries( ex006-3 ${Python_LIBRARIES} )
#set(CMAKE_VERBOSE_MAKEFILE TRUE)
#set(CMAKE_VERBOSE_MAKEFILE TRUE)

  • コンパイルは前章と同じ手順

11.3 この章のまとめ

  • 標準装備のライブラリを使う例をやってみた
    • ここではPython3

12 C++の指定(C++11,C++14,C++17,C++20,C++23等)

12.1 CやC++の指定方法

12.1.1 設定例

set(CMAKE_CXX_STANDARD 14) # C++14
set(CMAKE_CXX_STANDARD_REQUIRED ON) # 満たせないならエラーに
set(CMAKE_CXX_EXTENSIONS OFF) # コンパイラの独自拡張をOFFに

12.1.2 注意点

  • project(XXX LANGUAGES CXX VERSION 0.01) という記述の前に上記の設定を行う必要あり。
    • 言語指定する前に設定しておく必要あり

12.1.3 備考

  • 設定ファイル内で指定しなくとも、cmake実行する時に環境変数を設定してもOK

12.2 この章のまとめ

  • C++14やC++17等が必要なときの設定方法

13 CやC++のコンパイラー指定

13.1 以下の操作を行っている動画


13.2 CやC++のコンパイラー指定

13.2.1 設定例1

  • PATHが通っているところから探してくれる
set(CMAKE_C_COMPILER    "clang")
set(CMAKE_CXX_COMPILER  "clang++")

13.2.2 設定例2

  • フルパスで指定
set(CMAKE_C_COMPILER    "/usr/bin/clang")
set(CMAKE_CXX_COMPILER  "/usr/bin/clang++")

13.2.3 注意点

  • project(XXX LANGUAGES CXX VERSION 0.01) という記述の前に上記の設定を行う必要あり。
    • 言語指定する前に設定しておく必要あり

13.2.4 備考

  • 設定ファイル内で指定しなくとも、cmake実行する時に環境変数を設定してもOK

13.3 この章のまとめ

  • clang++やclang等デフォルトで選ばれるコンパイラ以外を選択したい場合の設定方法

14 今後

  • 今後も文書追加していきます。

15 この文書のチェンジログ

  • 2021/05/17 初版
  • 2021/05/20 外部にあるライブラリをリンクして実行ファイルを作成1までの章かなり修正
  • 2021/05/21 C++の指定(C++11,C++14,C++17,C++20,C++23等) の章、 CやC++のコンパイラー指定 の章追加
  • 2021/05/24 外部にあるライブラリをリンクして実行ファイルを作成1の章追加
  • 2021/05/25 外部にあるライブラリをリンクして実行ファイルを作成2から4の章追加

著者: NM Max

Created: 2021-05-26 水 04:21

Validate

Mediapipeことはじめ

mediapipeことはじめ

1 概要

  • 瞳検出、Dlibよりも細かい顔ランドマーク検出、体のボーン検出など、相当良さげ

3 インストール(Python)

  • Pythonをインストールしてから、pip install mediapipeで、Pythonから使えるようになる(Linux,Windows,Mac等)

3.1 以下の操作を行っている動画


3.2 インストール(Python) する手順

  • Pythonがインストールされてて、pipあるいはpip3が使える環境で以下を実行
  • virtualenv で作成した方が良いかも。動画では virtualenv mediapipeしてから以下を行なった。
    • ipythonも追加でインストール
pip install mediapipe
or
pip3 install mediapipe

3.3 この章のまとめ

  • Python用のMediaPipeをインストール

4 顔のランドマーク(Python)検出

  • Pythonをインストールしてから、pip install mediapipeで、Pythonから使えるようになる(Linux,Windows,Mac等)

4.1 以下の操作を行っている動画


4.2 顔のランドマーク(Python)検出 する手順

  • MediaPipe Face Mesh https://google.github.io/mediapipe/solutions/face_mesh にあるサンプルソースを修正した
    • # For webcam input: までをコピペ
    • globを利用してカレントディレクトリにあるjpgファイルに対して処理
    • 元々は/tmpディレクトリに結果を書き出すが、ここでは、表示するように修正(オリジナルと、結果)
  • MediaPipe Face Mesh Colab https://mediapipe.page.link/face_mesh_py_colab もわかりやすい
  • 画像としては、パブリックドメインの”Yukichi_Fukuzawa_1891.png”File:Yukichi_Fukuzawa_1891.jpgを利用。他のファイルでもOK
  • ランドマークの描画の色がわかりにくいので、赤に変更するオプション追加
import cv2
import mediapipe as mp
import glob
mp_drawing = mp.solutions.drawing_utils
mp_face_mesh = mp.solutions.face_mesh

#file_list=["radu-florin-JyVcAIUAcPM-unsplash_small.jpg"]
file_list=glob.glob('*.jpg')

# For static images:
#drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=1)
drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=1, color=(0, 0, 255))
with mp_face_mesh.FaceMesh(
    static_image_mode=True,
    max_num_faces=1,
    min_detection_confidence=0.5) as face_mesh:
  for idx, file in enumerate(file_list):
    image = cv2.imread(file)
    cv2.imshow('org', image)
    # Convert the BGR image to RGB before processing.
    results = face_mesh.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))

    # Print and draw face mesh landmarks on the image.
    if not results.multi_face_landmarks:
      continue
    annotated_image = image.copy()
    for face_landmarks in results.multi_face_landmarks:
      print('face_landmarks:', face_landmarks)
      mp_drawing.draw_landmarks(
	  image=annotated_image,
	  landmark_list=face_landmarks,
	  connections=mp_face_mesh.FACE_CONNECTIONS,
	  landmark_drawing_spec=drawing_spec,
	  connection_drawing_spec=drawing_spec)
    cv2.imshow('result', annotated_image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    #cv2.imwrite('/tmp/annotated_image' + str(idx) + '.png', annotated_image)

4.3 この章のまとめ

  • Python用のMediaPipeで顔のランドマーク(Python)検出を行った。

5 今後

  • 今後も文書追加していきます。

6 この文書のチェンジログ

  • 2021/02/19 初版
  • 2021/05/17 長期放置の後、修正、追加

著者: NM Max

Created: 2021-05-20 木 05:49

Validate

pybind11ことはじめ

pybind11ことはじめ

目次

1 概要

  • C++11をPythonで利用しやすくするツールの一種
    • ヘッダーファイルのみで構成されている
    • DlibのPythonとの連携で使われていて調べた

2 関連文書

3 環境構築(Dockerを利用して)

  • 色々なOS(Windows,Mac,Linux)で、同じ操作で出来るように、Dockerを利用して環境を作る
  • Docker無しで、必要なツールをインストールして直接やってもOK(その場合この章はスキップ)
    • 必要なツール
      • C++のコンパイラ
      • CMake
      • GNU Make
      • Python とヘッダーファイル、ライブラリファイル
      • Python のライブラリ
        • pip
        • pybind11
    • あった方が良いもの
      • git
      • Python のライブラリ
        • ipython

3.1 以下の操作を行っている動画


3.2 環境構築(Dockerを利用して)の手順

3.2.1 事前準備

  • OSに依存せずに同じ環境作れるようにDockerを利用してこの動画シリーズやっていきます。
  • まずDockerをインストールしてください。
    • 私はUbuntu20.04の環境で行って行きます。DockerはWindowsやMacでも使えるので、他のOSでもDockerを入れれば同じ手順で出来ます。
  • Docker等でUbuntuの環境を用意
    • Python,Python-dev,c++コンパイラー,cmake,git等必要なパッケージインストール
  • 以下のコマンドで、共有用のディレクトリ作成し、user idを1000にしておく
sudo mkdir -p /work/pybind11
sudo chown 1000.1000 /work/pybind11

3.2.2 DockerのUbuntu20.04を利用して毎回必要なパッケージを入れる場合

  • ubuntu20.04を起動する
    • Docker内の/homeを/work/pybind11と共有
docker run -it --rm -v /work/pybind11:/home/ ubuntu:20.04
  1. Docker内で、必要なパッケージのインストール
    apt update
    apt upgrade
    apt -y install python3-dev python3-pip vim git g++ clang cmake make w3m less python3-ipython ipython3 nkf less diffutils patch sudo zlib1g-dev unzip locales 
    locale-gen ja_JP.UTF-8
    
    • pybind11パッケージのインストール
    pip3 install pybind11
    

3.2.3 pybind11を利用するのに必要なパッケージを入れたDockerイメージを作成する場合

  1. Dockerfileの準備
    • 以下の内容でDockerfileを作成
    FROM ubuntu:20.04
    MAINTAINER NM Max
    ENV user_n=user
    ENV user_id=1000
    #ENV DEBIAN_FRONTEND=noninteractive
    RUN apt -y update \
        && apt -y upgrade \
        && echo "6\n79\n" | apt -y install tzdata
    RUN apt -y install python3-dev python3-pip vim git g++ clang cmake make w3m less python3-ipython ipython3 nkf less diffutils patch sudo zlib1g-dev unzip locales \
        && locale-gen ja_JP.UTF-8 \
        && pip3 install pybind11
    ENV LC_ALL ja_JP.UTF-8
    ENV LANG ja_JP.UTF-8
    ENV LANGUAGE LANGUAGE=ja_JP:ja
    RUN echo 'LANG="ja_JP.UTF-8"' >> /etc/default/locale
    RUN echo "${user_n} ALL=NOPASSWD: ALL" >> /etc/sudoers
    WORKDIR /work
    RUN echo "\n\n\n\n\n\n\n" | adduser --uid ${user_id} --disabled-password ${user_n}
    RUN echo "user ALL=NOPASSWD: ALL" >> /etc/sudoers && chown user.user /work
    RUN mkdir -p /home/${user_n}/C && chown  ${user_n}.${user_n} /home/${user_n}/C
    ENTRYPOINT sudo su - ${user_n}
    
    • 以下のコマンドでイメージ作成
    docker build -t mypybind11 .
    
    • 作成したDockerイメージの起動は以下のコマンドで
    docker run -it --rm -v /work/pybind11:/home/user/C mypybind11
    

3.3 この章のまとめ

  • どのOSでも共通で利用できる環境をDockerで作成
  • Dockerの環境の準備が面倒なら、必要なツールをインストールして直接やってもよい

4 本家の文書のFirst stepsをやってみる

4.1 以下の操作を行っている動画


4.2 本家の文書のFirst stepsをやる手順

4.2.1 事前準備

  • OSに依存せずに同じ環境作れるようにDockerを利用してこの動画シリーズやっていきます。
  • まずDockerをインストールしてください。
    • 私はUbuntu20.04の環境で行って行きます。DockerはWindowsやMacでも使えるので、他のOSでもDockerを入れれば同じ手順で出来ます。
  • Docker等でUbuntuの環境を用意
    • Python,Python-dev,c++コンパイラー,cmake,git等必要なパッケージインストール
  1. 前の章で作成したmypybind11イメージを利用する場合
    • 前の章で作成した専用Dockerイメージmypybind11を起動
      • /work/pybind11 を Docker内の/homeと共通にしてます。
    docker run -it --rm -v /work/pybind11:/home/user/C mypybind11
    
    • 起動したDocker環境内で以下を実行
      • ubuntu20.04の場合は cd /home/user/C ではなく cd /home で
    cd /home/user/C
    mkdir test001
    cd test001/
    pwd
    
    • /home/user/C/test001 と表示され、現在の作業しているディレクトリを確認できます。
  2. 前の章で作成したmypybind11イメージを利用せずにUbuntu20.04を利用する場合
    • この場合、必要なものが入ってないので、Dockerイメージ起動あとに、必要なものを入れる必要があります。
    docker run -it --rm -v /work/pybind11:/home Ubuntu20.04
    
    • 以下を実行して必要なパッケージを入れる
    apt update
    apt upgrade
    apt install python3-dev python3-pip vim git g++ clang cmake make w3m less python3-ipython ipython3
    pip3 install pybind11
    
    • 起動したDocker環境内で以下を実行
      • ubuntu20.04の場合は cd /home/user/C ではなく cd /home で
    cd /home/
    mkdir test001
    cd test001/
    pwd
    
    • /home/test001 と表示され、現在の作業しているディレクトリを確認できます。

4.2.2 example.cppの準備

4.2.3 コンパイル

c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)

4.2.4 動作確認

  • 対話環境で動作確認した方がやりやすいので、IPythonを起動する
ipython3
  • 作成したモジュールの読み込み
import example                                                                                                                                
  • 1+2をやってみる
example.add(1,2)                                                                                                                              
  • 1+2で3が表示されます
  • 次に5+6をやってみる。
example.add(5,6)   
  • 5+6で11が表示されます

4.3 この章のまとめ

  • 本家文書のFirst stepsをやってみた
  • 使い方の基本の確認
  • C++で作成した関数をPythonで利用する手順の理解

5 CMakeで前章の内容をやってみる

5.1 以下の操作を行っている動画


5.2 cmakeで前章の内容をやってみる手順

5.2.1 事前準備

  • 必要なソフトを入れる
  • 前の章のexample.cppを入れておく
  • example.cppのあるディレクトリに移動
  1. 以下のコマンドでpybind11の最新バージョンをダウンロードして利用しても良い
    git clone https://github.com/pybind/pybind11
    
    • 以下のコマンドでバックアップ取っておいても良いかも
    tar cvzf pybind11_`date +%Y%m%d_%H%M`.tgz pybind11/
    

5.2.2 CMakeLists.txt の準備

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

5.2.3 コンパイル

mkdir build
cd build
cmake ..
make 
  • 前の章と同じ手順で動作確認すべき

5.3 この章のまとめ

  • 前章の内容をcmakeを利用してやってみた
  • コンパイルがちょい楽に

6 classを利用その1

6.1 以下の操作を行っている動画


6.2 classを利用その1の手順

  • この動画で以前作成したDockerイメージを起動
  • 作業用ディレクトリにてCMakeLists.txtとexample.cppの2つを用意

6.2.1 以前作成したDockerイメージの起動

docker run -it --rm -v /work/pybind11:/home/user/C mypybind11

6.2.2 作業用のディレクトリの作成と移動

cd /home/user/C
mkdir test002
cd test002/
pwd

6.2.3 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

6.2.4 example.cppの作成

  • 前の章で利用したものに簡単なクラスTest01を追加
  • Class Test01をPython側で利用出来るようにコード追加
    • def_readwrite でpublicのメンバ変数を参照してPythonから使えるようにした
    • コンストラクタと、helloメンバ関数を参照してPythonから使えるようにした
#include <pybind11/pybind11.h>
#include <string>
namespace py = pybind11;

int add(int i, int j) {
    return i + j;
}

class Test01 {
        public:
                Test01(const std::string &s) {
                        name=s;
                }
                std::string name;
                std::string hello() {
                        return "Hello "+name+"!";
                }
};

// https://pybind11.readthedocs.io/en/stable/classes.html#instance-and-static-fields
// https://pybind11.readthedocs.io/en/stable/classes.html#binding-lambda-functions
PYBIND11_MODULE(example, m) {
        m.doc() = "pybind11 example plugin"; // optional module docstring

        m.def("add", &add, "A function which adds two numbers");
        py::class_<Test01>(m, "Test01")
                .def(py::init<const std::string &>())
                .def_readwrite("name", &Test01::name)
                .def("hello", &Test01::hello);
}

6.2.5 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

6.2.6 コンパイル

mkdir build
cd build
cmake ..
make 

6.2.7 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
m=example.Test01("Tom")
m.name
m.hello()
  • 次の章でオブジェクトを文字列化するところをカスタマイズするので、一度表示してみる。
m
  • 内部の情報とかは現状見れない。次の章でここらの表現をカスタマイズします。
  • 次の章で、ダイナミックに属性を追加出来るようにするので、現在出来ないことを確認
m.age=32                                                                                                                                      
  • AttributeError: ‘example.Test01’ object has no attribute ‘age’ が表示される

6.3 この章のまとめ

  • classをやってみた。

7 classを利用その2

7.1 以下の操作を行っている動画


7.2 classを利用その2の手順

  • この動画で以前作成したDockerイメージを起動
  • 作業用ディレクトリにてCMakeLists.txtとexample.cppの2つを用意

7.2.1 以前作成したDockerイメージの起動

docker run -it --rm -v /work/pybind11:/home/user/C mypybind11

7.2.2 作業用のディレクトリの作成と移動

cd /home/user/C
mkdir test003
cd test003/
pwd

7.2.3 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

7.2.4 example.cppの作成

  • 前の章で利用したものに多少修正
    • Class Test01のpybind11用記述部分に2箇所追加
      • py::dynamic_attr()追加 これにより 動的に属性追加可能に。 dict でそれらの情報出てくる。
        • .def(“repr“, …. 部分追加 これにより、クラスオブジェクトの表示をカスタマイズ
#include <pybind11/pybind11.h>
#include <string>
namespace py = pybind11;

int add(int i, int j) {
    return i + j;
}

class Test01 {
        public:
                Test01(const std::string &s) {
                        name=s;
                }
                std::string name;
                std::string hello() {
                        return "Hello "+name+"!";
                }
};

PYBIND11_MODULE(example, m) {
        m.doc() = "pybind11 example plugin"; // optional module docstring

        m.def("add", &add, "A function which adds two numbers");
        py::class_<Test01>(m, "Test01", py::dynamic_attr())
                .def(py::init<const std::string &>())
                .def_readwrite("name", &Test01::name)
                .def("hello", &Test01::hello)
                .def("__repr__",
                        [](const Test01 &a) {
                            return "<example.Test01 named '" + a.name + "'>";
                        }
                );
}

7.2.5 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

7.2.6 コンパイル

mkdir build
cd build
cmake ..
make 

7.2.7 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
m=example.Test01("Tom")
m.name
m.hello()
  • 次の章でオブジェクトを文字列化するところをカスタマイズするので、一度表示してみる。
m
  • 表示がカスタマイズされて、nameの情報が表示されるようになった
  • 動的に属性を追加出来るようになっているので、試す。
m.age=32                                                                                                                                      
m.age  
print(m.__dict__)
  • 内部情報が表示されるようになった。

7.3 さらなる使い方

7.4 この章のまとめ

  • 前章のClassに動的に属性を追加出来るようにした。
  • 前章のClassを文字列化した時の表現のカスタマイズを行った。

8 コンテナを利用(std::vector) 1

8.1 以下の操作を行っている動画


8.2 コンテナを利用(std::vector) 1 の手順

  • この動画で以前作成したDockerイメージを起動
  • 作業用ディレクトリにてCMakeLists.txtとexample.cppの2つを用意

8.2.1 以前作成したDockerイメージの起動

docker run -it --rm -v /work/pybind11:/home/user/C mypybind11

8.2.2 作業用のディレクトリの作成と移動

cd /home/user/C
mkdir test004
cd test004/
pwd

8.2.3 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

8.2.4 example.cppの作成

  • pybind11/stl.h をインクルード
  • C++ で2つの関数を定義
    • range関数,最初、最後、差を与えると、等差数列をかえす関数
      • 無限ループ回避の処理をいれたら、ちょい不細工に
    • concatv 2つの整数(int)の数列を結合してかえす関数
  • Pythonに渡す関数の記述
    • 2つの関数の記述
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>
namespace py = pybind11;

std::vector<int> range(int st, int end, int diff) {
  std::vector<int> ans;
  bool flag=(end-st)*diff>=0;
  if(flag && diff!=0) {
    if(end>=st) {
      for(int i=st;i<=end;i+=diff) {
        ans.push_back(i);
      }
    } else {
      for(int i=st;i>=end;i+=diff) {
        ans.push_back(i);
      }
    }
  } else {
    ans.push_back(st);
  }
  return ans;
}       

std::vector<int> concatv(const std::vector<int> &a, const std::vector<int> &b) {
  std::vector<int> ans;
  for(int i=0;i<a.size();++i) {
    ans.push_back(a[i]);
  }
  for(int i=0;i<b.size();++i) {
    ans.push_back(b[i]);
  }
  return ans;
}       

PYBIND11_MODULE(example, m) {
  m.doc() = "pybind11 example plugin"; // optional module docstring

  m.def("range", &range, "A function which make a arithmetic progression");
  m.def("concatv", &concatv, "A function which concatenate two int vector");
}

8.2.5 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

8.2.6 コンパイル

mkdir build
cd build
cmake ..
make 

8.2.7 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
example.range(1,10,1)
example.range(1,10,2)
example.range(10,1,-1)
example.range(1,10,-1)
example.range(1,10,0)
example.concatv([5,6],[1,2,3])
example.concatv([1,2,3],[4,5])

8.3 この章のまとめ

  • std::vectorを使ったC++関数をPython側から使えるようにしてみた。

9 コンテナを利用(std::vector) 2 (Making opaque typesの1 意図したように動かない例)

9.1 以下の操作を行っている動画


9.2 コンテナを利用(std::vector) 2 (Making opaque typesの1 意図したように動かない例) の手順

9.2.1 以前作成したDockerイメージの起動

docker run -it --rm -v /work/pybind11:/home/user/C mypybind11

9.2.2 作業用のディレクトリの作成と移動

cd /home/user/C
mkdir test005
cd test005/
pwd

9.2.3 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

9.2.4 example.cppの作成

 - このままコピペじゃ動かないので、不足分を追加して実際に動かしてみる  - この例は意図した動作になっていない。自分でも同じことする時は気をつけるべき

  • 意図する動作にする手順は次の章で
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>

namespace py = pybind11;

void append_1(std::vector<int> &v) {
  v.push_back(1);
}

class MyClass {
  public:
    std::vector<int> contents;
};

/* ... binding code ... */


PYBIND11_MODULE(example, m) {
  m.doc() = "pybind11 example plugin"; // optional module docstring

  m.def("append_1", &append_1);
  py::class_<MyClass>(m, "MyClass")
      .def(py::init<>())
      .def_readwrite("contents", &MyClass::contents);
}

9.2.5 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

9.2.6 コンパイル

mkdir build
cd build
cmake ..
make 

9.2.7 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
v=[1,2,3]
example.append_1(v)
v
  • [1,2,3,1]ではなく[1,2,3]がかえってくる
  • クラスの方もやってみる
m = example.MyClass()
m.contents = [5, 6]
m.contents
m.contents.append(7)
m.contents
  • これも[5,6,7]ではなく[5,6]がかえってくる

9.3 この章のまとめ

10 コンテナを利用(std::vector) 3 (Making opaque typesの2 意図したように動くようにOPAQUEを使う)

10.1 以下の操作を行っている動画


10.2 コンテナを利用(std::vector) 3 (Making opaque typesの2 意図したように動くようにOPAQUEを使う)手順

  • 手順は前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

10.2.1 example.cppの作成

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>
#include <string>

namespace py = pybind11;

void append_1(std::vector<int> &v) {
  v.push_back(1);
}

class MyClass {
  public:
    std::vector<int> contents;
};

/* ... binding code ... */

PYBIND11_MAKE_OPAQUE(std::vector<int>);

PYBIND11_MODULE(example, m) {
  m.doc() = "pybind11 example plugin"; // optional module docstring

  py::class_<std::vector<int>>(m, "IntVector")
    .def(py::init<>())
    .def("clear", &std::vector<int>::clear)
    .def("pop_back", &std::vector<int>::pop_back)
    .def("push_back", (void (std::vector<int>::*)(const int &)) &std::vector<int>::push_back)
    .def("__len__", [](const std::vector<int> &v) { return v.size(); })
    .def("__iter__", [](std::vector<int> &v) {
       return py::make_iterator(v.begin(), v.end());
    }, py::keep_alive<0, 1>()); /* Keep vector alive while iterator is used */

  m.def("print_opaque_list", [](const std::vector<int> &l) {
        std::string ret = "Opaque list: [";
        bool first = true;
        for (auto entry : l) {
            if (!first)
                ret += ", ";
            ret += std::to_string(entry);
            first = false;
        }
        return ret + "]";
    });


  m.def("append_1", &append_1);
  py::class_<MyClass>(m, "MyClass")
      .def(py::init<>())
      .def_readwrite("contents", &MyClass::contents);
}

10.2.2 動作確認

import example
m=example.MyClass()
example.print_opaque_list(m.contents)
m.contents.push_back(1)
m.contents.push_back(2)
example.print_opaque_list(m.contents)
example.append_1(m.contents)
example.print_opaque_list(m.contents)
example.append_1(m.contents)
example.print_opaque_list(m.contents)

10.3 この章のまとめ

11 コンテナを利用(std::vector) 4 (Making opaque typesの3 意図したように動くようにOPAQUEと、Binding STL containersを使う)

11.1 以下の操作を行っている動画


11.2 コンテナを利用(std::vector) 4 (Making opaque typesの3 意図したように動くようにOPAQUEと、Binding STL containersを使う) 手順

  • 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

11.2.1 example.cppの作成

 - このままコピペじゃ動かないので、不足分を追加して実際に動かしてみる  - この例は意図した動作になっていない。自分でも同じことする時は気をつけるべき

  • 意図する動作にする手順は次の章で
  • ../pybind11/tests/test_opaque_types.cpp を参考に
    • push_backを追加(std::vector<int>用に修正)
    • print_opaque_list(std::vector<int>用に修正)
#include <pybind11/pybind11.h>
#include <pybind11/stl_bind.h>
#include <vector>
#include <string>

namespace py = pybind11;

void append_1(std::vector<int> &v) {
  v.push_back(1);
}

class MyClass {
  public:
    std::vector<int> contents;
};

/* ... binding code ... */

PYBIND11_MAKE_OPAQUE(std::vector<int>);

PYBIND11_MODULE(example, m) {
  m.doc() = "pybind11 example plugin"; // optional module docstring

  py::bind_vector<std::vector<int>>(m, "VectorInt");

  m.def("append_1", &append_1);
  py::class_<MyClass>(m, "MyClass")
      .def(py::init<>())
      .def_readwrite("contents", &MyClass::contents);
}

11.2.2 動作確認

import example
m=example.MyClass()
m.contents
m.contents=example.VectorInt([1,2,3])
example.append_1(m.contents)
m.contents
m.contents.append(5)
m.contents

11.3 この章のまとめ

12 引数に名前をつける

12.1 以下の操作を行っている動画


12.2 引数に名前をつける手順

  • 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

12.2.1 example.cppの作成

#include <pybind11/pybind11.h>
namespace py = pybind11;

int add(int i, int j) {
    return i + j;
}

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring

 // m.def("add", &add, "A function which adds two numbers"); // org
    m.def("add", &add, "A function which adds two numbers", py::arg("i"), py::arg("j"));
}

12.2.2 動作確認

import example
example.add(i=1,j=2)

12.3 この章のまとめ

13 引数にデフォルト値を設定

13.1 以下の操作を行っている動画


13.2 引数にデフォルト値を設定する手順

  • 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

13.2.1 example.cppの作成

#include <pybind11/pybind11.h>
namespace py = pybind11;

int add(int i, int j) {
    return i + j;
}

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring

 // m.def("add", &add, "A function which adds two numbers"); // org
 // m.def("add", &add, "A function which adds two numbers", py::arg("i"), py::arg("j")); // 前の章
    m.def("add", &add, "A function which adds two numbers", py::arg("i")=1, py::arg("j")=2);
}

13.2.2 動作確認

import example
example.add(i=2)
example.add(j=3)
example.add()

13.3 この章のまとめ

14 変数のエクスポート

14.1 以下の操作を行っている動画


14.2 変数のエクスポート 手順

  • 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

14.2.1 example.cppの作成

#include <pybind11/pybind11.h>
namespace py = pybind11;

PYBIND11_MODULE(example, m) {
    m.attr("the_answer") = 42;
    py::object world = py::cast("World");
    m.attr("what") = world;
}

14.2.2 動作確認

import example
example.the_answer
example.the_answer=53
example.the_answer
example.what
example.what="hoho"
example.what

14.3 この章のまとめ

15 オーバーロードされたメソッド

15.1 以下の操作を行っている動画


15.2 オーバーロードされたメソッドをPythonで利用する手順

  • C++14以前の方法と、C++14以降とでやり方2つある
  • C++14以降の方が記述が楽なので、こっちだけ動画で説明します。(もう一つの方法は Overloaded methods https://pybind11.readthedocs.io/en/stable/classes.html#overloaded-methodsをご覧ください)
  • pybind11では自動で、それらのメソッドを自動で選択してくれない、なので、ひとつひとつ引数を記述して記述していく
  • Dockerイメージの起動からコンパイルまでの手順は以前の動画 https://www.youtube.com/embed/fBW69-x4n6U を参考にやってください。

15.2.1 C++ソースファイルの作成

#include <pybind11/pybind11.h>
namespace py = pybind11;

struct Widget {
  int foo(int x, float y) {
    return x+y;
  }
  int foo(int x, float y) const {
    return x-y;
  }
};

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring
    py::class_<Widget>(m, "Widget")
       .def(py::init<>())
       .def("foo_mutable", py::overload_cast<int, float>(&Widget::foo))
       .def("foo_const",   py::overload_cast<int, float>(&Widget::foo, py::const_));
}

15.2.2 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)

set(CMAKE_CXX_STANDARD 14)          # C++14以上に設定する
set(CMAKE_CXX_STANDARD_REQUIRED ON) # 設定のC++のバージョン条件を満たせないならエラーにする
set(CMAKE_CXX_EXTENSIONS OFF)       # 互換性を高める

project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

15.2.3 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

15.2.4 コンパイル

  • 以前の章と同じコマンド
mkdir build
cd build
cmake ..
make 

15.2.5 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
w=example.Widget()
w.foo_mutable(1,2)
w.foo_const(1,2)

15.3 この章のまとめ

  • オーバーロードされたメソッドの取扱方法の1つを行なった。

16 モジュール名に注意

  • CMakeLists.txt内のモジュール名とc++ソースのモジュール名が異ると、コンパイルは可能なのですが、モジュール読み込み時にエラーが発生
  • Dockerイメージの起動からコンパイルまでの手順は以前の動画 https://www.youtube.com/embed/fBW69-x4n6U を参考にやってください。

16.1 以下の操作を行っている動画


16.2 モジュール名に注意 の確認手順

  • 前のソースのCMakeLists.txtの pybind11_add_module(example example.cpp) を pybind11_add_module(widget example.cpp) とか、別名にしてみる
  • コンパイルしなおして、モジュール読み込むと以下のエラーが発生
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-1-64ca027457b3> in <module>
----> 1 import widget

ImportError: dynamic module does not define module export function (PyInit_widget)
  • ということで、 CMakeLists.txt内のモジュール名と、C++ソースのモジュール名同じにする必要があります。(こないだこれでハマり、時間ロスしました)

16.3 この章のまとめ

  • CMakeLists.txt のモジュール名と、C++ソースで記述したモジュール名は同じにしましょう。そうしないとエラー発生。

17 今後

  • 今後も文書追加していきます。

18 この文書のチェンジログ

  • 2021/05/08 初版
  • 2021/05/10 classを利用その1 の章, classを利用その2 の章追加
  • 2021/05/10 Dockerイメージの起動のコマンドに誤りがあったので修正
  • 2021/05/11 コンテナを利用(std::vector) 1 の章追加
  • 2021/05/12 コンテナを利用(std::vector) 2 (Making opaque typesの1 意図したように動かない例) の章、コンテナを利用(std::vector) 3 (Making opaque typesの2 意図したように動くようにOPAQUEを使う) の章、 * コンテナを利用(std::vector) 4 (Making opaque typesの3 意図したように動くようにOPAQUEと、Binding STL containersを使う) の章追加
  • 2021/05/13 引数に名前をつける の章、 引数にデフォルト値を設定 の章、 変数のエクスポート の章追加
  • 2021/05/21 オーバーロードされたメソッド の章追加, モジュール名に注意 の章追加
  • 2021/05/24 BlogへのアップロードをMarkDownに変換して登録するように変更

著者: NM Max

Created: 2021-05-24 月 23:42

Validate

Dlib入門

Dlib入門

1 概要

  • お手軽に顔のパーツを検出出来る素晴らしいライブラリ
  • 画像認識他多数の機能あり

3 インストール

  • Pythonをインストールしてから、pip install dlibで、自動でコンパイルして、Pythonから使えるようになる(Linux,Windows,Mac等)

3.1 以下の操作を行っている動画


3.2 2021/02/05時点で最新のdlibをUbuntu20.04にコンパイルインストールする 手順

  • 作業用のディレクトリに移動してから以下の操作を行う

3.2.1 Python用のパッケージインストール(Ubuntu20.04)

  • Ubuntu20.04以外(WindowsやMac)はPythonをインストールして、pip install dlibでコンパイルインストール出来るはず
    • Windowsの場合はコンパイラも必要かも
    • DockerでUbuntuを動かして、そこに入れる方法なら、同じ手順でいける
  • DockerのUbuntu:20.04で確認したところ、以下をいれておけば、Dlibをコンパイル、インストール可能(もっと入れておけば良いのあるかも)
sudo apt update
apt install git clang cmake make sudo python3-virtualenv python3-dev libpng-dev lldb python3-pip python-numpy libboost-dev python3-scipy python3-opencv

3.2.2 Python用のパッケージインストール

  • 以下のコマンドで自動でダウンロードしてコンパイルし、Pythonから使えるようになる
  • virtualenv環境でやる方が良いかも(私はそうした)
pip3 install dlib
or
pip install dlib

3.2.3 virtualenv 作成コマンド例(名前がkivy_buildozerなら)

virtualenv kivy_buildozer
  • 作成したvirtualenvに入る
source kivy_buildozer/bin/activate

3.2.4 githubからゲットしてコンパイル

  • 作業用のディレクトリに移動して以下を実行(静的ライブラリ)
git clone https://github.com/davisking/dlib
cd dlib
mkdir build
cd build
cmake .. 
make
  • cmake .. を以下にすると、動的ライブラリ
cmake -DBUILD_SHARED_LIBS=1 .. 
  1. pybind11(python用の動的ライブラリをコンパイルする手順)
    • python setup.py build でもコンパイルできる(これで、どのようなコマンドでコンパイル可能か調べた)
    • virtualenvの場合は/usr/bin/python3 ではなく、which pythonとかwhich python3で確認したpythonにした方がよさげ(未確認)
    git clone https://github.com/davisking/dlib
    cd dlib
    cmake tools/python -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=build/lib.linux-x86_64-3.8 -DPYTHON_EXECUTABLE=/usr/bin/python3 -DCMAKE_BUILD_TYPE=Release
    make 
    

3.3 この章のまとめ

  • Pythonから使えるようにインストールする手順を紹介
  • GitHubからソースゲットしてコンパイルする手順も紹介

4 画像ファイルの読み込みと表示

4.1 以下の操作を行っている動画


4.2 画像ファイルの読み込みと表示手順

4.2.1 画像ファイルの読み込み

  • これで読み込める
dlib.load_rgb_image(ファイル名)
  1. 画像の表示
    win = dlib.image_window() # window作成
    win.set_image(画像)       # 画像表示
    
  2. サンプルプログラム
    • 顔の画像はパブリックドメインの福沢諭吉さんの画像”Yukichi_Fukuzawa_1891.png”を使ってます。他の顔画像でもOK
    import dlib
    img=dlib.load_rgb_image("Yukichi_Fukuzawa_1891.png")
    win = dlib.image_window()
    win.set_image(img)
    

4.3 この章のまとめ

  • dlibの機能をつかって、ファイルの読み込みと、表示を行った。

5 顔認識

5.2 以下の操作を行っている動画


5.3 顔認識の手順

5.3.1 顔認識

detector = dlib.get_frontal_face_detector()
dets = detector(画像データ, 1)

5.3.2 プログラム例

import dlib
img=dlib.load_rgb_image("Yukichi_Fukuzawa_1891.png")
detector = dlib.get_frontal_face_detector()
dets = detector(img, 1)
win = dlib.image_window()
win.set_image(img)
win.add_overlay(dets)

5.4 この章のまとめ

  • dlibの機能をつかって、顔認識と、認識箇所の描画を行った。

6 顔のランドマーク検出

6.2 以下の操作を行っている動画


6.3 顔のランドマーク検出 の手順

6.3.1 検出器に必要なファイルダウンロード

wget http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
  • 解凍(ここではこのコマンドつかってるけど、他のツールで解凍してもOK)
bzcat shape_predictor_68_face_landmarks.dat.bz2 > shape_predictor_68_face_landmarks.dat

6.3.2 Dlibでの顔のランドマーク検出のやりかた

  • predictorの作成
predictor = dlib.shape_predictor(ランドマーク検出用datファイル)
  • 検出
    • 顔のある場所はrectangleで渡す
shape = predictor(画像データ, 顔のある場所)

6.3.3 プログラム例

  • 顔の画像はパブリックドメインの福沢諭吉さんの画像”Yukichi_Fukuzawa_1891.png”を使ってます。他の顔画像でもOK
import dlib
img=dlib.load_rgb_image("Yukichi_Fukuzawa_1891.png")
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
detector = dlib.get_frontal_face_detector()
dets = detector(img, 1)
win = dlib.image_window()
win.set_image(img)
win.add_overlay(dets)
shapes=[]
for k, d in enumerate(dets):
  shapes.append(predictor(img, d))
  win.add_overlay(shapes[k])

6.4 この章のまとめ

  • dlibの機能をつかって、顔のランドマーク検出を行って、結果を表示した。

7 次のまだ書いてない章

7.0.1 追加パッケージインストール

pip install immutils opencv-python Pillow ipython matplotlib

8 今後

  • 今後も文書追加していきます。

9 この文書のチェンジログ

  • 2021/02/06 初版
  • 2021/02/16 画像ファイルの読み込みと表示, 顔認識, 顔のランドマーク検出 の章追加

著者: NM Max

Created: 2021-02-16 火 14:07

Validate

Ubuntu20.04にAndroidのNDK,SDKをコマンドラインでインストール





Ubuntu20.04にAndroidのNDK,SDKをコマンドラインでインストール

1 概要

  • Android Studioが重いので、コマンドラインでインストールしてみたかった
  • やねうら王や、他のツールをUbuntu上でAndroid用をクロスコンパイルしてみたかった。

2 リンク

3 インストール

3.1 Command line tools onlyのインストール

  • 以下の手順でインストールすると5G弱ディスクスペースを消費した

3.2 以下の操作を行っている動画


3.2.1 Command line tools onlyのインストールの手順

  1. ベースツールのダウンロード
    • Android Studio関係ダウンロードページhttps://developer.android.com/studio?hl=ja の「Command line tools only」のところからLinux用のcommandlinetools-linux-6858069_latest.zipをダウンロード
  2. ダウンロードしたファイルを解凍
    • ここではunarコマンドで行っていますが、他の解凍ツールでもOK
    • 解凍場所はどこでもOK、このファイルは後で使わない
    unar commandlinetools-linux-6858069_latest.zip
    
    • 解凍した実行ファイルのディレクトリに移動
    cd cmdline-tools/bin/
    
  3. インストールするディレクトリを作成
    • ここではホームディレクトリのAndroid/SDKにインストールします
    mkdir -p ${HOME}/Android/SDK
    
  4. sdkmanager helpの確認方法
    ./sdkmanager --sdk_root=${HOME}/Android/SDK/ --help
    
  5. 解凍したコマンドラインツールで、必要パッケージをインストール
    • パッケージリストを確認
    • これでインストールするバージョン選ぶ。以下の私の手順と同じバージョンでなくてもOK
    ./sdkmanager --sdk_root=${HOME}/Android/SDK/ --list
    
    • コマンドラインツールをインストール
    ./sdkmanager --sdk_root=${HOME}/Android/SDK/ --install "cmdline-tools;latest"
    
    • プラットフォームツールと、プラットフォームをインストール。ここでは最新の30の物をインストールした
    ./sdkmanager --sdk_root=${HOME}/Android/SDK/ "platform-tools" "platforms;android-30"
    
    • ndkの最新をインストール
    ./sdkmanager --sdk_root=${HOME}/Android/SDK/ "ndk-bundle"
    
    • build-toolsをインストール
    ./sdkmanager --sdk_root=${HOME}/Android/SDK/ "build-tools;30.0.3"
    
    • 他にもインストールした方が良いものとしては、エミュレーターとかもある。Androidのpkgを作成するには、他にも追加のものをsdkmanagerでインストールする必要あると思う。その場合は上の感じで追加インストールすればOK。
  6. 環境変数のセット
    • SDKを使う場合は、以下の環境変数を設定
    • 毎回設定が面倒なら、.bashrcに以下の2行を追加。追加したばかりだと、これらは設定されてないので、使う前にこれらをシェルで実行
    • set.shというファイル名に入れておいて、source set.sh 等でこれらを実行してもOK
    export PATH=${HOME}/Android/SDK/cmdline-tools/latest/bin:${HOME}/Android/SDK/ndk-bundle/:$PATH
    export ANDROID_SDK_ROOT=${HOME}/Android/SDK/
    
  7. インストールしたパッケージの確認
    sdkmanager --sdk_root=${HOME}/Android/SDK/ --list_installed
    
    • 現在の状態出力
    Installed packages:=====================] 100% Fetch remote repository...       
      Path                 | Version      | Description                             | Location             
      -------              | -------      | -------                                 | -------              
      build-tools;30.0.3   | 30.0.3       | Android SDK Build-Tools 30.0.3          | build-tools/30.0.3/  
      cmdline-tools;latest | 3.0          | Android SDK Command-line Tools (latest) | cmdline-tools/latest/
      emulator             | 30.3.5       | Android Emulator                        | emulator/            
      ndk-bundle           | 22.0.7026061 | NDK                                     | ndk-bundle/          
      patcher;v4           | 1            | SDK Patch Applier v4                    | patcher/v4/          
      platform-tools       | 30.0.5       | Android SDK Platform-Tools              | platform-tools/      
      platforms;android-30 | 3            | Android SDK Platform 30                 | platforms/android-30/
    
  8. updateのやり方
    sdkmanager --sdk_root=${HOME}/Android/SDK/ --update
    

3.3 この章のまとめ

  • コマンドラインツールで、Android SDK,NDKをインストールしてみた。

4 今後

  • 今後も文書追加していきます。

5 この文書のチェンジログ

  • 2021/01/19 初版

著者: NM Max

Created: 2021-01-20 水 08:34

Validate

ANTLR4事始め





ANTLR4ことはじめ

目次

1 概要

  • 機能豊富なパーサジェネレータ
  • インストール
  • 簡易電卓作成(普通のプログラム言語のHello Worldにあたるもの)
  • 簡易プログラム言語作成(計算機能、変数利用と、print命令のみ)

2 この文書作ろうと思ったきっかけ

  • 構文解析をPythonでやろうと色々調べたところ、どうやら、ANTLR4が抜けてるというのをみつけて、これやってみよとなりました。

5 Ubuntu20.04でANTLR4をインストール

  • 公式サイトの文書のやつをやってみる

5.1 以下の操作を行っている動画


5.2 Ubuntu20.04でANTLR4をインストール する手順

sudo apt install antlr4
  • 環境変数をセットしないと、上手く動作しなかった(必要なものが見つからないってエラー)
  • 以下を実行してから実行するのが良い
  • ホームディレクトリの.bashrcとかに追記しておくと、いちいち実行しなくても良くなる
export CLASSPATH=.:/usr/share/java/antlr4.jar:/usr/share/java/antlr4-runtime.jar:/usr/share/java:${CLASSPATH}

5.3 動作確認

5.3.1 ソースファイルHello.g4を用意

5.3.2 ソースファイルHello.g4から生成

antlr4 Hello.g4
  • これで、必要なファイルが生成される
HelloLexer.interp
HelloLexer.java
HelloLexer.tokens
Hello.interp
HelloParser.java
HelloListener.java
HelloBaseListener.java
Hello.tokens

5.3.3 生成したjavaファイルをコンパイル

javac Hello*.java

5.3.4 生成したものを動作確認

/usr/share/antlr4/grun Hello r -tree
or
/usr/share/antlr4/grun Hello r -gui

5.4 この章のまとめ

  • antlr4をUbuntu20.04にインストール
  • 公式サイトのGetting StartedのHello.g4を利用してコンパイル実行してみた

6 簡易電卓の作成

6.1 自然数を解釈する

6.1.1 以下の操作を行っている動画


6.1.2 自然数を解釈する 手順

  1. 0だけを解釈するものを作る
    • 以下の内容でCalc.g4というファイルを作成
    • Parser rule(パーサールール)名は小文字で開始
    • Token(識別子)名は大文字で開始
    grammar Calc;
    expr  : N;
    N     : '0';
    WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
    
    • コンパイル
    export CLASSPATH=.:/usr/share/java/antlr4.jar:/usr/share/java/antlr4-runtime.jar:/usr/share/java:${CLASSPATH}
    antlr4 Calc.g4
    javac Calc*java
    
    • 以下で確認する(色々入力して、最後にCtrl-Dを押す。WindowsならCtrl-Zかも)
    /usr/share/antlr4/grun Calc expr -gui
    
  2. 0と1を解釈するものを作る
    • 以下の内容にCalc.g4を修正
    • 亀の子括弧[]は中身のどれかに該当する一文字にマッチする正規表現
      • 例1 [01]は0か1にマッチ
      • 例2 [012]は0か1か2にマッチ
      • 例3 [abc]はaかbかcにマッチ
    • 正規表現は言語やツールによって多少方言あり
    grammar Calc;
    expr  : N;
    N     : [01];
    WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
    
    • コンパイル
    antlr4 Calc.g4
    javac Calc*java
    
    • 以下で確認する(色々入力して、最後にCtrl-Dを押す。WindowsならCtrl-Zかも)
    /usr/share/antlr4/grun Calc expr -gui
    
  3. 0から9までを解釈するものを作る
    • 以下の内容にCalc.g4を修正
    grammar Calc;
    expr  : N;
    N     : [0123456789];
    WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
    
    • コンパイル
    antlr4 Calc.g4
    javac Calc*java
    
    • 以下で確認する(色々入力して、最後にCtrl-Dを押す。WindowsならCtrl-Zかも)
    /usr/share/antlr4/grun Calc expr -gui
    
  4. 0から9までを解釈するものを作る(その2)
    • 以下の内容にCalc.g4を修正
    • 亀の子括弧[]は中身のどれかに該当する一文字にマッチする正規表現
      • 例1 [0-5]は0か1か2か3か4か5にマッチ
        • (文字もコンピューター内部では数字で処理されていて、この数字ならこの文字の事ということで処理されている。通常半角英数の場合,アスキーコードという文字と数字の対応の規約が使われていて、それだと0から9まで1つずつ増える数字で扱っている)
      • 例2 [0-2]は0か1か2にマッチ
      • 例3 [a-z]はaからzまでの26文字の1文字にマッチ
      • 今回の[0-9]は0,1,2,3,4,5,6,7,8,9の1文字にマッチする正規表現
    grammar Calc;
    expr  : N;
    N     : [0-9];
    WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
    
    • コンパイル
    antlr4 Calc.g4
    javac Calc*java
    
    • 以下で確認する(色々入力して、最後にCtrl-Dを押す。WindowsならCtrl-Zかも)
    /usr/share/antlr4/grun Calc expr -gui
    
  5. 二桁以上の数字に対応(その1)
    • 以下の内容にCalc.g4を修正
    • +は正規表現で、直前のものを1度以上繰り返ししているものにマッチ
      • 例えば 1+なら、1が1文字以上にマッチ、1,11,111,1111,….にマッチする
      • 今回の[0-9]+だと、0から9までの文字が1文字以上繰り返されるものにマッチ
    • *は正規表現で、直前のものを0回以上繰り返ししているものにマッチ
      • 例1 0* なら 文字無し、0,00,000,0000,0000,….にマッチ
      • 例2 [0-9]* なら 数字が0回以上繰り返されるものにマッチ、 文字なし、0,12,359,…等など
    grammar Calc;
    expr  : N;
    N     : [0-9]+;
    WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
    
    • コンパイル
    antlr4 Calc.g4
    javac Calc*java
    
    • 下で確認する(色々入力して、最後にCtrl-Dを押す。WindowsならCtrl-Zかも)
    /usr/share/antlr4/grun Calc expr -gui
    
  6. 二桁以上の数字に対応(その2)
    • 以下の内容にCalc.g4を修正
    grammar Calc;
    expr  : N;
    N     : [0-9]
          | [1-9][0-9]+;
    WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
    
    • [0-9] | [1-9][0-9]+ : 0から9のひと桁の数字あるいは、1から9ではじまる2桁以上の数字にマッチする表現
    • コンパイル
    antlr4 Calc.g4
    javac Calc*java
    
    • 下で確認する(色々入力して、最後にCtrl-Dを押す。WindowsならCtrl-Zかも)
    /usr/share/antlr4/grun Calc expr -gui
    

6.1.3 この節のまとめ

  • 自然数を解釈するパーサーの作成

6.2 足し算表現、引き算表現の解釈処理追加

6.2.1 以下の操作を行っている動画


6.2.2 足し算表現、引き算表現の解釈処理追加 手順

  1. まず足し算表現を追加
    • 前の章で作成したCalc.g4を以下に修正
    • 注意書き、正規表現マッチの多くの場合、特別な意味を持つ文字(+,*,.,?等)はバックスラッシュでエスケープすると、特殊な意味ではなく、その文字自体を意味するものとして扱うことが多いが、ANTLERの文法記述ではこれではなく、半角シングルクオートでかこむようです。
      • 例えば+文字自体を扱いたい時
        • ‘+’と記述
    • 他の主要な正規表現で使う文字
      • .(半角ピリオド文字) : 任意の1文字にマッチ
    • “no viable alternative at input ‘<EOF>'” を防ぐ為に、parseルールを追加
    grammar Calc;
    parse : expr EOF;
    expr  : expr '+' expr
          | N;
    N     : [0-9]
          | [1-9][0-9]+;
    WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
    
    • コンパイル
    export CLASSPATH=.:/usr/share/java/antlr4.jar:/usr/share/java/antlr4-runtime.jar:/usr/share/java:${CLASSPATH}
    antlr4 Calc.g4
    javac Calc*java
    
    • 以下で確認する(色々入力して、最後にCtrl-Dを押す。WindowsならCtrl-Zかも)
    /usr/share/antlr4/grun Calc parse -gui
    
  2. 引き算表現も追加
    • 以下の内容にCalc.g4を修正
    grammar Calc;
    parse : expr EOF;
    expr  : expr  '+' expr
          | expr '-' expr
          | N;
    N     : [0-9]
          | [1-9][0-9]+;
    WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
    
    • コンパイル
    antlr4 Calc.g4
    javac Calc*java
    
    • 以下で確認する(色々入力して、最後にCtrl-Dを押す。WindowsならCtrl-Zかも)
    /usr/share/antlr4/grun Calc parse -gui
    
  3. 数字の前に’-‘がある場合の処理追加
    • 以下の内容にCalc.g4を修正
    grammar Calc;
    parse : expr EOF;
    expr  : expr  '+' expr
          | expr '-' expr
          | N
          | '-' N;
    N     : [0-9]
          | [1-9][0-9]+;
    WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
    
    • コンパイル
    antlr4 Calc.g4
    javac Calc*java
    
    • 以下で確認する(色々入力して、最後にCtrl-Dを押す。WindowsならCtrl-Zかも)
    /usr/share/antlr4/grun Calc parse -gui
    

6.2.3 この節のまとめ

  • 足し算引き算表現も解釈出来るように修正
  • 数字の前のマイナス記号も解釈出来るように修正

6.3 掛け算表現、割り算表現の解釈処理追加

6.3.1 以下の操作を行っている動画


6.3.2 掛け算表現、割り算表現の解釈処理追加 手順

  • 前の章で作成したCalc.g4を以下に修正
grammar Calc;
parse : expr EOF;
expr  : expr '*' expr
      | expr '/' expr
      | expr '+' expr
      | expr '-' expr
      | N
      | '-' N;
N     : [0-9]
      | [1-9][0-9]+;
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
  • コンパイル
export CLASSPATH=.:/usr/share/java/antlr4.jar:/usr/share/java/antlr4-runtime.jar:/usr/share/java:${CLASSPATH}
antlr4 Calc.g4
javac Calc*java
  • 以下で確認する(色々入力して、最後にCtrl-Dを押す。WindowsならCtrl-Zかも)
/usr/share/antlr4/grun Calc parse -gui

6.3.3 この節のまとめ

  • 掛け算、割り算表現も解釈出来るように修正

6.4 括弧でくるんだ部分を優先して処理するように修正

6.4.1 以下の操作を行っている動画


6.4.2 括弧でくるんだ部分を優先して処理するように修正 する手順

  • 前の章で作成したCalc.g4を以下に修正
  • 計算式を複数入れれるように修正
    • 区切り文字としては、EOF,改行,セミコロン(;)
grammar Calc;
parse : expr EOF;
expr  : '(' expr ')'
      | expr '*' expr
      | expr '/' expr
      | expr '+' expr
      | expr '-' expr
      | N
      | '-' N
      | '-' '(' expr ')' ;
N     : [0-9]
      | [1-9][0-9]+;
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
  • コンパイル
export CLASSPATH=.:/usr/share/java/antlr4.jar:/usr/share/java/antlr4-runtime.jar:/usr/share/java:${CLASSPATH}
antlr4 Calc.g4
javac Calc*java
  • 以下で確認する(色々入力して、最後にCtrl-Dを押す。WindowsならCtrl-Zかも)
/usr/share/antlr4/grun Calc parse -gui

6.4.3 この節のまとめ

  • 括弧でくるんだ部分を優先して処理するように修正

6.5 複数数式入力に対応する修正

6.5.1 以下の操作を行っている動画


6.5.2 複数数式入力に対応する修正 する手順

  • 前の章で作成したCalc.g4を以下に修正
  • 計算式を複数入れれるように修正
    • 区切り文字としては、EOF,改行,セミコロン(;)
grammar Calc;
lines:
     | equation
     | lines equation
     | EOF;
equation : expr CR
	 | expr EOF;
expr  : '(' expr ')'
      | expr '*' expr
      | expr '/' expr
      | expr '+' expr
      | expr '-' expr
      | N
      | '-' N
      | '-' '(' expr ')' ;
N     : [0-9]
      | [1-9][0-9]+;
CR  : [\n;];          // newlines, semicolons
WS : [ \t]+ -> skip ; // skip spaces, tabs
  • コンパイル
export CLASSPATH=.:/usr/share/java/antlr4.jar:/usr/share/java/antlr4-runtime.jar:/usr/share/java:${CLASSPATH}
antlr4 Calc.g4
javac Calc*java
  • 以下で確認する(色々入力して、最後にCtrl-Dを押す。WindowsならCtrl-Zかも)
/usr/share/antlr4/grun Calc lines -gui

6.5.3 この節のまとめ

  • 複数数式入力に対応できるようになった

6.6 現時点で最新バージョンのAntlr4をインストール(2021/1/25現在最新の4.9.1をインストール)

  • 色々やっていると以下の不具合があったので、最新のものを入れ直すことにしたhttps://www.antlr.org/download/
    • Ubuntu20.04でPython用のAntlr4パッケージがデフォルトで用意されていない
    • pipでPython用のAntlr4ランタイムを入れると、Ubuntu20.04でパッケージ化されているAntlr4はバージョンがあわない

6.6.1 以下の操作を行っている動画


6.6.2 現時点で最新バージョンのAntlr4をインストール(2021/1/25現在最新の4.9.1をインストール) する手順

  1. antlr-4.9.1-complete.jar ダウンロード
    wget -m -l 1 https://www.antlr.org/download/antlr-4.9.1-complete.jar
    ln -s www.antlr.org/download/antlr-4.9.1-complete.jar .
    
  2. 設定を行う
    • 設定の方法についてはhttps://github.com/antlr/antlr4/blob/master/doc/getting-started.mdのInstallationのUnixのところがわかりやすい。そこの方法を、カレントディレクトリのファイルを使うように、また、バージョンを4.9.1を使うように修正したのが以下となります。
    • これを利用しているシェルで実行すればOK
    export CLASSPATH=".:./antlr-4.9.1-complete.jar:$CLASSPATH"
    alias antlr4='java -Xmx500M -cp "./antlr-4.9.1-complete.jar:$CLASSPATH" org.antlr.v4.Tool'
    alias grun='java -Xmx500M -cp "./antlr-4.9.1-complete.jar:$CLASSPATH" org.antlr.v4.gui.TestRig'
    
    • 私はset.shというファイル名でこの命令を入れておいた。(また使う時にやり方忘れる為)
    • ファイルに入れている場合(set.sh)環境変数や、aliasを設定するには
    . set.sh
    
    • あるいは、
    source set.sh
    
  3. python用のパッケージをインストール
    • デバッグ用のipdbと、ANTLR 4.9.1 runtime for Python 3 をインストール
    • pip3はpipになる環境もある。環境にあわせてPython用のパッケージインストールコマンドを使って下さい。
    • virtualenv下に入れた方が良いかも。私はvirtualenv環境にこれらのパッケージを入れている
    • 例えばvirtualenvの環境名をYoutubeToolsにする場合
    virtualenv YoutubeTools
    
    • 作った環境に入るには
    source YoutubeTools/bin/activate
    
    • その後に以下を実行。pip3ではなく、pipを使うべき環境なら、そちらを使ってください。Ubuntu20.04ならpip3を使います。
    pip3 install ipdb
    pip3 install antlr4-python3-runtime
    

6.6.3 この節のまとめ

  • 現時点で最新バージョンのAntlr4をインストール(2021/1/25現在最新の4.9.1をインストール)
  • Python3で利用するのに必要なパッケージインストール
  • Python3用のデバッガーパッケージインストール

6.7 アクション用のラベル追加, Python用のコード生成

6.7.1 以下の操作を行っている動画


6.7.2 アクション用のラベル追加, Python用のコード生成 する手順

  • 前の章で作成したCalc.g4を以下に修正
grammar Calc;
lines:
     | equation
     | lines equation
     | EOF;
equation : expr CR
	 | expr EOF;
expr  : '(' expr ')' #myBr
      | expr '*' expr #myMul
      | expr '/' expr #myDiv
      | expr '+' expr #myAdd
      | expr '-' expr #mySub
      | N #myNum
      | '-' N #myMinusNum
      | '-' '(' expr ')' #myMinus ;
N     : [0-9]
      | [1-9][0-9]+;
CR  : [\n;];           // newlines, semicolons
WS : [ \t]+ -> skip ;  // skip spaces, tabs
  • コンパイル
antlr4 -Dlanguage=Python3 Calc.g4

6.7.3 この節のまとめ

  • アクション用のラベル追加し、Python3用のコードを自動生成した。

6.8 Python用のコード作成(Listenerメソッドが動くように修正)

6.8.1 関連文書

6.8.2 以下の操作を行っている動画


6.8.3 Python用のコード作成(Listenerメソッドが動くように修正) の手順

  • main.pyを以下の内容で作成
  • ANATLR4 の Python (2 and 3)関連文書 https://github.com/antlr/antlr4/blob/master/doc/python-target.md の “How do I create and run a custom listener?”の部分をベースに、今回作成した構文の名前に変更した
  • ipdbを使って動作確認しやすくなるコードも追加してある
  • ipdbを使わない場合は、ipdbが含まれいている行を削除するか、#でコメントにしておけばOK
import ipdb
import sys
from antlr4 import *
from CalcLexer import CalcLexer
from CalcParser import CalcParser
from CalcListener import CalcListener

class KeyPrinter(CalcListener):
    def exitKey(self, ctx):
        pass

def main(argv):
    input = InputStream(argv[1])
    lexer = CalcLexer(input)
    stream = CommonTokenStream(lexer)
    parser = CalcParser(stream)
    tree = parser.lines()
    #print(tree.getChild(0))
    #print(tree.getChild(0).getText())
    ##print(tree.getChild(0).toStringTree())
    #ipdb.set_trace()
    printer = KeyPrinter()
    walker = ParseTreeWalker()
    walker.walk(printer, tree)

if __name__ == '__main__':
    main(sys.argv)

6.8.4 前の節で自動生成した、CalcListener.pyを以下のように修正し、どこが、どの順で呼び出されるかを確認

  • 主要な解釈のexit部分に、print文追加
  • print(ctx.getText()) で該当の部分を表示
  • 今回は省略していますが、enterの方も表示してみるとよりわかりやすくなります。
# Generated from Calc.g4 by ANTLR 4.9.1
from antlr4 import *
if __name__ is not None and "." in __name__:
    from .CalcParser import CalcParser
else:
    from CalcParser import CalcParser

# This class defines a complete listener for a parse tree produced by CalcParser.
class CalcListener(ParseTreeListener):

    # Enter a parse tree produced by CalcParser#lines.
    def enterLines(self, ctx:CalcParser.LinesContext):
        pass

    # Exit a parse tree produced by CalcParser#lines.
    def exitLines(self, ctx:CalcParser.LinesContext):
        print("exitLines")
        pass


    # Enter a parse tree produced by CalcParser#equation.
    def enterEquation(self, ctx:CalcParser.EquationContext):
        pass

    # Exit a parse tree produced by CalcParser#equation.
    def exitEquation(self, ctx:CalcParser.EquationContext):
        print("exitEquation")
        print(ctx.getText())
        pass


    # Enter a parse tree produced by CalcParser#myMul.
    def enterMyMul(self, ctx:CalcParser.MyMulContext):
        pass

    # Exit a parse tree produced by CalcParser#myMul.
    def exitMyMul(self, ctx:CalcParser.MyMulContext):
        print("exitMyMul")
        print(ctx.getText())
        pass


    # Enter a parse tree produced by CalcParser#myNum.
    def enterMyNum(self, ctx:CalcParser.MyNumContext):
        pass

    # Exit a parse tree produced by CalcParser#myNum.
    def exitMyNum(self, ctx:CalcParser.MyNumContext):
        print("exitMyNum")
        print(ctx.getText())
        pass


    # Enter a parse tree produced by CalcParser#myMinusNum.
    def enterMyMinusNum(self, ctx:CalcParser.MyMinusNumContext):
        pass

    # Exit a parse tree produced by CalcParser#myMinusNum.
    def exitMyMinusNum(self, ctx:CalcParser.MyMinusNumContext):
        print("exitMyMinusNum")
        print(ctx.getText())
        pass


    # Enter a parse tree produced by CalcParser#myMinus.
    def enterMyMinus(self, ctx:CalcParser.MyMinusContext):
        pass

    # Exit a parse tree produced by CalcParser#myMinus.
    def exitMyMinus(self, ctx:CalcParser.MyMinusContext):
        print("exitMyMinus")
        print(ctx.getText())
        pass


    # Enter a parse tree produced by CalcParser#mySub.
    def enterMySub(self, ctx:CalcParser.MySubContext):
        pass

    # Exit a parse tree produced by CalcParser#mySub.
    def exitMySub(self, ctx:CalcParser.MySubContext):
        print("exitMySub")
        print(ctx.getText())
        pass


    # Enter a parse tree produced by CalcParser#myDiv.
    def enterMyDiv(self, ctx:CalcParser.MyDivContext):
        pass

    # Exit a parse tree produced by CalcParser#myDiv.
    def exitMyDiv(self, ctx:CalcParser.MyDivContext):
        print("exitMyDiv")
        print(ctx.getText())
        pass


    # Enter a parse tree produced by CalcParser#myAdd.
    def enterMyAdd(self, ctx:CalcParser.MyAddContext):
        pass

    # Exit a parse tree produced by CalcParser#myAdd.
    def exitMyAdd(self, ctx:CalcParser.MyAddContext):
        print("exitMyAdd")
        print(ctx.getText())
        pass


    # Enter a parse tree produced by CalcParser#myBr.
    def enterMyBr(self, ctx:CalcParser.MyBrContext):
        pass

    # Exit a parse tree produced by CalcParser#myBr.
    def exitMyBr(self, ctx:CalcParser.MyBrContext):
        pass



del CalcParser

6.8.5 テスト

  1. テスト1 100 の場合
    python main.py "100"
    
    • 上記の場合の出力
    exitLines
    exitMyNum
    100
    exitEquation
    100<EOF>
    exitLines
    
  2. テスト2 -100 の場合
    python main.py "-100"
    
    • 上記の場合の出力
    exitLines
    exitMyMinusNum
    -100
    exitEquation
    -100<EOF>
    exitLines
    
  3. テスト3 -100 の場合
    python main.py "-100"
    
    • 上記の場合の出力
    exitLines
    exitMyMinusNum
    -100
    exitEquation
    -100<EOF>
    exitLines
    
  4. テスト3 1+3 の場合
    python main.py "1+3"
    
    • 上記の場合の出力
    exitLines
    exitMyNum
    1
    exitMyNum
    3
    exitMyAdd
    1+3
    exitEquation
    1+3<EOF>
    exitLines
    
  5. テスト3 1+3 の場合
    python main.py "(3-1)*5"
    
    • 上記の場合の出力
    exitLines
    exitMyNum
    3
    exitMyNum
    1
    exitMySub
    3-1
    exitMyNum
    5
    exitMyMul
    (3-1)*5
    exitEquation
    (3-1)*5<EOF>
    exitLines
    

6.8.6 この節のまとめ

  • Python用のコード作成(Listenerメソッドが動くように修正)
  • print文を多量に埋め込むことで、どのように動作しているかを確認

6.9 電卓として動作するように処理を書く(Python向け)

6.9.1 以下の操作を行っている動画


6.9.2 電卓として動作するように処理を書く手順

6.9.3 前の節で自動生成した、CalcListener.pyを以下のように修正

# Generated from Calc.g4 by ANTLR 4.9.1
from antlr4 import *
from collections import deque
if __name__ is not None and "." in __name__:
    from .CalcParser import CalcParser
else:
    from CalcParser import CalcParser

# This class defines a complete listener for a parse tree produced by CalcParser.
class CalcListener(ParseTreeListener):
    s = deque([])

    # Enter a parse tree produced by CalcParser#lines.
    def enterLines(self, ctx:CalcParser.LinesContext):
        pass

    # Exit a parse tree produced by CalcParser#lines.
    def exitLines(self, ctx:CalcParser.LinesContext):
        #print("exitLines")
        pass


    # Enter a parse tree produced by CalcParser#equation.
    def enterEquation(self, ctx:CalcParser.EquationContext):
        pass

    # Exit a parse tree produced by CalcParser#equation.
    def exitEquation(self, ctx:CalcParser.EquationContext):
        print("***exitEquation")
        print(ctx.getText())
        if(len(self.s)>0):
            print(self.s.pop())
        pass


    # Enter a parse tree produced by CalcParser#myMul.
    def enterMyMul(self, ctx:CalcParser.MyMulContext):
        pass

    # Exit a parse tree produced by CalcParser#myMul.
    def exitMyMul(self, ctx:CalcParser.MyMulContext):
        #print("exitMyMul")
        #print(ctx.getText())
        a=self.s.pop()
        b=self.s.pop()
        self.s.append(a*b)
        pass

    # Enter a parse tree produced by CalcParser#myNum.
    def enterMyNum(self, ctx:CalcParser.MyNumContext):
        pass

    # Exit a parse tree produced by CalcParser#myNum.
    def exitMyNum(self, ctx:CalcParser.MyNumContext):
        #print("exitMyNum")
        #print(ctx.getText())
        self.s.append(int(ctx.getText()))
        pass


    # Enter a parse tree produced by CalcParser#myMinusNum.
    def enterMyMinusNum(self, ctx:CalcParser.MyMinusNumContext):
        pass

    # Exit a parse tree produced by CalcParser#myMinusNum.
    def exitMyMinusNum(self, ctx:CalcParser.MyMinusNumContext):
        #print("exitMyMinusNum")
        #print(ctx.getText())
        self.s.append(int(ctx.getText()))
        pass


    # Enter a parse tree produced by CalcParser#myMinus.
    def enterMyMinus(self, ctx:CalcParser.MyMinusContext):
        pass

    # Exit a parse tree produced by CalcParser#myMinus.
    def exitMyMinus(self, ctx:CalcParser.MyMinusContext):
        #print("exitMyMinus")
        #print(ctx.getText())
        a=self.s.pop()
        self.s.append(-a)
        pass


    # Enter a parse tree produced by CalcParser#mySub.
    def enterMySub(self, ctx:CalcParser.MySubContext):
        pass

    # Exit a parse tree produced by CalcParser#mySub.
    def exitMySub(self, ctx:CalcParser.MySubContext):
        #print("exitMySub")
        #print(ctx.getText())
        a=self.s.pop()
        b=self.s.pop()
        self.s.append(b-a)
        pass


    # Enter a parse tree produced by CalcParser#myDiv.
    def enterMyDiv(self, ctx:CalcParser.MyDivContext):
        pass

    # Exit a parse tree produced by CalcParser#myDiv.
    def exitMyDiv(self, ctx:CalcParser.MyDivContext):
        a=self.s.pop()
        b=self.s.pop()
        self.s.append(b/a)
        pass


    # Enter a parse tree produced by CalcParser#myAdd.
    def enterMyAdd(self, ctx:CalcParser.MyAddContext):
        pass

    # Exit a parse tree produced by CalcParser#myAdd.
    def exitMyAdd(self, ctx:CalcParser.MyAddContext):
        #print("exitMyAdd")
        #print(ctx.getText())
        a=self.s.pop()
        b=self.s.pop()
        self.s.append(a+b)
        pass


    # Enter a parse tree produced by CalcParser#myBr.
    def enterMyBr(self, ctx:CalcParser.MyBrContext):
        pass

    # Exit a parse tree produced by CalcParser#myBr.
    def exitMyBr(self, ctx:CalcParser.MyBrContext):
        pass



del CalcParser

6.9.4 動作確認

python main.py "(1+3)*4;"
python main.py "(1+3)*4;5*4;8*3;-1+2*3;1+1;5-3;5/3;-6/3;-(1+3)*5+3;(1+3)/2;-4/(1+1)"

6.9.5 この節のまとめ

  • 文法チェック、エラー処理無しだが、電卓として計算できるところまでもっていった
  • (バグをみつけたら、教えて下さい。お願い致します。)

6.9.6 この節の追記

  • 文法チェックを特別にコーディングしなくても、デフォである程度のエラー管理してくれるようで、文法間違ってたら、メッセージがでた。ただし、文法エラーという表示ではなかった。

7 簡易プログラム言語の作成その1

  • 簡易電卓に以下の機能を追加したプログラム言語を作成する
    • 変数に結果を代入可能
    • 変数をprint命令で表示可能
    • 直接計算結果をprint命令で表示可能
    • 文字列もprint命令で表示可能
    • 計算式にも変数を使える
    • コメント文を入れれる

7.1 parserと、lexerのファイル分離

  • ファイル分離しない方法で、文字列を扱う方法がわからなかったので、ファイルを2つに分ける
  • ファイルを分けると、parser側で、’+’等の記法でトークンを処理できなくなるようだったので、全ての特別な扱いをする記号に名前をつけて、Lexer側に追記した。

7.1.1 以下の操作を行っている動画


7.2 parserと、lexerのファイル分離 する手順

  • 前の章のCalc.g4をベースに MyLangLexer.g4 MyLangParser.g4 を作成する。MyLangLexer.g4 がトークンを抽出するルールで、MyLangParser.g4 がパースするルールを記述している。
  • 色々ためして、数式をパース出来るものが以下
  • 数式の終わりはセミコロンのみに変更(前の章では改行もOKだったが)
  • MyLangLexer.g4 は以下の内容で作成する。作成は使い慣れたテキストエディタでOK
lexer grammar MyLangLexer;

N     : [0-9]
      | [1-9][0-9]+;
ADD   : '+'; 
SUB   : '-'; 
MUL   : '*'; 
DIV   : '/'; 
SB    : '=';
LBR   : '(';
RBR   : ')';
EL : [;];          // semicolons
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
  • MyLangParser.g4 は以下の内容で作成する。同じく、作成は使い慣れたテキストエディタでOK
parser grammar MyLangParser;
options { tokenVocab=MyLangLexer; }
lines:
     | command
     | lines command
     | EOF;
command : expr EL;
expr  : LBR expr RBR #myBr
      | expr MUL expr #myMul
      | expr DIV expr #myDiv
      | expr ADD expr #myAdd
      | expr SUB expr #mySub
      | N #myNum
      | SUB N #myMinusNum
      | SUB LBR expr RBR #myMinus ;

7.2.1 コンパイルして、動作確認

antlr4 MyLangParser.g4 MyLangLexer.g4 
javac MyLang*java
grun MyLang lines -gui

7.2.2 この節のまとめ

  • parserルール記述ファイルと、lexer記述ファイルを分離した
  • 分離したものをコンパイルして、試す方法を説明した

7.3 print命令、変数、文字列も扱えるように修正

  • 関係する本家の文書https://github.com/antlr/antlr4/blob/master/doc/lexer-rules.md の”Lexer Commands”の”mode(), pushMode(), popMode, and more”に文字列を処理する方法の例があり、これをルールに追加している
    • モード切替をおこなわないと、文字列のデータの中まで通常のトークン探す処理をしてしまうので、モード切替を行い、文字列の中は、別処理にする記述をおこなっている

7.3.1 以下の操作を行っている動画


7.4 する手順

  • 前の節の2つのg4ファイルを以下に修正する
  • MyLangLexer.g4 は以下の内容で作成する。作成は使い慣れたテキストエディタでOK
    • ~[ほにゃらら]になっていると、ほにゃららを含まない文字列にマッチ
    • 変数名の自由度を高くしていたが、数式等が変数名と解釈されたりしたので、変数名の制限を強くした
    • 文字列の記述方法が[https://github.com/antlr/antlr4/blob/master/doc/lexer-rules.md]] の”Lexer Commands”の”mode(), pushMode(), popMode, and more”に文字列を処理する方法の例があり、これをそのまま使っている。ただし、このままだと、””でかこんだ中でバックスラッシュでエスケープは出来ない。そのルールにするには、より記述が複雑になるため、今回の例ではやっていない。
lexer grammar MyLangLexer;

N     : [0-9]
      | [1-9][0-9]+;
ADD   : '+'; 
SUB   : '-'; 
MUL   : '*'; 
DIV   : '/'; 
SB    : '=';
LBR   : '(';
RBR   : ')';
PRINT : 'print';
// VARIABLE : [A-Z]~[=; "'.+\-*/()\t\r\n]*;
VARIABLE : [a-zA-Z_][a-zA-Z0-9_]*;
EL : [;];          // semicolons
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines

// String
LQUOTE : '"' -> more, mode(STR) ;
mode STR;
STRING : '"' -> mode(DEFAULT_MODE) ; // token we want parser to see
TEXT : . -> more ; // collect more text for string
  • MyLangParser.g4 は以下の内容で作成する。作成は使い慣れたテキストエディタでOK
    • 変数に数式処理の結果を代入可能にするルール追加
    • 変数に文字列をを代入可能にするルール追加
    • print命令を追加(数式処理結果,文字列,変数の中身を出力可能)
    • 数式中にも変数を使えるようにルール追加
parser grammar MyLangParser;
options { tokenVocab=MyLangLexer; }
lines:
     | command
     | lines command
     | EOF;
command : VARIABLE SB expr EL   #mySubstitutionExpr
	| VARIABLE SB STRING EL #mySubstitutionStr
	| printout              #myPrintout;
printout :PRINT expr EL         #myPrintOutExpr
	 |PRINT STRING EL       #myPrintOutString
	 |PRINT VARIABLE EL     #myPrintOutVariable;
expr  : LBR expr RBR #myBr
      | expr MUL expr #myMul
      | expr DIV expr #myDiv
      | expr ADD expr #myAdd
      | expr SUB expr #mySub
      | N #myNum
      | VARIABLE #myVal
      | SUB N #myMinusNum
      | SUB VARIABLE #myMinusVal
      | SUB LBR expr RBR #myMinus ;

7.4.1 コンパイルして、動作確認

antlr4 MyLangParser.g4 MyLangLexer.g4 
javac MyLang*java
grun MyLang lines -gui

7.4.2 この節のまとめ

7.5 コメント文も扱えるように修正

7.5.1 以下の操作を行っている動画


  • MyLangLexer.g4 を以下の内容で作成する。作成は使い慣れたテキストエディタでOK。 MyLangParser.g4は前の章と同じ
lexer grammar MyLangLexer;

N     : [0-9]
      | [1-9][0-9]+;
ADD   : '+'; 
SUB   : '-'; 
MUL   : '*'; 
DIV   : '/'; 
SB    : '=';
LBR   : '(';
RBR   : ')';
PRINT : 'print';
// VARIABLE : [A-Z]~[=; "'.+\-*/()\t\r\n]*;
VARIABLE : [a-zA-Z_][a-zA-Z0-9_]*;
EL : [;];          // semicolons
BLOCK_COMMENT
	: '/*' .*? '*/' -> channel(HIDDEN)
	;
LINE_COMMENT
	: '//' ~[\r\n]* -> channel(HIDDEN)
	;
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines

// String
LQUOTE : '"' -> more, mode(STR) ;
mode STR;
STRING : '"' -> mode(DEFAULT_MODE) ; // token we want parser to see
TEXT : . -> more ; // collect more text for string

7.5.2 コンパイルして、動作確認

antlr4 MyLangParser.g4 MyLangLexer.g4 
javac MyLang*java
grun MyLang lines -gui

7.5.3 この節のまとめ

7.6 数式計算と、print 計算式; の動作部分のみ、Listenerメソッド追加

  • Pythonでリスナー関数が呼び出されるようにして、インタプリタとして動作するようにコードを追加する
  1. 以下の操作を行っている動画

  2. 数式計算と、print 計算式; の動作部分のみ、Listenerメソッド追加 する手順
    • 前節の MyLangLexer.g4 MyLangParser.g4 利用して、Pythonのコードを自動生成する
    antlr4 -Dlanguage=Python3 MyLangLexer.g4 MyLangParser.g4
    
    • MyLangLexer.py MyLangParser.py MyLangParserListener.py が生成される
    • MyLangParserListener.py に それぞれの処理を追加する。
  3. MyLangParserListener.py の修正例
    • 未作成今後作成予定
    
    
  4. main.py の作成例
    import ipdb
    import sys
    from antlr4 import *
    from MyLangLexer import MyLangLexer
    from MyLangParser import MyLangParser
    from MyLangParserListener import MyLangParserListener
    
    class KeyPrinter(MyLangParserListener):
    	def exitKey(self, ctx):
    		pass
    
    def main(argv):
    	input = InputStream(argv[1])
    	lexer = MyLangLexer(input)
    	stream = CommonTokenStream(lexer)
    	parser = MyLangParser(stream)
    	tree = parser.lines()
    	#print(tree.getChild(0))
    	#print(tree.getChild(0).getText())
    	##print(tree.getChild(0).toStringTree())
    	#ipdb.set_trace()
    	printer = KeyPrinter()
    	walker = ParseTreeWalker()
    	walker.walk(printer, tree)
    
    if __name__ == '__main__':
    	main(sys.argv)
    
    
  5. MyLangParserListener.py を以下に修正
    • 前章の計算する部分と、print 計算式の部分だけコード追加
    # Generated from MyLangParser.g4 by ANTLR 4.9.1
    from antlr4 import *
    from collections import deque
    if __name__ is not None and "." in __name__:
    	from .MyLangParser import MyLangParser
    else:
    	from MyLangParser import MyLangParser
    
    # This class defines a complete listener for a parse tree produced by MyLangParser.
    # Generated from MyLangParser.g4 by ANTLR 4.9.1
    from antlr4 import *
    from collections import deque
    if __name__ is not None and "." in __name__:
    	from .MyLangParser import MyLangParser
    else:
    	from MyLangParser import MyLangParser
    
    # This class defines a complete listener for a parse tree produced by MyLangParser.
    class MyLangParserListener(ParseTreeListener):
    	s = deque([])
    
    	# Enter a parse tree produced by MyLangParser#lines.
    	def enterLines(self, ctx:MyLangParser.LinesContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#lines.
    	def exitLines(self, ctx:MyLangParser.LinesContext):
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#mySubstitutionExpr.
    	def enterMySubstitutionExpr(self, ctx:MyLangParser.MySubstitutionExprContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#mySubstitutionExpr.
    	def exitMySubstitutionExpr(self, ctx:MyLangParser.MySubstitutionExprContext):
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#mySubstitutionStr.
    	def enterMySubstitutionStr(self, ctx:MyLangParser.MySubstitutionStrContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#mySubstitutionStr.
    	def exitMySubstitutionStr(self, ctx:MyLangParser.MySubstitutionStrContext):
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#myPrintout.
    	def enterMyPrintout(self, ctx:MyLangParser.MyPrintoutContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#myPrintout.
    	def exitMyPrintout(self, ctx:MyLangParser.MyPrintoutContext):
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#myPrintOutExpr.
    	def enterMyPrintOutExpr(self, ctx:MyLangParser.MyPrintOutExprContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#myPrintOutExpr.
    	def exitMyPrintOutExpr(self, ctx:MyLangParser.MyPrintOutExprContext):
    	    #print(ctx.getText())
    	    if(len(self.s)>0):
    		    print(self.s.pop())
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#myPrintOutString.
    	def enterMyPrintOutString(self, ctx:MyLangParser.MyPrintOutStringContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#myPrintOutString.
    	def exitMyPrintOutString(self, ctx:MyLangParser.MyPrintOutStringContext):
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#myPrintOutVariable.
    	def enterMyPrintOutVariable(self, ctx:MyLangParser.MyPrintOutVariableContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#myPrintOutVariable.
    	def exitMyPrintOutVariable(self, ctx:MyLangParser.MyPrintOutVariableContext):
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#myMul.
    	def enterMyMul(self, ctx:MyLangParser.MyMulContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#myMul.
    	def exitMyMul(self, ctx:MyLangParser.MyMulContext):
    	    a=self.s.pop()
    	    b=self.s.pop()
    	    self.s.append(a*b)
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#myNum.
    	def enterMyNum(self, ctx:MyLangParser.MyNumContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#myNum.
    	def exitMyNum(self, ctx:MyLangParser.MyNumContext):
    	    self.s.append(int(ctx.getText()))
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#myMinusNum.
    	def enterMyMinusNum(self, ctx:MyLangParser.MyMinusNumContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#myMinusNum.
    	def exitMyMinusNum(self, ctx:MyLangParser.MyMinusNumContext):
    	    self.s.append(int(ctx.getText()))
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#myMinus.
    	def enterMyMinus(self, ctx:MyLangParser.MyMinusContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#myMinus.
    	def exitMyMinus(self, ctx:MyLangParser.MyMinusContext):
    	    a=self.s.pop()
    	    self.s.append(-a)
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#myMinusVal.
    	def enterMyMinusVal(self, ctx:MyLangParser.MyMinusValContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#myMinusVal.
    	def exitMyMinusVal(self, ctx:MyLangParser.MyMinusValContext):
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#mySub.
    	def enterMySub(self, ctx:MyLangParser.MySubContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#mySub.
    	def exitMySub(self, ctx:MyLangParser.MySubContext):
    	    a=self.s.pop()
    	    b=self.s.pop()
    	    self.s.append(b-a)
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#myVal.
    	def enterMyVal(self, ctx:MyLangParser.MyValContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#myVal.
    	def exitMyVal(self, ctx:MyLangParser.MyValContext):
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#myDiv.
    	def enterMyDiv(self, ctx:MyLangParser.MyDivContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#myDiv.
    	def exitMyDiv(self, ctx:MyLangParser.MyDivContext):
    	    a=self.s.pop()
    	    b=self.s.pop()
    	    self.s.append(b/a)
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#myAdd.
    	def enterMyAdd(self, ctx:MyLangParser.MyAddContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#myAdd.
    	def exitMyAdd(self, ctx:MyLangParser.MyAddContext):
    	    a=self.s.pop()
    	    b=self.s.pop()
    	    self.s.append(a+b)
    	    pass
    
    
    	# Enter a parse tree produced by MyLangParser#myBr.
    	def enterMyBr(self, ctx:MyLangParser.MyBrContext):
    	    pass
    
    	# Exit a parse tree produced by MyLangParser#myBr.
    	def exitMyBr(self, ctx:MyLangParser.MyBrContext):
    	    pass
    
    
    
    del MyLangParser
    
    

7.6.1 動作確認

python main.py "print (1+3)*4+5*3;print -(1-5)*3;print 4/2;"
  • 出力
31
12
2.0

7.6.2 この節のまとめ

  • print 計算式; が上手く動作するように修正

7.7 残りのListener部分処理追加

  • 変数処理や、文字列操作等の処理を追加
  • まだ作って動作確認はしてない。作りしだい、文書に追記します。
  • ここまでの復習でやってもらっても良いかも
  1. 以下の操作を行っている動画

7.7.1 MyLangParserListener.py を以下に修正

  • 前章の計算する部分と、print 計算式の部分だけコード追加
  • vdicという連想配列をメンバ変数として用意して、変数関係に利用してます。
  • 内容で重要な部分
    • ctx.getText() でそのリスナー関数が呼ばれたところ全体の文字列を取得できる。
    • ctx.getChild(0).getText() で複数の要素があるところのリスナー関数は、1番目の要素の文字列取り出せる。
    • ctx.getChild(1).getText() で複数の要素があるところのリスナー関数は、2番目の要素の文字列取り出せる。要素数が1の時はエラーになる。
    • ctx.getChild(3).getText() で複数の要素があるところのリスナー関数は、3番目の要素の文字列取り出せる。要素数が2以下の時はエラーになる。
# Generated from MyLangParser.g4 by ANTLR 4.9.1
from antlr4 import *
from collections import deque
if __name__ is not None and "." in __name__:
	from .MyLangParser import MyLangParser
else:
	from MyLangParser import MyLangParser

# This class defines a complete listener for a parse tree produced by MyLangParser.
class MyLangParserListener(ParseTreeListener):
	s = deque([])
	vdic = {}

	# Enter a parse tree produced by MyLangParser#lines.
	def enterLines(self, ctx:MyLangParser.LinesContext):
	    pass

	# Exit a parse tree produced by MyLangParser#lines.
	def exitLines(self, ctx:MyLangParser.LinesContext):
	    pass


	# Enter a parse tree produced by MyLangParser#mySubstitutionExpr.
	def enterMySubstitutionExpr(self, ctx:MyLangParser.MySubstitutionExprContext):
	    pass

	# Exit a parse tree produced by MyLangParser#mySubstitutionExpr.
	def exitMySubstitutionExpr(self, ctx:MyLangParser.MySubstitutionExprContext):
	    #print("exitMySubstitutionExpr")
	    self.vdic[ctx.getChild(0).getText()]=self.s.pop();
	    #print(self.vdic[ctx.getChild(0).getText()])
	    #print(ctx.getText())
	    pass


	# Enter a parse tree produced by MyLangParser#mySubstitutionStr.
	def enterMySubstitutionStr(self, ctx:MyLangParser.MySubstitutionStrContext):
	    pass

	# Exit a parse tree produced by MyLangParser#mySubstitutionStr.
	def exitMySubstitutionStr(self, ctx:MyLangParser.MySubstitutionStrContext):
	    #print("exitMySubstitutionStr")
	    self.vdic[ctx.getChild(0).getText()]=ctx.getChild(2).getText()[1:-1]
	    #print(self.vdic[ctx.getChild(0).getText()])
	    #print(ctx.getText())
	    pass


	# Enter a parse tree produced by MyLangParser#myPrintout.
	def enterMyPrintout(self, ctx:MyLangParser.MyPrintoutContext):
	    pass

	# Exit a parse tree produced by MyLangParser#myPrintout.
	def exitMyPrintout(self, ctx:MyLangParser.MyPrintoutContext):
	    pass


	# Enter a parse tree produced by MyLangParser#myPrintOutExpr.
	def enterMyPrintOutExpr(self, ctx:MyLangParser.MyPrintOutExprContext):
	    pass

	# Exit a parse tree produced by MyLangParser#myPrintOutExpr.
	def exitMyPrintOutExpr(self, ctx:MyLangParser.MyPrintOutExprContext):
	    #print(ctx.getText())
	    if(len(self.s)>0):
	       print(self.s.pop())
	    pass


	# Enter a parse tree produced by MyLangParser#myPrintOutString.
	def enterMyPrintOutString(self, ctx:MyLangParser.MyPrintOutStringContext):
	    pass

	# Exit a parse tree produced by MyLangParser#myPrintOutString.
	def exitMyPrintOutString(self, ctx:MyLangParser.MyPrintOutStringContext):
	    #str=ctx.getText()
	    #print(ctx.getChild(0).getText())
	    #print(ctx.getChild(1).getText())
	    #print(str)
	    #str2=str[6:-2]
	    print(ctx.getChild(1).getText()[1:-1])
	    pass


	# Enter a parse tree produced by MyLangParser#myPrintOutVariable.
	def enterMyPrintOutVariable(self, ctx:MyLangParser.MyPrintOutVariableContext):
	    pass

	# Exit a parse tree produced by MyLangParser#myPrintOutVariable.
	def exitMyPrintOutVariable(self, ctx:MyLangParser.MyPrintOutVariableContext):
	    print(self.vdic[ctx.getChild(1).getText()])
	    pass


	# Enter a parse tree produced by MyLangParser#myMul.
	def enterMyMul(self, ctx:MyLangParser.MyMulContext):
	    pass

	# Exit a parse tree produced by MyLangParser#myMul.
	def exitMyMul(self, ctx:MyLangParser.MyMulContext):
	    a=self.s.pop()
	    b=self.s.pop()
	    self.s.append(a*b)
	    pass


	# Enter a parse tree produced by MyLangParser#myNum.
	def enterMyNum(self, ctx:MyLangParser.MyNumContext):
	    pass

	# Exit a parse tree produced by MyLangParser#myNum.
	def exitMyNum(self, ctx:MyLangParser.MyNumContext):
	    self.s.append(int(ctx.getText()))
	    pass


	# Enter a parse tree produced by MyLangParser#myMinusNum.
	def enterMyMinusNum(self, ctx:MyLangParser.MyMinusNumContext):
	    pass

	# Exit a parse tree produced by MyLangParser#myMinusNum.
	def exitMyMinusNum(self, ctx:MyLangParser.MyMinusNumContext):
	    self.s.append(int(ctx.getText()))
	    pass


	# Enter a parse tree produced by MyLangParser#myMinus.
	def enterMyMinus(self, ctx:MyLangParser.MyMinusContext):
	    pass

	# Exit a parse tree produced by MyLangParser#myMinus.
	def exitMyMinus(self, ctx:MyLangParser.MyMinusContext):
	    a=self.s.pop()
	    self.s.append(-a)
	    pass


	# Enter a parse tree produced by MyLangParser#myMinusVal.
	def enterMyMinusVal(self, ctx:MyLangParser.MyMinusValContext):
	    pass

	# Exit a parse tree produced by MyLangParser#myMinusVal.
	def exitMyMinusVal(self, ctx:MyLangParser.MyMinusValContext):
	    #print("exitMyMinusVal")
	    #print(ctx.getChild(1).getText())
	    self.s.append(-self.vdic[ctx.getChild(1).getText()])
	    pass


	# Enter a parse tree produced by MyLangParser#mySub.
	def enterMySub(self, ctx:MyLangParser.MySubContext):
	    pass

	# Exit a parse tree produced by MyLangParser#mySub.
	def exitMySub(self, ctx:MyLangParser.MySubContext):
	    a=self.s.pop()
	    b=self.s.pop()
	    self.s.append(b-a)
	    pass


	# Enter a parse tree produced by MyLangParser#myVal.
	def enterMyVal(self, ctx:MyLangParser.MyValContext):
	    pass

	# Exit a parse tree produced by MyLangParser#myVal.
	def exitMyVal(self, ctx:MyLangParser.MyValContext):
	    self.s.append(self.vdic[ctx.getText()])
	    pass


	# Enter a parse tree produced by MyLangParser#myDiv.
	def enterMyDiv(self, ctx:MyLangParser.MyDivContext):
	    pass

	# Exit a parse tree produced by MyLangParser#myDiv.
	def exitMyDiv(self, ctx:MyLangParser.MyDivContext):
	    a=self.s.pop()
	    b=self.s.pop()
	    self.s.append(b/a)
	    pass


	# Enter a parse tree produced by MyLangParser#myAdd.
	def enterMyAdd(self, ctx:MyLangParser.MyAddContext):
	    pass

	# Exit a parse tree produced by MyLangParser#myAdd.
	def exitMyAdd(self, ctx:MyLangParser.MyAddContext):
	    a=self.s.pop()
	    b=self.s.pop()
	    self.s.append(a+b)
	    pass


	# Enter a parse tree produced by MyLangParser#myBr.
	def enterMyBr(self, ctx:MyLangParser.MyBrContext):
	    pass

	# Exit a parse tree produced by MyLangParser#myBr.
	def exitMyBr(self, ctx:MyLangParser.MyBrContext):
	    pass



del MyLangParser

7.7.2 動作確認

python main.py "print 1+1;print \"hello\";X=\"sss\";print X;Y=-(5-1)*5;print Y;Z=5*Y;print -Z;print Z;"
  • 出力
2
hello
sss
-20
100
-100

7.7.3 この節のまとめ

  • 変数がらみの処理追加し、変数を利用可能で、文字列も変数に入れて処理できる簡易プログラム言語を作成した
  • ループ、関数定義、if文は現状使えない簡易言語を作れれた。他の機能追加も、多分作れそうな感じまできた。
  • ここまでに利用した機能はANTLR4のほんの一部と思われるが、もっと複雑なプログラム言語、独自の設定ファイルや、変換ツール、フィルターも、ここまでのテクだけ、あるいはちょっとプラスアルファで作れそう。
  • 動作確認はちょっとしか行ってないので、バグやおかしな動作があるかもしれません。みつけたら教えてください。不具合を修正するのも練習に良いと思うので、みつけたら、修正していただいた方が良いと思います。

7.8 ファイル指定して実行できるバージョンのmain2.py作成

  • コマンドラインの引数として命令を直接与えていたけど、ファイルで命令を与えれるようにしたmain2.pyを作成
  1. 以下の操作を行っている動画

7.8.1 main2.py を以下で作成

  • main.pyをベースに作成
import ipdb
import sys
from antlr4 import *
from MyLangLexer import MyLangLexer
from MyLangParser import MyLangParser
from MyLangParserListener import MyLangParserListener

class KeyPrinter(MyLangParserListener):
	def exitKey(self, ctx):
		pass

def main(argv):
	with open(argv[1]) as f:
	  input = InputStream(f.read())
	  lexer = MyLangLexer(input)
	  stream = CommonTokenStream(lexer)
	  parser = MyLangParser(stream)
	  tree = parser.lines()
	  #print(tree.getChild(0))
	  #print(tree.getChild(0).getText())
	  ##print(tree.getChild(0).toStringTree())
	  #ipdb.set_trace()
	  printer = KeyPrinter()
	  walker = ParseTreeWalker()
	  walker.walk(printer, tree)

if __name__ == '__main__':
	main(sys.argv)
  • test01.mylangファイルを以下の内容で作成
/* 
   複数行のコメント
*/  
// 一行のコメント
X=12;
print 3*X;
print -X*5;
S="Hello";
print S;
print "World!";
print -(5-1)*5;
print -(5+1)*5;

7.8.2 動作確認

python3 main2.py test01.mylang 
or 
python main2.py test01.mylang 
  • その時の出力

7.8.3 この節のまとめ

  • ファイルからプログラムを読み込めるmain2.pyを作成

7.9 この章のまとめ

  • 以下の処理を追加して、簡易プログラム言語を作ってみた。
    • 変数処理
    • 文字列処理
    • 計算式に変数を利用可能に改良
    • print命令の実装
  • 今後
    • もしかしたら、ループとか、関数定義、関数利用、if文等の処理を追加した、簡易言語パート2を作るかもしれない。
    • もともと別の用途として、Antler4を使いだしたので、他の用途の簡易言語を作るかもしれない。
    • いちおう簡易言語作れるようになったので、ここで、この文書や、動画シリーズ終わるかも

8 今後

  • 今後も文書追加していきます。

9 この文書のチェンジログ

  • 2021/01/17 初版
  • 2021/01/18 自然数を解釈する の章, 足し算表現、引き算表現の解釈処理追加 の章, 掛け算表現、割り算表現の解釈処理追加, 括弧でくるんだ部分を優先して処理するように修正 追加
  • 2021/01/25 括弧でくるんだ部分を優先して処理するように修正 修正
  • 2021/01/25 複数数式入力に対応する修正, 現時点で最新バージョンのAntlr4をインストール(2021/1/25現在最新の4.9.1をインストール), アクション用のラベル追加, Python用のコード生成, Python用のコード作成(Listenerメソッドが動くように修正), 電卓として動作するように処理を書く(Python向け) 追加
  • 2021/01/27 簡易プログラム言語の作成その1 の章追加
  • 2021/01/28 簡易プログラム言語の作成その1 の章の def exitMyMinusVal(self, ctx:MyLangParser.MyMinusValContext): にバグがあったので修正(デバッグ用print文もコメントアウト)
  • 2021/01/31 簡易プログラム言語の作成その1 の章の 「ファイル指定して実行できるバージョンのmain2.py作成」の節追加

著者: NM Max

Created: 2021-01-31 日 15:11

Validate

SoX(Sound eXchange)の使い方例

SoX(Sound eXchange)の使い方例

1 概要

  • SoX(Sound eXchange), 音声処理のためのスイスアーミーナイフ
  • なんでも出来るがゆえ、使い方難しい

2 この文書作ろうと思ったきっかけ

  • 備忘録かねて作ることに

4 似たツール

  • CSound (音作成関係面では)

5 インストール情報

  • Windows, Mac用は https://sourceforge.net/projects/sox/files/sox/ からダウンロード可能,最新のバージョン番号の該当のファイルをダウンロードして、実行すれば多分インストールされるはず
  • Ubuntu(Debianも)の場合は、パッケージになってるので、以下でOK
sudo apt install sox
  • Linuxの他のディストリビューションも、SoXは必ずパッケージ化されてると思うので、そのディストリビューションのパッケージ管理コマンドでインストール出来る。

6 音の作成

  • 色々な音を簡単に作成して試すことが出来る(効果音とか作りやすい)

6.1 指定時間の無音音声ファイル作成

6.1.1 以下の操作を行っている動画


6.1.2 指定時間の無音音声ファイル作成手順

  • 3秒間の無音
sox -n silence.wav trim 0.0 3.0 
  • オプションの意味は
    • -n : 入力無し
    • silence.wav 出力ファイル名
    • trim 0.0 3.0 :最初の3秒切り出し
  • 以下でもいけた(ゴミ数値はいってるかもしれないけど、聞いても無音)
sox -n silence.wav synth 3 sine 100 vol 0 
  • オプションの意味は
    • -n : 入力無し
    • silence.wav 出力ファイル名
    • synth 3 sine 100 : 音声合成3秒間sine波形で、周波数100Hz
    • vol 0 : ボリューム0

6.1.3 この節のまとめ

  • 指定時間の無音ファイルの生成

6.2 指定時間の指定周波数のサイン波作成

6.2.1 以下の操作を行っている動画


6.2.2 指定時間の指定周波数のサイン波ファイル作成 手順

  • 周波数500Hzの3秒の波形を生成して、音を聞いてみます。
play -n synth 3 sine 500
  • オプションの意味は
    • -n : 入力無し
    • synth 3 sine 500 : 音声合成3秒間sine波形で、周波数500Hz
  • 今の音を 500.wav というファイルに保存する場合は以下で出来ます。
sox -n 500.wav synth 3 sine 500
  • オプションの意味は
    • -n : 入力無し
    • 500.wav : 出力ファイル名
    • synth 3 sine 500 : 音声合成3秒間sine波形で、周波数500Hz

6.2.3 この節のまとめ

  • playコマンドの使い方の例(playコマンドで試して、上手くいったものをsoxコマンドでファイル出力するのがオススメ)
  • 指定時間の指定周波数のサイン波ファイル作成をおこなった
  • (周波数を指定しない場合440Hzがデフォで使われる)http://sox.sourceforge.net/sox.html(でsynthで検索)

6.3 指定時間の色々な波形の音の作成

6.3.1 以下の操作を行っている動画


6.3.2 指定時間の指定周波数の色々な波形の作成 手順

  • マニュアルのsynth部分を確認すると以下の波形が指定可能です(デフォルトはsine) http://sox.sourceforge.net/sox.html(でwhiteあるいはsynthで検索)
  • Linux系なら以下でマニュアルみれる
man sox
  • sine
  • square
  • triangle
  • sawtooth
  • trapezium
  • exp
  • [white]noise
  • tpdfnoise
  • pinknoise
  • brownnoise
  • pluck
  1. square
    • 周波数500Hzの3秒の波形を生成して、音を聞いてみます。
    play -n synth 3 square 500
    
    • オプションの意味は
      • -n : 入力無し
      • 500.wav : 出力ファイル名
      • synth 3 square 500 : 音声合成3秒間square波形で、周波数500Hz
  2. triangle
    • 周波数500Hzの3秒の波形を生成して、音を聞いてみます。
    play -n synth 3 triangle 500
    
    • オプションの意味は
      • -n : 入力無し
      • 500.wav : 出力ファイル名
      • synth 3 triangle 500 : 音声合成3秒間triangle波形で、周波数500Hz
  3. sawtooth
    • 周波数500Hzの3秒の波形を生成して、音を聞いてみます。
    play -n synth 3 sawtooth 500
    
    • オプションの意味は
      • -n : 入力無し
      • 500.wav : 出力ファイル名
      • synth 3 sawtooth 500 : 音声合成3秒間sawtooth波形で、周波数500Hz
  4. trapezium
    • 周波数500Hzの3秒の波形を生成して、音を聞いてみます。
    play -n synth 3 trapezium 500
    
    • オプションの意味は
      • -n : 入力無し
      • 500.wav : 出力ファイル名
      • synth 3 trapezium 500 : 音声合成3秒間trapezium波形で、周波数500Hz
  5. exp
    • 周波数500Hzの3秒の波形を生成して、音を聞いてみます。
    play -n synth 3 exp 500
    
    • オプションの意味は
      • -n : 入力無し
      • 500.wav : 出力ファイル名
      • synth 3 exp 500 : 音声合成3秒間exp波形で、周波数500Hz
  6. pluck
    • 周波数500Hzの3秒の波形を生成して、音を聞いてみます。
    play -n synth 3 pluck 500
    
    • オプションの意味は
      • -n : 入力無し
      • 500.wav : 出力ファイル名
      • synth 3 pluck 500 : 音声合成3秒間pluck波形で、周波数500Hz

6.3.3 この節のまとめ

  • sine以外の波形を生成して聴いてみた
  • noise系は不快な音になるので、各自お試しください。(ノイズ系では周波数指定は意味なし)

6.4 プッシュフォンの音をSoXで作ってみる

6.4.1 以下の操作を行っている動画


6.4.2 プッシュフォンの音をSoXで作ってみるの手順

  • 「プッシュホン 周波数」でググると、使っている周波数を調べることが出来る
    • 1209Hz,1336Hz,1447Hz,1633Hzと 697Hz,770Hz,852Hz,941Hzの組み合わせ
    • 9,5,1なら1447Hz+852Hz, 1336Hz+770Hz, 1209Hz+697Hz
play -n synth 0.5 sine 1447 sine 852  
play -n synth 0.5 sine 1336 sine 770
play -n synth 0.5 sine 1209 sine 697
  • オプションの意味は
    • -n : 入力無し
    • synth 0.5 sine 1447 sine 852: 音声合成0.5秒間sine波形で、周波数1447Hzと周波数852Hzの和音
  • 一度にやると
play -n synth 0.5 sine 1447 sine 852  ; play -n synth 0.5 sine 1336 sine 770 ; play -n synth 0.5 sine 1209 sine 697

6.4.3 この節のまとめ

  • 今までの知識を元に、プッシュフォンの音を合成してみた

6.5 周波数を変化させてみる1

6.5.1 以下の操作を行っている動画


6.5.2 周波数を変化させてみる1

  • 100Hzから1000Hzまで
play -n synth 0.5 sine 100-1000
  • 1000Hzから100Hzまで
play -n synth 0.5 sine 1000-100
  • マニュアルで確認すると、用意されている変化の方法として以下がある。
:      Linear: the tone will change by a fixed number of hertz per second.

+      Square: a second-order function is used to change the tone.

/      Exponential: the tone will change by a fixed number of semitones per second.

-      Exponential: as `/', but initial phase always zero, and stepped (less smooth) frequency changes.
  • :をやってみる
play -n synth 0.5 sine 100:1000
  • +をやってみる
play -n synth 0.5 sine 100+1000
  • /をやってみる
play -n synth 0.5 sine 100/1000

6.5.3 この節のまとめ

  • 周波数を変化させてみた

7 今後

  • 今後も文書追加していきます。

8 この文書のチェンジログ

  • 2021/01/17 初版
  • 2021/01/19 周波数を変化させてみる1 の節追加

著者: NM Max

Created: 2021-01-24 日 07:34

Validate