ライセンスを明記するだけの記事。
このブログは別に注記がない場合、文章、画像、コードについてはクリエイティブ・コモンズ・ライセンス(CC-BY-SA)で公開されています。
明記していなかったので書きました(2021/1/14)
このブログは別に注記がない場合、文章、画像、コードについてはクリエイティブ・コモンズ・ライセンス(CC-BY-SA)で公開されています。
明記していなかったので書きました(2021/1/14)
Pandocのバージョンは2.11.4です。いつの間にこんなにバージョン上がってるの…。
久々にPandocのissueでも見るかーって見た一個目がこれだったので、これをやることにした。
Wordの脚注の線と脚注の文字の間のスペースを詰めたいという話。
まずはこの脚注の線を修正する方法。ググれば出てくるが、
すると、よくわからんが線が表示される。これを消して他の文字にするなどすれば脚注の線は他の文字に変えることが出来る。これ以外の修正方法があるのかは知らない。
なお、この情報は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に書いたコメントを見直してよくわからなかったとき用にメモを残しておく。真面目にキャプチャとか載せておけばもっといい記事になるのに面倒くさいのでやらない。誰か書いてくれ。
ちょっとkuniezu
パッケージを試してみたかったんですが、
内部で使ってるparzer
パッケージがエラー吐いて止まる(Win、32bit版)か止まってしまって処理が返ってこない(Win, 64bit版)という挙動をしていました。
再現できるコードはこれ。
parzer::parse_lon("10")
RToolsは4.0の最新版を入れなおしてもダメでした。一方、Ubuntu上では問題なく動作して、結果として一個前の記事が出来ました(ヨカッタネ)
ってことをTwitterに呟いていたら、僕らのユタ兄さんから、
Sys.setlocale(locale = "C") にすると動きますね。この現象、arrowパッケージでも見たのでなんかあるんだろうと思ってるんですが原因を突き止められていません。。
— Hiroaki Yutani (@yutannihilation) 2021年1月23日
というアドバイスをいただいて、上記コード実行前に
Sys.setlocale(locale = "C")
をしたら動くようにはなりました。が、原因がわからないのでちょっと調べてみます。昔のバージョンなら問題なかったのではないだろうか、とかそのあたりですね…(CRANのテストはもちろん通った状態でリリースされているのでそこら辺ではなさそう)
その後、std::regex
が問題とわかり…
どうもstd::regexがだめっぽいですhttps://t.co/bZY62rHXDc
— Hiroaki Yutani (@yutannihilation) 2021年1月23日
minimal reprexhttps://t.co/Ylmi0fMrtR
結局、gccに問題があるのではということまで来ました(主にユタ兄さんの解析によって)
GCC側で直さないとだめ、という話になってるっぽいです。 https://t.co/SWetVPGB7B
— Hiroaki Yutani (@yutannihilation) 2021年1月24日
現状では先にあげたように、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"
Ubuntu18の方で普通にRをインストールするとR3.xが入ってしまうので、Ubuntu20.04LTSに移行しようとした。
で、Rを入れた後にRStudioをこのページに書かれているコマンドで入れようとしたのだが、
以下のようなエラーが出て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
調べたら下記のサイトに書かれていた。
投稿から引用すると、/etc/apt/sources.list
に deb http://security.ubuntu.com/ubuntu xenial-security main
という行を追記し、その後 sudo apt update
して sudo apt install libssl1.0.0
してから sudo rstudio-server start
して起動できることを確認しました。
とりあえず良かった~
各日のページからデータを読み込むことが出来たので不要になったが、これが出来ないと思っていたので過去の震源データを下記から入手して確認しようとしていた。
欲しい年を選択すると、例えば2016年ならh2016.zipみたいなファイルがダウンロードできる。これを展開すれば2016なるファイルがある。拡張子はないが、これは文字長固定で区切られたファイルで、csvなどのカンマや空白で区切られたファイルではない。
このファイルフォーマットの説明はこちら。
これを読み混むことにする。これは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
さて、以前の日記で気象庁の各日の震源データが消えていると思ったら見つかりました~ってのを書きました。
今回はそのページからデータを取ってくる作業をします。手作業でも良いかなと思ったらこれは日毎にページが分かれているわけですね~。流石にこれを手でやるのはちょっとシンドイので、久々にスクレイピングでやっつけます。
丁度良いことに、昨年末のJapan.R 2020にてwatagusaさんのLT、「"polite"で守るWebスクレイピングのエチケット」でpolite
パッケージの存在を知ったので、これを参考にしてやってみました。
Japan.Rのページはこちら
また、LTの内容ついてはwatagusaさんのブログにまとまってます。
とりあえず先にコードを書いてしまうと、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によるスクレイピング入門がおすすめですね。
lubridateパッケージについては書籍はないですが、ネット上に解説もあるので今回程度の使い方なら困ることはないでしょう(知らんけど)。
なんか変じゃねこれみたいなのあったら教えてくだされ~~
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")
昨年末、ふと防災情報について気になり、自衛隊防災BOOKを買ってパラパラと読んでみた。
まだ読み終わっていないが、日本に住んでいる以上は自然災害で被災するリスクはかなり高いと考えられるので、覚えておくと良いのではと思っている。ただし、実践しておかないといざという時に体が動かないだろうから、どこかで講習を受けた方が良いのかもしれない。
2020年も7月に豪雨があり、その前年も令和元年東日本台風があったので河川の氾濫リスクを可視化して確認したいと考えていた。
そんな中、国土交通省がハザードマップポータルサイトを運営していることを知った。これは地図の上に浸水リスクや土砂災害リスクを重ねて表示することで可視化されるため便利である。
ハザードマップは平成27年の水防法改正のタイミングで各自治体で作成されているようであるが、その作り方は自治体に依存しそうである(未確認)また、その後の更新がされているかも自治体に依存しそうである(未確認)国土交通省の方で水害ハザードマップ作成の手引きがでているため、基本的にはこれに従ったものが出来ていると思われるが…
ただし、ハザードマップポータルサイト上で表示できるデータは当然?各自治体が公開しているデータ(オープンデータ)が存在しない場合は表示が出来ない。そのため、すごいリスクが高いと表示されている隣の自治体で何も表示されないということがある。これはその場所が本当にリスクがないのか、それともデータがないのかが判断できないので改善してほしい、というよりデータを公開してほしいところ。
なお、色々見ていくと荒川水系は文字通り"荒"川で下流の方はリスク高いなぁ…ということがわかる。ただしこれは各水系について「想定最大規模降雨による洪水浸水想定区域等」で調べた方が良いかもしれない。埼玉県の場合はここにデータがあった。
ということで、可視化をしたい。Rで地図の可視化といえばleaflet
パッケージかなと思いましたが、丁度良い本として以下の本がありました。
Rによる地理空間データ解析入門
扱っているパッケージがsf
パッケージ以前のパッケージがメインなので、ちょっと古い方法かもしれませんが、R上で地理空間データを扱うための基礎が掴めると思いました。空間統計についても触れているし、sf
パッケージにも触れているのでその点も良い。お値段はちょっとお高めですが…。
…が、ある程度読んだところで、R上で情報を表示するのは便利ではあるけども、Rの各パッケージの操作に慣れる必要がある点や今時点では「かっちりしたものをつくる」までは必要ないな?ということから一旦保留として、簡便に地理空間データを扱う方法がないかを調べることとなりました。
で、調べるとGUI上でGISデータを扱えるQGISに出会いました。
QGISの使い方についてはネット上にあるチュートリアルの情報である程度操作は学びましたが、まとまった情報を本で読んでおきたいと思い下記の本を読みました。
【改訂新版】[オープンデータ+QGIS]統計・防災・環境情報がひと目でわかる地図の作り方
事前の想定よりかなり基礎よりでしたが、その基礎部分の知識がかなり欠けていることがわかったのでかなり得るものがありました。測地系とかライセンスとか難しいよねホント。未だよくわからん。
後半はざっと読んだだけですが、この通りに動かせば行けそうだな、ということがわかったので一旦保留として、実際に目的のデータを集めてから再度読み直すこととしています。
ということで、年末から手を付け始めているものの、課題が多岐に渡っていてすぐには結果が出なさそうなので、日記として記録を残しておく。
なお、この話に興味を持った背景としては、令和2年(2020年)の宅建業法改正による、水害リスク情報の重要事項説明の義務化の話がきっかけになります。以下のページが情報へのリンクがまとまっていて良さそうなのでリンク貼っておく。
この改正は公布が7/17、施行が同年8/28と非常に短期間に行われていたため、周知が不足していたのではと感じるものでもあり、また、上記のハザードマップの更新がされておらず近年の災害情報が反映されていない(平成28年ごろまでの情報しかない)ことから、公開されている情報から自力でマップを作れないだろうか?ということを考えて、情報収集をはじめたものです。なので、現時点ではまだ自分の手元で満足するデータとその表示が出来ていません。
行政サイドでやっつけておいてほしいところなんだけど、ないものはないので無理なので、出来ることを手持ちで増やしておくといつか切れるカードになるのではないかなということでやっていきです。