feat([2fd88f42]): display attributes in point tooltip
This commit is contained in:
@@ -116,8 +116,24 @@ async def get_heatmap_data(request: FilterRequest):
|
|||||||
if filtered_df.empty:
|
if filtered_df.empty:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# Aggregate data by PLZ
|
# Aggregate data by PLZ, and also collect attribute summaries
|
||||||
plz_counts = filtered_df.groupby(plz_column_name).size().reset_index(name='count')
|
plz_grouped = filtered_df.groupby(plz_column_name)
|
||||||
|
plz_counts = plz_grouped.size().reset_index(name='count')
|
||||||
|
|
||||||
|
# Collect unique attributes for each PLZ
|
||||||
|
attribute_summaries = {}
|
||||||
|
for plz_val, group in plz_grouped:
|
||||||
|
summary = {}
|
||||||
|
for col in filtered_df.columns:
|
||||||
|
if col != plz_column_name and col != 'lat' and col != 'lon': # Exclude lat/lon if they somehow exist
|
||||||
|
unique_attrs = group[col].unique().tolist()
|
||||||
|
# Limit to top 3 unique values for readability
|
||||||
|
summary[col] = unique_attrs[:3]
|
||||||
|
attribute_summaries[plz_val] = summary
|
||||||
|
|
||||||
|
# Convert summaries to a DataFrame for merging
|
||||||
|
summary_df = pd.DataFrame.from_dict(attribute_summaries, orient='index')
|
||||||
|
summary_df.index.name = plz_column_name
|
||||||
|
|
||||||
# --- Geocoding Step ---
|
# --- Geocoding Step ---
|
||||||
# Merge the aggregated counts with the geocoding dataframe
|
# Merge the aggregated counts with the geocoding dataframe
|
||||||
@@ -129,17 +145,45 @@ async def get_heatmap_data(request: FilterRequest):
|
|||||||
how='inner'
|
how='inner'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Merge with attribute summaries
|
||||||
|
merged_df = pd.merge(
|
||||||
|
merged_df,
|
||||||
|
summary_df,
|
||||||
|
left_on=plz_column_name,
|
||||||
|
right_index=True,
|
||||||
|
how='left'
|
||||||
|
)
|
||||||
|
|
||||||
# Rename columns to match frontend expectations ('lon' and 'lat')
|
# Rename columns to match frontend expectations ('lon' and 'lat')
|
||||||
merged_df.rename(columns={'x': 'lon', 'y': 'lat'}, inplace=True)
|
merged_df.rename(columns={'x': 'lon', 'y': 'lat'}, inplace=True)
|
||||||
|
|
||||||
# Also rename the original PLZ column to the consistent name 'plz'
|
# Also rename the original PLZ column to the consistent name 'plz'
|
||||||
merged_df.rename(columns={plz_column_name: 'plz'}, inplace=True)
|
merged_df.rename(columns={plz_column_name: 'plz'}, inplace=True)
|
||||||
|
|
||||||
# Convert to the required JSON format
|
# Convert to the required JSON format, including all remaining columns (which are the attributes)
|
||||||
heatmap_data = merged_df[['plz', 'lat', 'lon', 'count']].to_dict(orient='records')
|
# We'll dynamically collect attribute columns for output
|
||||||
|
output_columns = ['plz', 'lat', 'lon', 'count']
|
||||||
|
for col in merged_df.columns:
|
||||||
|
if col not in output_columns and col != plz_column_name: # Ensure we don't duplicate PLZ or coords
|
||||||
|
output_columns.append(col)
|
||||||
|
|
||||||
|
heatmap_data = merged_df[output_columns].to_dict(orient='records')
|
||||||
|
|
||||||
print(f"Generated heatmap data with {len(heatmap_data)} PLZ points.")
|
# The frontend expects 'attributes_summary' as a single field, so let's restructure for that
|
||||||
return heatmap_data
|
# For each record, pick out the attributes that are not 'plz', 'lat', 'lon', 'count'
|
||||||
|
final_heatmap_data = []
|
||||||
|
for record in heatmap_data:
|
||||||
|
attrs = {k: v for k, v in record.items() if k not in ['plz', 'lat', 'lon', 'count']}
|
||||||
|
final_heatmap_data.append({
|
||||||
|
"plz": record['plz'],
|
||||||
|
"lat": record['lat'],
|
||||||
|
"lon": record['lon'],
|
||||||
|
"count": record['count'],
|
||||||
|
"attributes_summary": attrs
|
||||||
|
})
|
||||||
|
|
||||||
|
print(f"Generated heatmap data with {len(final_heatmap_data)} PLZ points.")
|
||||||
|
return final_heatmap_data
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"ERROR generating heatmap: {e}")
|
print(f"ERROR generating heatmap: {e}")
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export interface HeatmapPoint {
|
|||||||
lat: number;
|
lat: number;
|
||||||
lon: number;
|
lon: number;
|
||||||
count: number;
|
count: number;
|
||||||
|
attributes_summary?: Record<string, string[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MapMode = 'points' | 'heatmap';
|
export type MapMode = 'points' | 'heatmap';
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ const MapDisplay: React.FC<MapDisplayProps> = ({ heatmapData, radiusMultiplier,
|
|||||||
<Tooltip>
|
<Tooltip>
|
||||||
PLZ: {point.plz} <br />
|
PLZ: {point.plz} <br />
|
||||||
Count: {point.count}
|
Count: {point.count}
|
||||||
|
{point.attributes_summary && Object.entries(point.attributes_summary).map(([attr, values]) => (
|
||||||
|
<div key={attr}>
|
||||||
|
<strong>{attr}:</strong> {values.join(', ')}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</CircleMarker>
|
</CircleMarker>
|
||||||
))
|
))
|
||||||
|
|||||||
Reference in New Issue
Block a user