Reputation: 534
I would like to build an interactive chart with world map with COVID-19 confirmed cases per country and date slider using Altair library in python.
Data format:
"country_region","date","confirmed_cases"
"Afghanistan",2020-01-22,0
"Afghanistan",2020-01-23,0
"Afghanistan",2020-01-24,0
"Afghanistan",2020-01-25,0
I have managed to build non-interactive chart, but can't set up slider. My chart now looks like this:
I want to add slider to chose date, but can't set up it properly.
I use transform_lookup
method to add colors to countries according to the data (confirmed cases / population) and transform_filter
as far as I understand should be added to perform data filtering when slider position is changed by user. But this doesn't work. My assumption is that in transform_lookup
always original data is used and filtering doesn't work there. I haven't found examples or documentation about using transform_lookup
and slider at the same time.
Would be grateful to hear any ideas what can help me with this problem.
Code:
import requests
import json
import pandas as pd
import altair as alt
from vega_datasets import data
from altair import datum
df = pd.read_csv('https://raw.githubusercontent.com/MariaKokshaikina/any-data/main/covid19_global_confirmed_cases%20(1).csv')
country_info = requests.get(
'https://raw.githubusercontent.com/MariaKokshaikina/any-data/main/country_info.json'
).json()
df = df[df['country_region'].isin(country_info)]
df = df.sort_values('date', ascending=True)
df = df.tail(5000)
def timestamp(t):
return pd.to_datetime(t).timestamp() * 1000
df['id'] = df['country_region'].map(lambda x: country_info[x]['numericCode'])
df['rate'] = df['confirmed_cases'] / df['country_region'].map(lambda x: country_info[x]['population'])
df['timestamp'] = df['date'].map(timestamp)
countries = alt.topo_feature(data.world_110m.url, 'countries')
slider = alt.binding_range(
step=24 * 60 * 60 * 1000,
min=df['timestamp'].min(),
max=df['timestamp'].max()
)
select_date = alt.selection_single(
name="slider",
fields=['timestamp'],
bind=slider,
)
alt.Chart(countries).mark_geoshape()\
.encode(color='rate:Q')\
.add_selection(select_date)\
.transform_filter(select_date)\
.transform_lookup(
lookup='id',
from_=alt.LookupData(df, key='id', fields=['rate'])
)\
.project('equirectangular')\
.properties(
width=500,
height=300,
title='Title'
)
.transform_filter(select_date)\
line to see working map with slider which doesn't change anything.Upvotes: 4
Views: 3238
Reputation: 11
I realize this is an older question, but for anyone still struggling to resolve the issue applying Jake's suggestion in their own code (as I did), I've found an alternative solution!
I ended up ditching the "transform_lookup" altogether and handled it directly in GeoPandas instead:
import geopandas as gpd
url = data.world_110m.url #in my case, this was a github url
gdf = gpd.read_file(url)
merged_data = pd.merge(gdf, df, on='id', how='left')
And then the code to the map would be something closer to a "normal" graph, just loading one data:
alt.Chart(merged_data).mark_geoshape()\
.encode(color='rate:Q')\
.add_selection(select_date)\
.transform_filter(select_date)\
.project('equirectangular')\
.properties(
width=500,
height=300,
title='Title'
)
I hope this helps someone that is having difficulties making the transform_lookup work :)
Upvotes: 1
Reputation: 86300
The problem appears to be that in Vega, lookup transforms do not dynamically recompute in response to selections. You can address this by switching which is the primary data source, so that all timestamps appear in the final joined dataset:
alt.Chart(df).mark_geoshape()\
.encode(color='rate:Q')\
.add_selection(select_date)\
.transform_filter(select_date)\
.transform_lookup(
lookup='id',
from_=alt.LookupData(countries, key='id',
fields=["type", "properties", "geometry"])
)\
.project('equirectangular')\
.properties(
width=500,
height=300,
title='Title'
)
Upvotes: 4