見出し画像

感染シミュレーションを作ってみる on Processing

画像2

 ゆめみでデータ分析をしているtmhr11です。今日はプログラミングによるビジュアライズが簡単にできるPrcessingを使って、サクっと感染のビジュアライズを作ってみたいと思います。
 なお、シミュレーション内容について疫学的・科学的根拠はありません。見た目雰囲気が感染を想起させるものであれば、良しとしますw。

動機

1.  コロナによって、連日感染者数の時間的増減はグラフ表示されていますが、感染のイメージは、隣人から隣人へと、空間的に広がって行くものだと思います。このイメージを見たい。

2.Processingは前から知っていたが、ちゃんと使っていなかった。言語はJAVAと思っていたが、最近Pythonでも記述できることを知った。
  もちろん、Pythonでもmatplotlibというメジャーな視覚化ライブラリーはありますが、(https://qiita.com/kira4845/items/9d340d68a0336f954506)
動きがないし、見た目真面目臭くてつまらないですね。
 一方、Processing(https://processing.org/) は、美しく動きのある表現が簡単にできる、プロトタイピングツールとして定評があります。Pythonの素晴らしい計算ライブラリとProcessingの視覚化環境がそろえば最強では、と思ったのでした。

Processingとは

 グラフィック表示ライブラリと、プログラミング実行環境がセットになっています。ベジェ曲線や細かなタイポグラフィーの出力も可能です。  https://www.d-improvement.jp/learning/processing/ 
  昔FLASHのactionscriptでタイムラインを使わずに動画を作っていた人は、雰囲気が近いことを感じると思います。
 エンジニアよりアート系の学生のほうに知られているのかもしれませんね。
 通常、javaで記述するのですが、ここはあえてPythonを選択してみようと思います。

シミュレーションルール

・シンプルにすること
 x,x方向2次元のグリッドを空間とし、各グリッドの1コマ(セル)が、周囲のセルに対して影響すること(セルオートマトン)をベースとした。セルの状態変化ルールはシンプルであるほどかっこいいと思います。

・lifegame
 セルオートマトンの代表で、life game という70年代の有名なゲーム(?)があるのですが、簡単に言えば、周囲との粗密関係で、生命個体を表すセルが生き残るか死ぬかが決まる、生態系シミュレーションの元祖のようなものです。http://math.shinshu-u.ac.jp/~hanaki/lifegame/
 セル自体は単純なルールに従っているだけにも関わらず、一見予測不能な動きや形を発生させるという点で、生命の神秘に迫っているような気にさせますが、作った本人はそこまで考えていなかったでしょう。複雑系という学術領域の文脈で出てくることも多いです。余談ですが、複雑系という名称は、英語のcomplex systemを直訳したものと思いますが、渋谷系・ビジュアル系のようにチャラい印象を受けますw。よっぽど、'複雑システム'とかにしておけば良かったんじゃないでしょうか。

 本題に戻ると、ルールは以下にしました。
・セルは、感染状態と非感染状態を持つ。
・感染状態は30ステップ(=時間)続き、31ステップ以降非感染状態になる。
・感染状態最初の2ステップは周囲に感染力を持つ
・非感染状態のセルの縦横斜め1ブロック(合計8ブロック)に、感染力を持ったセルが存在すると、80%の確率で感染し、新たな感染セルとなる。

 これは、新規感染後2ステップは周囲に感染させる力を持つ、3〜30ステップは免疫を持った状態で、31ステップ目で免疫力は無くなることを意味します。
 以上ですが、各種定数は調整可能として、一番面白く見える塩梅を探すのが肝です。

制作

 Processingには多くのサンプルコードが付属しています。その中を漁っていると、なんとlifegameがあるではないですか。このコードを流用します。これで制作時間8割減です。

1.アルゴリズムを記述していきます。
 lifegameの肝である、周囲セルの状態探索と、状態変化の部分をカスタマイズしていきます。

def iteration():  # When the clock ticks
   # Save cells to buffer
   # (so we opeate with one array keeping the other intact)
   global disp_text
   
   new_infection = 0
   
   for x in range(grid_w):
       for y in range(grid_h):
           cellsBuffer[x][y] = cells[x][y]
           
   # Visit each cell:
   for x in range(grid_w):
       for y in range(grid_h):
           # And visit all the neighbours of each cell
           neighbours = 0  # We'll count the neighbours
           
           for xx in range(x - 1, x + 2):
               for yy in range(y - 1, y + 2):
                   # Make sure you are not out of bounds
                   if 0 <= xx < grid_w and 0 <= yy < grid_w:
                       # Make sure to check against self
                       if not (xx == x and yy == y):
                           
                           
                           if (cellsBuffer[xx][yy] > (lifetime - 2)) and (cellsBuffer[xx][yy] <= (lifetime - 0)):
                               # Check alive neighbours and count them
                               neighbours = neighbours + 1
                               
           if cellsBuffer[x][y] > 0:
               cells[x][y] = cellsBuffer[x][y] - 1
           else:
               if neighbours > 0:
                   if random(100) > 80:
                       cells[x][y] = lifetime  # new infection, reflesh lifetime
                       new_infection = new_infection + 1


2. 見た目を変えていきます。
  Processingでのアニメーションは、draw()メソッドが1フレーム毎に呼び出され、描写されるというのが基本となります。
 色合い、セルの形状などを、変えていきます。今回はセル円形とし、活性状態に合わせてサイズも微妙に変化させます。
  せっかくなんで色もサイケデリックにしていきましょう。

def draw():
   global lastRecordedTime
   global disp_text
   global lifetime

   #reflash  screen
   fill(0,0,0)
   noStroke()
   rect(0, 0, width, height)
 
   # Draw grid
   for x in range(grid_w):
       for y in range(grid_h):
           
           life = cells[x][y]
           
           if cells[x][y] > 0:
               fill(color( life * 8, 0,100 ))  # 感染中
           else:
               fill(dead)  # 感染なし

           circle(x * cellSize + cellSize/2, y * cellSize + cellSize/2, life*0.5)

3. こうなります

まとめ

・いい感じに気持ち悪い。
 動きが生き物っぽい。

・新規感染の波が起こる
 シミュレーションは常に同じルールに従っているにも関わらず、新規感染の発生数には波が起きます。つまり、小康状態と感染爆発を繰り返します。個人的な意見ですが、コロナ感染の増減とは、人間の活動量に依存している以外に、自然界のゆらぎが影響していると思います。

・Python on Processsing の問題
 スピードが思ったほど早くない
  遅い、描画部分に引きづられてるのかもしれません。
 Pythonのライブラリが自由にインポートできない
  これが最も問題で、Pythonでscikit-learnなどのライブラリをインポートする方法が、あるのかどうか?単純にimport文を書くだけではダメなようです。
 また、コメントに日本語を使うと文字化けするという、細かな制約も見られました。

それでは、ご視聴頂き有難うございました。


この記事が気に入ったらサポートをしてみませんか?