Skip to content

Instantly share code, notes, and snippets.

@deeplook
Last active March 19, 2020 22:06
Show Gist options
  • Select an option

  • Save deeplook/d4361f8275f8649a951687327505f8bf to your computer and use it in GitHub Desktop.

Select an option

Save deeplook/d4361f8275f8649a951687327505f8bf to your computer and use it in GitHub Desktop.
COVID-19 dynamics plot
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# COVID-19 Dynamics\n",
"\n",
"There are many visiualizations of the ongoing [COVID-19](https://en.wikipedia.org/wiki/Coronavirus_disease_2019) (or Corona) virus outbreak. As most are static, this one specifically aims to illustrate the dynamics of the COVID-19 virus infection using the official datasets available at https://github.com/CSSEGISandData/COVID-19. It builds on [Jupyter](https://jupyter.org) and [IPyLeaflet](https://github.com/jupyter-widgets/ipyleaflet) (and [Voilà](https://github.com/voila-dashboards/voila) and [MyBinder](https://mybinder.org), soon)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from functools import partial\n",
"from math import pi\n",
"\n",
"from ipyleaflet import basemap_to_tiles, basemaps, CircleMarker, \\\n",
" FullScreenControl, LayersControl, LayerGroup, Map, Marker, \\\n",
" WidgetControl\n",
"from ipywidgets import IntSlider, HBox, jslink, Layout, Output, Play\n",
"import pandas as pd"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"url = (\"https://raw.githubusercontent.com/CSSEGISandData/COVID-19/\"\n",
" \"master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Confirmed.csv\")\n",
"df_confirmed = pd.read_csv(url)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# df_confirmed.describe()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# df_confirmed.head()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"day_cols = [col for col in df_confirmed.columns if col.count(\"/\") == 2]\n",
"locations = list(zip(df_confirmed.Lat, df_confirmed.Long))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def radius_sphere(volume):\n",
" return (volume / pi / 4 * 3) ** (1/2.75)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def slider_changed(change, the_map=None, output=None, slider=None, group=None):\n",
" day = change['new']\n",
" values = df_confirmed[day_cols[day]]\n",
" if slider:\n",
" slider.description = day_cols[day]\n",
" if the_map:\n",
" circle_layers = list(l for l in group.layers if type(l) == CircleMarker)\n",
" if not circle_layers:\n",
" # if output:\n",
" # with output:\n",
" # print(f\"updating {day_cols[day]}\")\n",
" markers = []\n",
" for i, loc in enumerate(locations):\n",
" rad = int(radius_sphere(values[i]))\n",
" marker = CircleMarker(\n",
" location=tuple(loc),\n",
" radius=rad,\n",
" color=\"red\" if rad > 0 else \"white\",\n",
" opacity=rad > 0)\n",
" markers.append(marker)\n",
" group.layers = tuple(markers)\n",
" else:\n",
" for i, lay in enumerate(circle_layers):\n",
" rad = int(radius_sphere(values[i]))\n",
" lay.radius = rad\n",
" lay.color=\"red\" if rad > 0 else \"white\"\n",
" lay.opacity = rad > 0"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# output = Output()\n",
"# display(output)\n",
"\n",
"m = Map(zoom=2, basemap=basemaps.CartoDB.Positron)\n",
"\n",
"m += FullScreenControl()\n",
"\n",
"# dark_matter_layer = basemap_to_tiles(basemaps.CartoDB.DarkMatter)\n",
"# m.add_layer(dark_matter_layer)\n",
"# nat_geo_world_layer = basemap_to_tiles(basemaps.Esri.NatGeoWorldMap)\n",
"# m.add_layer(nat_geo_world_layer)\n",
"layers_control = LayersControl(position='topright')\n",
"m += layers_control\n",
"\n",
"confirmed_group = LayerGroup(layers=[], name=\"Confirmed\")\n",
"m += confirmed_group\n",
"\n",
"play = Play(\n",
" value=0,\n",
" min=0,\n",
" max=len(day_cols)-1,\n",
" step=1,\n",
" interval=500,\n",
" # description=\"Press play\",\n",
" disabled=False\n",
")\n",
"day_slider = IntSlider(\n",
" description='Day:',\n",
" layout=Layout(width=\"600px\"),\n",
" min=-1, max=len(day_cols)-1, value=-1)\n",
"jslink((play, 'value'), (day_slider, 'value'))\n",
"cb = partial(slider_changed,\n",
" the_map=m,\n",
" # output=output,\n",
" group=confirmed_group,\n",
" slider=day_slider)\n",
"day_slider.observe(cb, names='value')\n",
"widget_control1 = WidgetControl(\n",
" widget=HBox([play, day_slider]),\n",
" position='bottomleft',\n",
" layout=Layout(width=\"600px\"),\n",
")\n",
"day_slider.value = 0\n",
"day_slider.min = 0\n",
"m.add_control(widget_control1)\n",
"\n",
"m"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment