I am plotting a choropleth map colored by the field Passenger_0_
and a line chart showing the evolution of Passenger_0_
throughout a day by zone
.
I would like to select a line ( zone
) in the line chart and have it highlighted in the map and vice versa (select a zone in the map and have it highlighted in the line chart).
For now, I am able to change the whole color of the map when selecting the line, but have no clue of how to only change the color of the selected area.
I would appreciate any help.
In order to reproduce the sample you need to download these two files:
Then run this piece of code to get a GeoDataFrame named long_df
:
import altair as alt
import pandas as pd
import geopandas as gpd
import json
geo_json_file_loc= './taxi_zones.geojson'
with open(geo_json_file_loc) as json_data:
data = json.load(json_data)
gdf = gpd.GeoDataFrame.from_features((data))
gdf = gdf[gdf['borough']=='Manhattan']
gdf = gdf[['location_id','zone','geometry']]
gdf = gdf.rename(columns={'location_id':'LocationID'})
gdf['LocationID'] = pd.to_numeric(gdf['LocationID'])
output_data = pd.read_csv('./output_data.csv',sep=',')
def load_taxis_data(output_data, shape_data):
df_to_visualize = shape_data.copy()
pickups = output_data.groupby(['hour','dayofweek','LocationID']).sum()
listofdays = pd.unique(output_data['dayofweek'])
for hour in range(24):
for dayofweek in listofdays:
# get pickups for this hour and weekday
p = pd.DataFrame(pickups.loc[(hour, dayofweek)]).reset_index()
# add pickups to the Taxi Zones DataFrame
df_to_visualize = pd.merge(df_to_visualize, p, on="LocationID", how="left").fillna(0)
# rename column as per day and hour
df_to_visualize.rename(columns={"pickups" : "Passenger_%d_%d"%(dayofweek, hour)}, inplace=True)
return df_to_visualize
gdf_merged = load_taxis_data(output_data, gdf)
# drop unwanted days
for hour in range(24):
for dayofweek in [5,6]:
column_to_drop = "Passenger_%d_%d"%(dayofweek, hour)
gdf_merged.drop([column_to_drop], axis=1, inplace=True)
gdf_merged.reset_index(level=0, inplace=True)
long_df = pd.wide_to_long(gdf_merged, ["Passenger_0_"], i='index', j="hour")
long_df = long_df.reset_index()
Once you got long_df
this is the code for the plots:
dict_json = json.loads(long_df[long_df['hour']==0].to_json())
colours_obj = alt.Color('properties.Passenger_0_:Q',
scale=alt.Scale(scheme='yelloworangered'),
title = "Pickups")
sel_line_hover = alt.selection_single(on='mouseover', empty='none')
sel_line_col = alt.selection_single()
sel_line_size = alt.selection_single(empty='none')
base = alt.Chart(alt.Data(values=dict_json['features'])).mark_geoshape(
stroke='black',
strokeWidth=1
).encode(
color=alt.condition(sel_line_col, colours_obj, alt.value('lightgray')),
tooltip = ['properties.zone:O',
'properties.Passenger_0_:Q']
).properties(
width=350,
height=750,
).add_selection(
sel_line_col
)
line = alt.Chart(long_df).mark_line().encode(
x='hour',
y='Passenger_0_',
color=alt.condition(sel_line_hover|sel_line_col, 'zone', alt.value('lightgray')),
size=alt.condition(sel_line_hover|sel_line_size, alt.value(4),alt.value(1)),
tooltip = ['zone:O']
).properties(
width=250,
height=750,
).add_selection(
sel_line_hover,sel_line_col,sel_line_size
)
base | line
And this is what the plot does:
Thank you in advance for your help!
Here is a general example of how to achieve two-way interactivity in Altair, using data from the sample repos only. The key is to set the feature that should be filtered by the selection even via fields
parameter when creating the selection. Then you add this selection and the corresponding condition to the same encoding of both the plots.
import altair as alt
from vega_datasets import data
state_pop = data.population_engineers_hurricanes()[['state', 'id', 'population']]
state_map = alt.topo_feature(data.us_10m.url, 'states')
click = alt.selection_multi(fields=['state'])
choropleth = (alt.Chart(state_map).mark_geoshape().transform_lookup(
lookup='id',
from_=alt.LookupData(state_pop, 'id', ['population', 'state']))
.encode(
color='population:Q',
opacity=alt.condition(click, alt.value(1), alt.value(0.2)),
tooltip=['state:N', 'population:Q'])
.add_selection(click)
.project(type='albersUsa'))
bars = (
alt.Chart(
state_pop.nlargest(15, 'population'),
title='Top 15 states by population').mark_bar().encode(
x='population',
opacity=alt.condition(click, alt.value(1), alt.value(0.2)),
color='population',
y=alt.Y('state', sort='x'))
.add_selection(click))
choropleth & bars
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.