Поскольку вспышка COVID-19 набирает обороты, может помочь хороший взгляд на вспышку. И когда я увидел видео 3b1b о моделировании эпидемий, я попытался воссоздать то, что он делал. Итак, приступим.

Обязательно посмотрите 3b1b video, о котором я упоминал ранее, чтобы вы знали, что кодировалось, а для интерактивного моделирования перейдите сюда или здесь.

Поскольку нам нужно куда-то поместить нашу графику, мы создаем холст в HTML и инициализируем его в JS.

<canvas id="c">
    Your browser does not support the canvas.
</canvas>

И наш JS:

var cv = document.getElementById("canvas")   
var c = cv.getContext("2d")
cv.width = window.innerWidth   
cv.height = window.innerHeight

Во-первых, нам нужны такие переменные, как популяция и уровень заражения (небольшое примечание, мы будем кодировать это на JS, поэтому убедитесь, что вы понимаете основы JS, прежде чем переходить к этому руководству).

var population = 100   
var infected = 1 
var speed = 10   
var currentInfections = 1

Хорошо, это говорит само за себя, но давайте просто рассмотрим это. Переменная population - это количество точек / людей в моделировании. Переменная infected - это начальное количество инфекций, и оно у нас есть, потому что в одной вспышке может быть 10 или 20 «нулей пациентов». speed - это скорость перемещения точек, а currentInfections - количество заражений. Причина, по которой у нас есть infected и currentInfections, заключается в том, что currentInfections - это количество, которое у нас есть в любой момент времени во время эпидемии, а infected - это количество, с которым мы должны начать.

Затем нам нужен массив, в котором мы будем хранить каждое отдельное значение, например, является ли он зараженным, восприимчивым или восстановленным; точки x и y; и это скорость, которую я объясню чуть позже.

Прежде чем перейти к скорости, я хочу объяснить, что такое наша модель. Наша модель называется моделью SIR, что означает «восприимчивый», «инфицированный» и «выздоровевший». Восприимчивая популяция может заразиться, инфицированная популяция может заразить других, а выздоровевшая популяция больше не может заразить других и, согласно этой модели, больше не может быть повторно инфицирована.

Теперь перейдем к скорости. Это направление точек, например влево, вправо, вверх или вниз. У нас будет две части: скорость x и скорость y. Таким образом, точки располагаются не только вверх, вниз, влево и вправо, но и по диагоналям.

Поскольку написание всего этого займет много времени, мы будем использовать цикл for. Сначала мы определяем наш массив:

var dots = []

А теперь добавим к нему:

for(var i = 0; i<population-infected;i++){
     
    dots.push([Math.random()*Math.min(cv.width,cv.height)*3/4,
    Math.random()*Math.min(cv.width, cv.height) *
    3/4,0,speed*Math.random(),speed*Math.random()]
}

Теперь он разделен на несколько строк, потому что среда не позволяет мне выходить за поля, но я попытался сделать его как можно более читаемым.

Давай пройдемся по этому поводу. Поскольку каждая точка состоит из нескольких частей, мы создаем внутри нее подмассивы. Первые 2 параметра - это x и y. Мы размещаем их в произвольном месте на нашем холсте, но чтобы разместить их в центре экрана, мы умножаем их на 3/4.

Затем у нас есть его состояние: восприимчивый, инфицированный или выздоровевший. Мы можем добавить больше состояний, таких как мертвый или иммунный, вместо выздоровевшего, но пока давайте оставим это простым. Мы указываем 0 как восприимчивый, 1 как инфицированный и 2 как выздоровевший.

Далее у нас есть значения скорости. Мы умножаем скорость на случайное число, чтобы получить нашу скорость.

Теперь вы могли заметить, что цикл for охватывает только 99 человек, а не 100. Это связано с тем, что нам нужен новый цикл for для зараженной популяции.

for(var i = 0; i<infected;i++){
     
    dots.push([Math.random()*Math.min(cv.width,cv.height)*3/4,
    Math.random()*Math.min(cv.width, cv.height) *
    3/4,1,speed*Math.random(),speed*Math.random()]
}

Теперь мы создаем функцию с именем refresh() для анимации.

var refresh = function () {
}

Прежде чем мы перейдем к анимации и рисованию, обязательно нарисуйте границу «города», которая представляет собой белый прямоугольник.

ctx.fillStyle = "rgb(255,255,255)"
ctx.strokeRect(cv.width*1/4,cv.height*1/4,cv.width*3/4,cv.width*3/4)

Внутри функции нам нужно сделать нашу анимацию и рисование. Сначала мы рисуем круги для всей восприимчивой популяции, которая будет синей, затем инфицированная, которая будет красной, и удаленная / восстановленная популяция, которая будет серой. Я позволю тебе разобраться в этом.

Теперь давайте оживим их. Мы запускаем цикл for, который просматривает массив dots и анимирует их.

for(var i = 0; i < population;i++){
  dots[i][3]+=Math.random()*2-1
  dots[i][4]+=Math.random()*2-1      
  if ( dots[i][3] >= speed ){dots[i][3] = 0}     
  if ( dots[i][3] <= -speed){dots[i][3] = 0}     
  if ( dots[i][4] >= speed ){dots[i][4] = 0}       
  if ( dots[i][4] <= -speed ){dots[i][4] = 0}      
  dots[i][0]+=dots[i][3]     
  dots[i][1]+=dots[i][4]      
  if(dots[i][0]>1*Math.min(cv.width,cv.height)*3/4){      
    dots[i][0]=1*Math.min(cv.width,cv.height)*3/4      
  }     
  if(dots[i][0]<0){
    dots[i][0]=0
  }
  if(dots[i][1]>1*Math.min(cv.width,cv.height)*3/4){
    dots[i][1]=1*Math.min(cv.width,cv.height)*3/4      
  }     
  if(dots[i][1]<0){
    dots[i][1]=0      
  }    
}

Теперь, когда мы это сделали, нам нужно начать заражать других. Для этого мы запускаем вложенный цикл for, который найдет зараженные точки. Как только мы их найдем, мы запустим вложенный цикл for, чтобы найти другие точки в пределах радиуса заражения, который мы обозначили как 5. Я позволю вам разобраться и с этим, поскольку это не должно быть слишком сложно (ПОДСКАЗКА: там двойной вложенный цикл for).

Вот заразились, нарисовали, анимировали, нужно еще кое-что. Поскольку люди либо умирают, либо выздоравливают, мы должны добавить это. Мы добавляем еще один элемент в подмассивы внутри dots. В начале цикла for (первого) мы помещаем это:

dots[i][5]++

Если вы поместили другую переменную в цикл for, замените i этой переменной. В конце поставьте это:

if(dots[i][5] >= 200){dots[i][2] = 2}

Это добавляет «таймер» к зараженным, и когда он достигает 200, он меняется на одну из удаленных точек.

Мы все сделали! Чтобы нарисовать и полностью оживить, поместите это в конец refresh():

window.requestAnimationFrame(refresh)

А затем запустите функцию:

refresh()

ПРИМЕЧАНИЕ. Эта модель определенно не отражает вспышку COVID-19 или любую другую вспышку, но это может быть очень, очень, очень, очень, очень простой способ представить вспышку.

Что добавить

Вот несколько вещей, которые вы можете добавить:

  • Мертвые и восстановленные точки, а не только удаленная популяция в целом
  • Социальное дистанцирование (этого можно добиться, не перемещая некоторые точки, идея взята из сообщения Гарри Стивенса)
  • Изоляция части больных точек (только части, потому что не у всех, кто болен, проявляются симптомы и проходят анализы)
  • Добавление нескольких сообществ, в которых люди путешествуют от одного к другому (идея из упомянутого мной видео 3b1b)
  • Графики, диаграммы, данные и т. Д.
  • Больше настроек в таких параметрах, как скорость заражения, скорость, скорость восстановления и т. Д.
  • Центральная точка, похожая на магазин (также из видео 3b1b)

Для более сложного моделирования я предлагаю вам ознакомиться со статьей q9i о моделировании болезней - Безопасное открытие: подход на основе анализа данных

Примеры

Вот несколько хороших примеров