Altair 等值线图,基于折线图选择的颜色高亮

Posted

技术标签:

【中文标题】Altair 等值线图,基于折线图选择的颜色高亮【英文标题】:Altair choropleth map, color highlight based on line chart selection 【发布时间】:2020-12-24 07:32:51 【问题描述】:

我正在绘制由字段Passenger_0_ 着色的等值线图和显示Passenger_0_ 在一天内由zone 演变的折线图。

我想在折线图中选择一条线 (zone) 并在地图中突出显示,反之亦然(在地图中选择一个区域并在折线图中突出显示)。

目前,我可以在选择线时更改地图的整体颜色,但不知道如何仅更改所选区域的颜色。

我将不胜感激。

为了重现示例,您需要下载这两个文件:

output_data.csv

taxi_zones.geojson

然后运行这段代码得到一个名为long_df的GeoDataFrame:

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()

一旦你得到long_df,这就是绘图的代码:

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

这就是情节的作用:

提前感谢您的帮助!

【问题讨论】:

如果您可以提供Minimal reproducible example 来展示您遇到的问题,您将更有可能获得对您的问题有用的答案。当我运行你的代码 sn-p 我得到NameError: name 'long_df' is not defined 道歉@jakevdp 你是对的。我想简化消息,没想到实际上不可能用提供的信息重现示例。我已经编辑了这个问题,添加了指向计算long_df```, and the piece of code necessary to calculate long_df```所需的.geojson.csv 文件的链接。我非常感谢您的时间和帮助。 【参考方案1】:

这是一个关于如何在 Altair 中实现双向交互的一般示例,仅使用来自示例存储库的数据。关键是在创建选择时甚至通过fields 参数设置应该被选择过滤的特征。然后将此选择和相应的条件添加到两个图的相同编码中。

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

【讨论】:

非常感谢您的回答@joelostblom。我现在正忙于另一个项目,但我会尽快测试它。 这是一个很好的例子!

以上是关于Altair 等值线图,基于折线图选择的颜色高亮的主要内容,如果未能解决你的问题,请参考以下文章

ECharts 折线图 设置平滑和颜色

iOS 动画绘制线条颜色渐变的折线图

Python使用matplotlib函数subplot可视化多个不同颜色的折线图自定义数据点的形状自定义折线图的颜色

echarts更改折线图区域颜色折线颜色折点颜色

Python使用matplotlib函数subplot可视化多个不同颜色的折线图在折线图上为每个数据点添加数值标签

Python使用matplotlib函数subplot可视化多个不同颜色的折线图在折线图上为每个数据点添加日期数据标签