niszetの日記

アナログCMOS系雑用エンジニアが頑張る備忘録系日記

(Pandoc) Pandocは脚注の設定をreference.docxから持ってこれない

...と思う。

Pandocのバージョンは2.11.4です。いつの間にこんなにバージョン上がってるの…。

久々にPandocのissueでも見るかーって見た一個目がこれだったので、これをやることにした。

github.com

Wordの脚注の線と脚注の文字の間のスペースを詰めたいという話。

まずはこの脚注の線を修正する方法。ググれば出てくるが、

  1. 下書きモードの表示にする
  2. ツールバーの参考資料から注の表示を選択して表示させる
  3. 出てきた脚注のなかで脚注の境界線を選択する。

すると、よくわからんが線が表示される。これを消して他の文字にするなどすれば脚注の線は他の文字に変えることが出来る。これ以外の修正方法があるのかは知らない。

なお、この情報はdocx内ではfootnotes.xml中に含まれており、専用のタグ、<w:separator />を使って示されている。もう一個の方は<w:continuationSeparator />である。<w:footnote w:type="separator" w:id="-1">などで調べると良い。w:idは他の数字かもしれないので注意。

さて、この脚注だが実はこの画面上で右クリックすることでフォントやスタイル、段落設定をすることが可能である。そのため、段落設定で段落後のスペースを0にすることによって、脚注の区切り線と脚注の文字との間を詰めることが可能なのである。

脚注の設定はココでしか使わないので、そのまま指定しても良いが、使いまわしを考えるならばスタイルを専用に作成して指定する方が良いだろうと思う。とはいえ、reference.docx中のスタイルを別のファイルにマージするとか面倒くさいのであまりやることはないと思うだが…。

さて一方でPandocはこの脚注の設定をreference.docxから拾ってくれないようだ。実行した結果がそうなのだからそうなんだろう。footnotes.xmlから設定を引っこ抜いてくるためには、styles.xmlからスタイルを引っこ抜いてくるのと同様の処理をしないといけないであろう。

ということで、あとでissueに書いたコメントを見直してよくわからなかったとき用にメモを残しておく。真面目にキャプチャとか載せておけばもっといい記事になるのに面倒くさいのでやらない。誰か書いてくれ。

(R) Windows上で parzer パッケージが動かないやつの暫定対応

なんでしょうね

ちょっとkuniezuパッケージを試してみたかったんですが、

github.com

内部で使ってるparzerパッケージがエラー吐いて止まる(Win、32bit版)か止まってしまって処理が返ってこない(Win, 64bit版)という挙動をしていました。

再現できるコードはこれ。

parzer::parse_lon("10")

RToolsは4.0の最新版を入れなおしてもダメでした。一方、Ubuntu上では問題なく動作して、結果として一個前の記事が出来ました(ヨカッタネ)

ってことをTwitterに呟いていたら、僕らのユタ兄さんから、

というアドバイスをいただいて、上記コード実行前に

Sys.setlocale(locale = "C") 

をしたら動くようにはなりました。が、原因がわからないのでちょっと調べてみます。昔のバージョンなら問題なかったのではないだろうか、とかそのあたりですね…(CRANのテストはもちろん通った状態でリリースされているのでそこら辺ではなさそう)

続報

その後、std::regexが問題とわかり…

結局、gccに問題があるのではということまで来ました(主にユタ兄さんの解析によって)

現状では先にあげたように、localeを設定してやり過ごすのが対策になりそうです。ちなみに、regex[]がダメっぽくて、[0]はダメ、(a+)*\dみたいなのはOKでした。こんなこと(コンパイラのバグ)ってあるんですねぇ…(Windowsの日本語localeのみで発生するregexのバグ…)

ちなみに、Windows上でSys.getlocale()するとこうなります。この環境下でのみ発生する、という感じですね(ubuntuのutf8環境では問題なかった)

> Sys.getlocale()
[1] "LC_COLLATE=Japanese_Japan.932;LC_CTYPE=Japanese_Japan.932;LC_MONETARY=Japanese_Japan.932;LC_NUMERIC=C;LC_TIME=Japanese_Japan.932"

(R) Ubuntu 20.04 LTS に RStudio Server をインストールしようとしたらlibssl.so.1.0.0がないと怒られたので対応してインストールするやつ

絶対忘れるのでメモ。

Ubuntu18の方で普通にRをインストールするとR3.xが入ってしまうので、Ubuntu20.04LTSに移行しようとした。

で、Rを入れた後にRStudioをこのページに書かれているコマンドで入れようとしたのだが、

rstudio.com

以下のようなエラーが出てRStudio serverは起動できなかった。

Couldn't find an alternative telinit implementation to spawn.
/usr/lib/rstudio-server/bin/rserver: error while loading shared libraries: libssl.so.1.0.0: cannot open shared object file: No such file or directory

調べたら下記のサイトに書かれていた。

askubuntu.com

投稿から引用すると、/etc/apt/sources.listdeb http://security.ubuntu.com/ubuntu xenial-security main という行を追記し、その後 sudo apt update して sudo apt install libssl1.0.0 してから sudo rstudio-server start して起動できることを確認しました。

とりあえず良かった~

(R)震源レコードフォーマットを読み込む

固定文字長フォーマットの読み込み。

各日のページからデータを読み込むことが出来たので不要になったが、これが出来ないと思っていたので過去の震源データを下記から入手して確認しようとしていた。

www.data.jma.go.jp

欲しい年を選択すると、例えば2016年ならh2016.zipみたいなファイルがダウンロードできる。これを展開すれば2016なるファイルがある。拡張子はないが、これは文字長固定で区切られたファイルで、csvなどのカンマや空白で区切られたファイルではない。

このファイルフォーマットの説明はこちら。

www.data.jma.go.jp

これを読み混むことにする。これはreadr::read_lines()stringr::str_sub()を組み合わせれば出来る。

  ff <- readr::read_lines("h2016")

fx <- function(f){
  d <- data.frame(
  record = stringr::str_sub(f, 1, 1), # レコード種別ヘッダ
  year = stringr::str_sub(f, 2, 5),
  month = stringr::str_sub(f, 6, 7),
  day = stringr::str_sub(f, 8, 9),
  hour = stringr::str_sub(f, 10, 11),
  min = stringr::str_sub(f, 12, 13),
  sec = stringr::str_sub(f, 14, 17),
  err_sec = stringr::str_sub(f, 18, 21), # 標準誤差(秒)
  lat_deg = stringr::str_sub(f, 22, 24), # 緯度(度)
  lat_min = stringr::str_sub(f, 25, 28), # 緯度(分)
  err_lat_min = stringr::str_sub(f, 29, 32), # 標準誤差(分)
  long_deg = stringr::str_sub(f, 33, 36), # 経度(度)
  long_min = stringr::str_sub(f, 37, 40), # 経度(分)
  err_long_min = stringr::str_sub(f, 41, 44), # 標準誤差(分)
  depth = stringr::str_sub(f, 45, 49),
  err_depth = stringr::str_sub(f, 50, 52),
  magnitude1 =stringr::str_sub(f, 53, 54),
  magnitude1_type = stringr::str_sub(f, 55, 55),
  magnitude2 = stringr::str_sub(f, 56, 57),
  magnitude2_type = stringr::str_sub(f, 58, 58),
  used_soujihyo = stringr::str_sub(f, 59, 59),
  shingen_hyoka = stringr::str_sub(f, 60, 60),
  shingen_hojo = stringr::str_sub(f, 61, 61),
  max_shindo = stringr::str_sub(f, 62, 62),
  higai = stringr::str_sub(f, 63, 63),
  tsunami = stringr::str_sub(f, 64, 64),
  daichiku = stringr::str_sub(f, 65, 65),
  shochiku = stringr::str_sub(f, 66, 68),
  shino_chimei = stringr::str_sub(f, 69, 92),
  kansoku_tensu = stringr::str_sub(f, 93, 95),
  shingen_kettei_flag = stringr::str_sub(f, 96, 96)
  )
  d
}

fx(ff) -> df

これで良い。ただし得られるものは全て文字なので、適当に型変換する。depthは" 0 4" みたいなデータがあり、これを適切に変換する方法がわからないのでNAが返るようにしている(暗黙にNAになるので他のデータのエラーを見逃す可能性があるため注意。エラー処理を入れることをお勧めします。マグニチュードは例にCまでしか書いてなかったのでこのようにした。D以降があれば定義追加すればよいでしょう。 " " をNAとするかそのままにするかは好みかもしれません。NAでない場合の方が取り扱いやすいこともあるので。 たまに表示幅あわせで空白が入ってるケースがあるので注意。明示的にas.integerせずにwrite_csvしてread_csvしても、"00"は文字列の扱いなので注意、など細かい点に注意が必要です(下記では明示的に変換をしている)。 また、記号ではよくわからないもの(震度など)は別途変換関数を作ってあげると良さそうです(やってません)

fx2 <- function(df){
  df$year <- as.integer(df$year)

  df$month <- as.integer(df$month)
  df$day <- as.integer(df$day)
  df$hour <- as.integer(df$hour)
  df$min <- as.integer(df$min)
  df$sec <- as.integer(df$sec)/100
  df$err_sec <- as.integer(df$err_sec)/100
  df$lat_deg <- as.integer(str_remove(df$lat_deg, " ")) # remove space between "-" and number.
  df$lat_min <- as.integer(df$lat_min)/100
  df$err_lat_min <- as.integer(df$err_lat_min)/100
  df$long_deg <- as.integer(str_remove(df$long_deg, " ")) # remove space between "-" and number.
  df$long_min <- as.integer(df$long_min)/100
  df$err_long_min <- as.integer(df$err_long_min)/100

  df$depth = as.integer(depth)/100 # "注意。  0 4" みたいな謎フォーマットはNAになる。
  df$err_depth <- as.integer(df$err_depth)/100
  df$magnitude1 <- sup_magnitude(df$magnitude1)
  df$magnitude1_type = dplyr::na_if(df$magnitude1_type , " ")
  df$magnitude2 <- sup_magnitude(df$magnitude2)
  df$magnitude2_type = dplyr::na_if(df$magnitude2_type , " ")
  df$used_soujihyo = dplyr::na_if(df$used_soujihyo , " ")
  df$shingen_hyoka = dplyr::na_if(df$shingen_hyoka , " ")
  df$shingen_hojo = dplyr::na_if(df$shingen_hojo , " ")
  df$max_shindo = dplyr::na_if(df$max_shindo , " ")
  df$higai = dplyr::na_if(df$higai , " ")
  df$tsunami = dplyr::na_if(df$tsunami , " ")

  df$daichiku <- as.integer(df$daichiku)
  df$shochiku <- as.integer(df$shochiku)
  df$kansoku_tensu <- as.integer(df$kansoku_tensu)

  df
}

# 補助関数
sup_magnitude <- function(mag){
  mag <- stringr::str_replace(mag, "A", "-1")
  mag <- stringr::str_replace(mag, "B", "-2")
  mag <- stringr::str_replace(mag, "C", "-3")
  mag <- as.integer(mag)/10
  mag
}

fx2(df) -> df

(R)気象庁の震源リストからスクレイピング(コード一部更新した)

robots.txt とかも自分で一度は目を通しておこうね。

さて、以前の日記で気象庁の各日の震源データが消えていると思ったら見つかりました~ってのを書きました。

niszet.hatenablog.com

今回はそのページからデータを取ってくる作業をします。手作業でも良いかなと思ったらこれは日毎にページが分かれているわけですね~。流石にこれを手でやるのはちょっとシンドイので、久々にスクレイピングでやっつけます。

丁度良いことに、昨年末のJapan.R 2020にてwatagusaさんのLT、「"polite"で守るWebスクレイピングのエチケット」でpoliteパッケージの存在を知ったので、これを参考にしてやってみました。

Japan.Rのページはこちら

japanr.connpass.com

また、LTの内容ついてはwatagusaさんのブログにまとまってます。

watagusa.hatenablog.com

とりあえず先にコードを書いてしまうと、2016年の1年間のデータを取ってきて整形してdata.frameにして最後にcsvに書き出すコードは下記のようになります(1/14 1900更新)。

library(rvest)
library(xml2)
library(polite)
library(lubridate)
library(stringr)
library(dplyr)
library(magrittr)

trg <- lubridate::ymd("2016/1/1")
df <- data.frame()

session <- polite::bow(url=stringr::str_c("https://www.data.jma.go.jp/svd/eqev/data/daily_map/", sprintf("%04d%02d%02d", lubridate::year(trg), lubridate::month(trg), lubridate::day(trg)) ,".html"), delay=5)

while(trg < lubridate::ymd("2017/1/1")){

  session <- polite::nod(bow=session, path= stringr::str_c("https://www.data.jma.go.jp/svd/eqev/data/daily_map/", sprintf("%04d%02d%02d", lubridate::year(trg), lubridate::month(trg), lubridate::day(trg)) ,".html"))

  page <- polite::scrape(session)
  page %>% rvest::html_node(xpath = "/html/body/div[2]/div") %>%
    rvest::html_node("pre") %>% rvest::html_text() %>%
    readr::read_lines(skip_empty_rows = T, skip=3) %>%
    stringr::str_replace_all("° ", "°") %>%
    stringr::str_trim() %>%
    readr::read_delim(" ", col_names = F, trim_ws = T) %>%
    dplyr::bind_rows(df, .) -> df
  trg <- trg + 1
}

colnames(df) <- c("年", "月", "日", "時:分", "秒", "緯度", "経度", "深さ(km)", "M", "震央地名")

readr::write_csv(df, "2016.csv")

蛇足

以下、コードの補足。コピペでいいや~って人は読み飛ばしてどうぞ。

library()を先頭に書いているのでライブラリ名::関数名にする必要はないですが、どの関数がどのパッケージ由来かわからんくなるので書いてます。 ymd()を使っているのは日付の管理が面倒くさいので。trg <- trg + 1で日付を1日分進めています。これで2017/1/1以前の日について処理が回るというwhileループになっとります。 そもそも、URLがyyyymmddであるからそうなってますが。1月の場合に"01"としたい場合(0で埋めたい)場合はsprintf("%02d", day)みたいに書くのが一番楽だと思ってますが、今風の書き方はあるのかしら? politeの使い方はLTの資料とブログ記事を見てもらうとして、対象のデータがどこのタグにいるのかはブラウザの開発者ツールつかって掘っていく感じですね。この構造が未来永劫保たれているとも限らないし、他の年では違うかもしれないので注意。 readr::read_delim()ではなくreadr::read_lines()を使ってるのは後述するように変なところに空白があり、デリミタの指定で空白文字を使うと列がずれるため。とりあえず一旦読み込んで行ごとのデータにしたいならread_lines()が便利。最初の3行を取り込むと変なことになるのでskipし、列名はあとでつけるようにしています。 緯度経度でたまに一桁の数字があると表示位置のあわせでスペースを一個入れているようです。こういう目印になる文字がある場合は一緒に検出して置き換えればよいので楽。分かりづらいですが、"°"(度)の後に空白がある場合に"°"だけにしてスペースを取り除いています。2文字以上ある場合は対応しきれないので、[ ]+とかで検出かな。 stringr::str_trim()は各行末に位置合わせで空白文字があり、これが空列として追加されるのを防ぐ。 readr::read_delim()でスペースを区切り文字として読み取る。列名は不要。trim_wsで取り込み後に空白文字が残らないようになる。これをしないと、列の位置合わせで1月などは" 1"となっているため型が文字列になってしまう。10月は10なのでintegerと判断してくれる。そして型が合わずにbind_rowsで怒られる。 dplyr::bind_rows(df, .)は時系列順にしたいならこの順で。後でソートしても良いけど。 列名は"時:分"はオリジナルの列名とは異なるので、ここで与えている。決め打ちで良いところは決め打ちにしてしまう…。 最後にcsvに書き出してオシマイ。

使った感じ、politeパッケージは色々と面倒を見てくれるので便利ですね。Rでスクレイピングするなら今後は必ず使う方が良いんじゃないかなと思いました。watagusaさんありがとうございます。

rvestを使ったスクレイピングについてはほぼノー説明にしましたが、困ってる場合はRによるスクレイピング入門がおすすめですね。

www.c-r.com

lubridateパッケージについては書籍はないですが、ネット上に解説もあるので今回程度の使い方なら困ることはないでしょう(知らんけど)。

qiita.com

kazutan.github.io

さいごに

なんか変じゃねこれみたいなのあったら教えてくだされ~~

追記

nod使ってないじゃん!って気づいたので修正しました。修正前のコードも載せておきます(恥) nod使って何度もアクセスしないようにしようねって書いてあったのに、勢いで実装するとこうなるのだ…。気を付けよう。

library(rvest)
library(xml2)
library(polite)
library(lubridate)
library(stringr)
library(dplyr)
library(magrittr)

trg <- lubridate::ymd("2016/1/1")
df <- data.frame()

while(trg < lubridate::ymd("2017/1/1")){

  session <- polite::bow(url=stringr::str_c("https://www.data.jma.go.jp/svd/eqev/data/daily_map/", sprintf("%04d%02d%02d", lubridate::year(trg), lubridate::month(trg), lubridate::day(trg)) ,".html"), delay=5)

  page <- polite::scrape(session)
  page %>% rvest::html_node(xpath = "/html/body/div[2]/div") %>%
    rvest::html_node("pre") %>% rvest::html_text() %>%
    readr::read_lines(skip_empty_rows = T, skip=3) %>%
    stringr::str_replace_all("° ", "°") %>%
    stringr::str_trim() %>%
    readr::read_delim(" ", col_names = F, trim_ws = T) %>%
    dplyr::bind_rows(df, .) -> df
  trg <- trg + 1
}

colnames(df) <- c("年", "月", "日", "時:分", "秒", "緯度", "経度", "深さ(km)", "M", "震央地名")

readr::write_csv(df, "2016.csv")

GISに手を付け始めた(メモ)

2021年内にある程度出来るようにしたいものの1つ

防災意識を高める

昨年末、ふと防災情報について気になり、自衛隊防災BOOKを買ってパラパラと読んでみた。

magazineworld.jp

magazineworld.jp

まだ読み終わっていないが、日本に住んでいる以上は自然災害で被災するリスクはかなり高いと考えられるので、覚えておくと良いのではと思っている。ただし、実践しておかないといざという時に体が動かないだろうから、どこかで講習を受けた方が良いのかもしれない。

ハザードマップポータルサイト

2020年も7月に豪雨があり、その前年も令和元年東日本台風があったので河川の氾濫リスクを可視化して確認したいと考えていた。

ja.wikipedia.org

ja.wikipedia.org

そんな中、国土交通省ハザードマップポータルサイトを運営していることを知った。これは地図の上に浸水リスクや土砂災害リスクを重ねて表示することで可視化されるため便利である。

disaportal.gsi.go.jp

ハザードマップ平成27年の水防法改正のタイミングで各自治体で作成されているようであるが、その作り方は自治体に依存しそうである(未確認)また、その後の更新がされているかも自治体に依存しそうである(未確認)国土交通省の方で水害ハザードマップ作成の手引きがでているため、基本的にはこれに従ったものが出来ていると思われるが…

www.mlit.go.jp

ただし、ハザードマップポータルサイト上で表示できるデータは当然?各自治体が公開しているデータ(オープンデータ)が存在しない場合は表示が出来ない。そのため、すごいリスクが高いと表示されている隣の自治体で何も表示されないということがある。これはその場所が本当にリスクがないのか、それともデータがないのかが判断できないので改善してほしい、というよりデータを公開してほしいところ。

なお、色々見ていくと荒川水系は文字通り"荒"川で下流の方はリスク高いなぁ…ということがわかる。ただしこれは各水系について「想定最大規模降雨による洪水浸水想定区域等」で調べた方が良いかもしれない。埼玉県の場合はここにデータがあった。

www.pref.saitama.lg.jp

可視化したい

ということで、可視化をしたい。Rで地図の可視化といえばleafletパッケージかなと思いましたが、丁度良い本として以下の本がありました。

Rによる地理空間データ解析入門

www.kyoritsu-pub.co.jp

扱っているパッケージがsfパッケージ以前のパッケージがメインなので、ちょっと古い方法かもしれませんが、R上で地理空間データを扱うための基礎が掴めると思いました。空間統計についても触れているし、sfパッケージにも触れているのでその点も良い。お値段はちょっとお高めですが…。

…が、ある程度読んだところで、R上で情報を表示するのは便利ではあるけども、Rの各パッケージの操作に慣れる必要がある点や今時点では「かっちりしたものをつくる」までは必要ないな?ということから一旦保留として、簡便に地理空間データを扱う方法がないかを調べることとなりました。

で、調べるとGUI上でGISデータを扱えるQGISに出会いました。

qgis.org

QGISの使い方についてはネット上にあるチュートリアルの情報である程度操作は学びましたが、まとまった情報を本で読んでおきたいと思い下記の本を読みました。

【改訂新版】[オープンデータ+QGIS]統計・防災・環境情報がひと目でわかる地図の作り方

gihyo.jp

事前の想定よりかなり基礎よりでしたが、その基礎部分の知識がかなり欠けていることがわかったのでかなり得るものがありました。測地系とかライセンスとか難しいよねホント。未だよくわからん。

後半はざっと読んだだけですが、この通りに動かせば行けそうだな、ということがわかったので一旦保留として、実際に目的のデータを集めてから再度読み直すこととしています。

ということで、年末から手を付け始めているものの、課題が多岐に渡っていてすぐには結果が出なさそうなので、日記として記録を残しておく。

蛇足

なお、この話に興味を持った背景としては、令和2年(2020年)の宅建業法改正による、水害リスク情報の重要事項説明の義務化の話がきっかけになります。以下のページが情報へのリンクがまとまっていて良さそうなのでリンク貼っておく。

www.jpm.jp

この改正は公布が7/17、施行が同年8/28と非常に短期間に行われていたため、周知が不足していたのではと感じるものでもあり、また、上記のハザードマップの更新がされておらず近年の災害情報が反映されていない(平成28年ごろまでの情報しかない)ことから、公開されている情報から自力でマップを作れないだろうか?ということを考えて、情報収集をはじめたものです。なので、現時点ではまだ自分の手元で満足するデータとその表示が出来ていません。

行政サイドでやっつけておいてほしいところなんだけど、ないものはないので無理なので、出来ることを手持ちで増やしておくといつか切れるカードになるのではないかなということでやっていきです。