愛知・岐阜県内 329 人の感染経路を可視化してみた

記事のタイトルは、9 年前の自分の記事からの「インスパイア」です。あの頃は、放射線量の時間変化や、空間分布を作っていました。福島県に親戚が住んでいたからです。いつでも逃げられるように、定量的な判断基準を持つための資料が必要でした。
oxon.hatenablog.com

雑感

今回の新型コロナウイルスでは、誰から感染するかも分からないし、逆に感染させてしまうかもしれないし、日本中、世界中のどこに行っても「逃げる」というのは困難です。自分一人が感染を防いでも社会全体の流れを止めることはできず、全員が同じように感染防止を目指さないと、逃げたくても逃げられないという、大変困難な状況です。我が家は自主的に保育園の利用を停止したり、小学校の始業式をサボったりしていますが、うちだけやったところで社会の流れを止められるわけもなく、焼け石に水と思いながら行動しています。

さて、毎日コロナのニュース、特に名古屋大学のある愛知県のニュースを観ていても、「本日は新規感染者が XX 人」とか「YY で起きた集団感染の濃厚接触者」とか 、そんな断片的な情報ばかり入ってきて、全然可視化できない。何が起きているか、頭の中で考えられない。どの集団感染がまだ続いているのか収束したのか把握し続けられない。合計感染者数の時間変化のヒストグラムを眺めても、はたして愛知はどういう状況かというのがちっとも分からない。そういう不満がありました。そこで、9 年ぶりに手を動かしてみることにしました。

図から分かること

愛知県は初期に感染者の急増があったのですが、その後増加が緩やかになりました。これを合計感染者数や、日毎の新規感染者数のヒストグラムで眺めていると何が起きているか見えませんでした。

(専門家や追いかけている人たちは知っていることでしょうが)今回の図で、2/14 と 2/29 に始まった初期の集団感染 2 件(スポーツジムとデイサービス)が関係者の努力で収まり、3 月上旬から感染経路不明の「孤発」事例が出続けているということが、よく見えてきました。感染防止や対策が徹底されていなかった頃の集団感染は仕方がないとして、やはり孤発事例が頻発し始めた時点で強い対策を取らないと、一気に広がるのだということが分かります。

3 月末からは岐阜県でも孤発事例が増え始め、愛知県警や岐阜シャルムの集団感染を除けば、感染経路不明のものが毎日 5〜10 件出るようになってしまいました。これは東京の 2 週間前と変わらない状況なので、自粛ムードの強くはなかった東海エリアでは、この先 2 週間で増え続けると覚悟する必要があります。

愛知の人口でも初期クラスターから感染経路不明の増大へ、という流れがはっきり見えるのですから、東京・大阪の大都市圏では、やはり「クラスター対策をすれば大丈夫」なんていうのは専門家の認識が甘かったということかと思います。もちろんクラスター潰しと追跡調査をするのは絶対に必要ですので、関係者の努力は大変ありがたいことです。しかし、あまりに感染力が強すぎた。追えない事例が多数出てしまう。それが今回の COVID-19 の大変なところであり、専門家ですら対策できると過信してしまった原因なのではないでしょうか。

このような感染の拡大は、おそらく愛知や岐阜に限ったことではないでしょう。まだ感染者の少ない小中規模の都市でも、気持ちを緩めていると孤発事例が徐々に増えていき、「あれ、もしかして危ない?」と思い始めた頃には後手後手の対応に回ってしまうということが起き続けるでしょう。

可視化したいもの、やりたいこと

  1. 感染者数の時間変化(それだけなら他にいくらでも転がっている)が終えること
  2. 集団感染なのか孤発事例なのかの切り分けができること
  3. 感染経路不明の事例の時間変化が一瞥して分かること
  4. 帰国者や外国籍が分かること
  5. 個々の集団感染がどのように広がり、収束したのかどうか、今も拡大し続けているのか分かること

以上の条件を満たすにはどうすれば良いかを検討し、普段は CERN の ROOT というデータ解析ライブラリを使うのですが、今回は Graphviz を使うことにしました。
www.graphviz.org

実際にどうやるか

Graphviz は複数のノード(node)をエッジ(edge)で接続し、うまいことグラフを描画してくれるソフトウェアです。ここで言う「グラフ」は、ネットワーク図などグラフであり、数学用語のグラフです。

何百人もいる感染者をノードとして配置し、感染者同士の接触をエッジとして表現するのは、手動でやるのは困難です。少なくとも何週間かは毎日この作業を継続する必要があると判断し、Graphviz で自動化することにしました。簡単に自動化できるだろうと踏んでいたのですが、実際は手動での微調整でかなり作り込んでやる必要がありました。

Graphviz をそのまま使うのではなく、CSV ファイルを Python で読み、Python 内で graphviz モジュールを利用することにしました。

graphviz.readthedocs.io

多数の感染者情報を自治体発表の HTML や PDF から収集するのは非常に大変なのですが、東海 3 県に限っては中京テレビが機械可読性の非常に高いデータ整理をしてくれていました。原発のときは文科省福島県の測定データを自分自身や有志の多くの方のご協力で Google Spreadsheet に手入力し、可視化も自分でするという作業をしていたので大変だったのですが、中京テレビのお陰で今回はその点、とても楽です。
www.ctv.co.jp

Graphviz で苦労したところ

日付を縦方向に揃える

Graphviz の基本的な考え方は「自動で全てのノードをいい具合に配置する」です。そのため、細かいノード位置の調整を人間がして、エッジだけ自動的に描かせるという思想にはなっていません。しかし今回は、ある日付に陽性確定した感染者を時系列で並べたいため、同じ陽性確定日の感染者は縦に整列させる必要があります。

そこで、今回は subgraph と rank という機能を使って、同じ陽性確定日の感染者は無理やり横位置を揃えることにしました。この場合、Graphviz は横位置を揃える作業は死守してくれるようです。例外なく、ちゃんとノードを揃えてくれました。

好きな場所に文字列を置けない

凡例や注意書きなど、グラフ中に多数のテキストを配置する必要がありました。しかし、調べた限りではそのような機能がありません。また Graphviz の描画エンジンとして dot を使用する場合、座標の指定なんかもできないようです(いくつかの描画エンジンを選べるが、前述の rank は dot で使える)。

そのため、図中の様々なテキストは、多数のノードを追加するという無理やりな手法をとっています。加えて、ノードの中に書き込むテキストは、テキスト中心位置とノード中心位置が同じになります。そうすると文字列を左揃えにすることができなくなるため、全角スペースを多数挿入するという荒技を使っています。

s.node('author', label=' ' * 25 + 'データ出典:https://www.ctv.co.jp/covid-19/person.html\n' + ' ' * 28 + '作成:@AkiraOkumura(名古屋大学 宇宙地球環境研究所 奥村曉)', shape='plaintext', fontsize='40', height='2.5')
ノードの縦位置が自動配置されてしまう

「自動配置されてしまう」と Graphviz に文句を言うのは、それが設計思想なので筋違いなのすが、今回の図では愛知県と岐阜県で区分けしたかったため、この自動配置には大変困りました。左→右で進むグラフの場合、追加したノードは下から上に並ぶようです。ただし追加した順通りになるわけではなく、グラフ形状にしたがって自動配置が Graphviz が最適と思うやり方で行われます。

そうすると、愛知県の感染者ノードの中に岐阜が混じってしまったり、その逆も起きます。そこで、手動にて非表示のエッジを多数追加することで、自分の意図した場所に無理やり置くことができるようになります。見えないエッジを追加することで、それらが接続するノードを近接した場所に置こうと Graphviz が機能するためです。しかしこれでも、自分の意図したものに近づくだけであって、Graphviz の挙動を完全に制御することはできません。

graph.edge('aichi134', 'dummy2020-03-19', style='invis')
graph.edge('aichi145', 'dummy2020-03-23', style='invis')
graph.edge('aichi151', 'aichi152', style='invis')
graph.edge('aichi155', 'aichi152', style='invis')
graph.edge('aichi155', 'aichi151', style='invis')
エッジ以外の線が描けない

これも Graphviz の設計思想として、そんなものは必要ないのは明らかですが、エッジ以外の線を自由に描くことができません。今回の場合、愛知と岐阜の県境を滑らかな線で描きたかったのですが、これも非表示のノードを多数配置しそれを点線のエッジで接続することで、無理やり実現しました。県境が滑らかでなくガタガタしているのはこれが原因です。

matplotlib などと連携できない

本当はヒストグラムなどを matplotlib かなんかで描いて、Graphviz の結果も一緒に並べるなんてことをやりたかったのですが、Pythongraphviz モジュールはそれ単体の世界で閉じているので、できませんでした。

エッジが多すぎると作図が発散する

集団感染が発生した場合、多くの感染者ノード同士を何本ものエッジで接続すると、描画結果が大変な場合になることがありました。具体的には岐阜県の飲食店シャルムの集団感染なのですが、ここをエッジで接続するのは諦めました。
f:id:oxon:20200409100712p:plain

ペスト (新潮文庫)

ペスト (新潮文庫)

  • 作者:カミュ
  • 発売日: 1969/10/30
  • メディア: ペーパーバック
銃・病原菌・鉄 上巻

銃・病原菌・鉄 上巻

Gist にきったない Python コードを置いておきます

人に見せるような綺麗なコードではないのですが、Graphviz を使う例として、誰かの役に立つかもしれません。
gist.github.com

Twitter のサムネイル用

f:id:oxon:20200409104542p:plain