Altair图表中条件选择相等性异常问题:交互式房屋友谊分数可视化点击响应故障
Fixing Altair Interactive Friendship Score Visualization
Let's dig into why your code only works when clicking house D, and fix it up properly.
What's Going Wrong?
Your core issues are two-fold:
- Data Structure Overload: When you merged the geographic data with the long-format friendship data, you ended up with 16 rows (4 houses × 4 friendship pairs). This means each house's rectangle in your geo chart is actually rendering 4 overlapping data points, which confuses the selection logic.
- Condition Logic Mismatch: The
datum.selected_val==datum.house2check was backwards. You want to show the friendship score between the selected house and the current house being rendered, not the other way around.
Corrected Code
Here's the fixed version with clear improvements:
import altair as alt import pandas as pd families = ["A", "B", "C", "D"] # Geographical house locations (cleaned up column name) df = pd.DataFrame( { "x": [1, 2, 1, 2], "y": [1, 1, 2, 2], "house": families, } ) # Friendship data matrix friendship_df = pd.DataFrame( [[0, 1, 2, 3], [1, 0, 2, 3], [2, 2, 0, 1], [3, 3, 1, 0]], columns=families ) friendship_df = friendship_df.set_index(friendship_df.columns) # Convert to long format with clearer column names friendship_df_lf = ( friendship_df.melt(var_name="source_house", value_name="friendship", ignore_index=False) .reset_index() .rename(columns={"index": "target_house"}) ) # Selection: Pick one house to show friendships for selector = alt.selection_single(name="SelectedHouse", fields=["house"], empty="none") # Base geo chart (one row per house, no overlapping data) base_geo = alt.Chart(df, width=200, height=200).mark_rect(strokeWidth=1, stroke="white") # Interactive geo chart with dynamic lookup geo_chart = base_geo.add_selection(selector).encode( x=alt.X("x:N"), y=alt.Y("y:N"), color=alt.condition( selector, alt.Color( "friendship:O", scale=alt.Scale(scheme="redyellowblue", domain=[0, 1, 2, 3]), ), alt.value("grey") ) ).transform_lookup( # Match current house as target, and filter to the selected source house lookup="house", from_=alt.LookupData(friendship_df_lf, "target_house", ["friendship", "source_house"]), on="source_house", values=selector.fields ) # Add house labels text_chart = base_geo.mark_text().encode(text="house") tot_chart = geo_chart + text_chart # Improved score matrix (only shows selected house's row) score_chart = ( alt.Chart(friendship_df_lf, width=200, height=200) .mark_rect() .encode( x="source_house:N", y="target_house:N", color=alt.condition( selector, alt.Color( "friendship:O", scale=alt.Scale(scheme="redyellowblue", domain=[0, 1, 2, 3]), ), alt.value("grey"), ), ) ).transform_filter( alt.datum.source_house == selector.house ) alt.vconcat(tot_chart, score_chart).show()
Key Improvements
- Cleaner Data Naming: Renamed columns to
source_houseandtarget_houseso it's obvious which direction the friendship score goes. - Single-Row Per House: The geo chart now uses the original 4-row dataset, so each rectangle maps to exactly one house (no overlapping data points).
- Dynamic Lookup: Instead of merging all data upfront,
transform_lookupfetches only the friendship score relevant to the selected house, making the logic more efficient and clear. - Matrix Optimization: Added a
transform_filterto the score matrix so it only highlights the row for the selected house, making it easier to cross-verify with the geo chart.
Now clicking any house (A, B, C, or D) will correctly update the geo chart to show friendship scores between the selected house and all others, just like the matrix does!
内容的提问来源于stack exchange,提问作者Kaqmak
相关产品推荐
相关产品推荐

