Использование FuncAnimation от matplotlib для простого создания информативных GIF-файлов для визуализации данных — часть 1 из 2

Мотивация

В этой работе я хочу показать, как легко делать анимацию с помощью matplotlib. В прошлом я искал учебные пособия и информацию по этой теме, но всегда терпел неудачу. Когда я нашел примеры, мне было трудно их интерпретировать, и казалось, что ничего не прилипает. Итак, я решил сделать набор руководств в надежде, что другие смогут научиться быстро и эффективно создавать GIF-файлы в matplotlib. С этой целью я выбрал SARS-CoV-2 в качестве темы для моего тематического исследования, поскольку в наши дни доступно так много данных о коронавирусе.

Фон

За последние два года термин R-ноль —также известный какR₀или репродуктивное число— появляется во всех средствах массовой информации всякий раз, когда появляется новый штамм. . Бьюсь об заклад, на данный момент мы все имеем представление о том, что это значит, но определение — это среднее количество людей, которых заражает инфицированный человек в отсутствие вакцин, масок или других защитных мер. Это число трудно измерить, и было предложено много значений. Ранее, весной 2020 года, люди делали множество оценок относительно R₀ предкового штамма, который колебался от 2 до 6+; теперь мы думаем, что это около 2,5 [1]. Дельта-вариант, по-видимому, имеет R₀ около 5, и хотя мы все еще находимся на ранних этапах существования Omicron, по оценкам, он имеет R₀ около 10 [2].

Очевидно, существует большая разница в инфекционности, но как мы можем ее визуализировать? В предыдущих сообщениях я описал, как люди отлично умеют находить закономерности, когда дело доходит до визуальных данных. Нам гораздо проще интерпретировать изображения, чем строки чисел. Имея это в виду, я объясню, как визуализировать эти различия в R₀ с помощью matplotlib. Здесь я покажу вам, как использовать FuncAnimation() для создания GIF-файлов вирусного распространения. Во-первых, мы рассмотрим, как создать анимированный линейный график и как настроить базовую точечную симуляцию распространения вируса. В следующей статье мы увидим, как мы можем улучшить эту базовую настройку и создать более сложную анимацию.

Вот импорт, который вам понадобится:

from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.collections import PatchCollection
from matplotlib.patches import Rectangle
import random
import numpy as np
from scipy.spatial import Delaunay
from matplotlib.lines import Line2D

Визуализация линейного графика

Интересно взглянуть на историю визуализации данных, и на рис. 1 показана пара очень ранних линейных графиков, обозначенных выше как рис. 6 и рис. 7. Эти графики изображают капиллярное действие воды между двумя стеклами. Это немного расплывчато, поэтому вот два других примера этого эксперимента: 1 и 2. Линейные графики можно использовать для отображения ряда типов взаимосвязей, но здесь мы можем использовать их для отображения изменения количества заражений с течением времени.

При создании визуализаций роста числа инфекций с течением времени мы можем использовать следующий код для создания правдоподобных траекторий линий. Во-первых, мы можем создать функцию с именем calc_y(), которая принимает несколько шагов (n) и значение R₀ (r). Вместо использования одного и того же R₀ на каждом шаге мы можем использовать функцию np.random.normal() для возврата значения из нормального распределения со средним значением R₀. Это лучше, потому что число размножения является средним, поэтому оно будет разным для каждого инфицированного человека.

Далее мы можем создать анимацию. В следующем коде используется FuncAnimation(), что позволяет нам передать пользовательскую функцию для создания анимации. Код ниже довольно прост. Все, что делает animation_func(), это итерация от 0 до 45, аргумент фреймов от FuncAnimation() и рисование линий на основе кода, описанного выше. Поскольку разные значения R₀ приводят к резкому различию количества заражений с течением времени, я написал функцию для рисования линий в три этапа, по одной для каждого R₀, по мере увеличения значения i. Первые 15 строк будут соответствовать R₀ 1, следующие 15 — R₀ 2, а последние 15 — R₀ 10.

Обратите внимание, что я использую imagemagick для записи рисунка в GIF. Если вы работаете в Google Colab, вы можете запустить !apt-get install imagemagick, чтобы установить его в своей среде выполнения, в противном случае вам нужно будет убедиться, что он установлен в вашей системе.

Приведенный выше код был использован для создания GIF ниже. Мы видим, что для каждого R₀ из 1, 2 и 10 нарисовано пятнадцать линий. Удивительно, но неудивительно видеть, как быстро растут линии больших R₀.

Если раскомментировать строку 10, ось Y преобразуется в логарифмическую шкалу, что еще раз иллюстрирует резкое увеличение числа заражений.

Визуализация моделирования

Эти линейные графики иллюстрируют быстрое увеличение числа инфекций с течением времени вирусом с R₀ 10. Но действительно ли эта информация актуальна? Обратите внимание, что шкала Y предыдущего графика настроена на логарифмическую шкалу, а фиолетовые линии достигают значений ~10 миллионов. Интуитивно это имеет смысл. Поскольку R₀ = 10 означает, что каждый человек заражает в среднем 10 человек, мы ожидаем роста, кратного 10. Но как это будет выглядеть в большой комнате, где толпятся люди? Скажем, на таком масштабном мероприятии, как Биоген конференция.

Еще в марте 2020 года в The Washington Post была опубликована статья, в которой было показано несколько симуляций, подобных тому, что я описал выше. Они были разработаны, чтобы проиллюстрировать, как такие действия, как карантин и социальное дистанцирование, могут замедлить распространение. R₀ вообще не учитывался при моделировании WP; точка была заражена просто в результате контакта с зараженной точкой.Я рекомендую вам ознакомиться со статьей, потому что эти симуляции послужили источником вдохновения для этого руководства. В то время как визуализации хорошо иллюстрируют, как уменьшить распространение, у нас другая цель: мы хотим смоделировать различное распространение штаммов с разными значениями R₀. Теперь, когда у нас есть оценки этого значения для разных штаммов, мы можем визуализировать, какими могут быть последствия инфекционности в реальном мире.

Первая попытка

Вопрос в том, как моделировать распространение вируса при разных значениях R₀? Мой первый план состоял в том, чтобы инициализировать плоскость кучей точек, каждая из которых имеет небольшую скорость и состояние, которое либо здорово, либо заражено. Одна из этих точек будет случайным образом выбрана для заражения в момент времени 0. Для имитации распространения количество точек, которые эта зараженная точка будет заражать, будет случайным образом выбрано из нормального распределения со средним значением R₀, аналогично процессу, описанному выше. Затем статистика этих точек была изменена со здоровой на зараженную. Выбирая количество заражений для зараженной точки из нормального распределения вокруг R₀, мы гарантируем, что в среднем точки R₀ заражены каждой зараженной точкой.

Описанный выше метод оказался неправильным подходом. Основная проблема заключалась в том, что каждый раз приращение ~R₀ заражает точки, и эти точки выбираются как ближайшие точки к зараженной точке. Это не значит, что они на самом деле близки. Что еще более важно, определение R₀ априори не является элегантным. Лучшее решение — спроектировать среду моделирования для получения желаемого R₀, что я и сделал дальше. Тем не менее, анимация моделирования была эффективной, и код, используемый для создания GIF, показан ниже.

Следующие шаги

В этой статье я показал, как создать два разных типа анимации, используя matplotlib и FuncAnimation. В следующем я углублюсь в улучшение второй симуляции. Обязательно подписывайтесь на меня, чтобы не пропустить! Если вам понравилась эта работа, пожалуйста, ознакомьтесь с другими моими статьями, подпишитесь на получение уведомлений и присоединяйтесь к Медиуму.

Рекомендации

1. Ин Лю, Йоаким Роклёв, Репродуктивное число дельта-варианта SARS-CoV-2 намного выше, чем у наследственного вируса SARS-CoV-2, Journal of Travel Medicine, том 28, Выпуск 7, октябрь 2021 г., taab124, https://doi.org/10.1093/jtm/taab124

2. Тальха Хан Бурки, Вариант Омикрон и бустерные вакцины против COVID-19,
The Lancet Respiratory Medicine, Том 10, Выпуск 2, 2022 г., Страница e17,
ISSN 2213–2600 , https://doi.org/10.1016/S2213-2600(21)00559-2.
(https://www.sciencedirect.com/science/article/pii/S2213260021005592)

3. Хоксби, Фрэнсис. Отчет об эксперименте с подъемом воды между двумя стеклянными плоскостями в гиперболической фигуре. Мистер Фрэнсис Хоксби, ФРС. Philosophical Transactions (1683–1775), vol. 27, Королевское общество, 1710 г., стр. 539–40, http://www.jstor.org/stable/103171.