Python实现Pandas列交互式图表:自定义Hover及优化实现方案
Great question! Let's tackle both the hover tool customization and making your code more Pythonic, plus cover a direct Bokeh implementation for good measure.
1. Improved Holoviews + Bokeh Implementation (Cleaner & Hover with Week Number)
Your original approach using reduce to combine curves works, but Holoviews offers more intuitive ways to group multiple lines, and we can easily tweak the hover tool to show the week number.
Here's a more Pythonic implementation that fixes the hover issue:
import holoviews as hv import pandas as pd import numpy as np # Regenerate your DataFrame (for reproducibility) np.random.seed(42) df = pd.DataFrame(np.random.randint(0, 1000, size=(24,53))) df['hour'] = range(24) df.rename(columns={col: str(col) for col in df.columns[:-1]}, inplace=True) hv.extension('bokeh') # Use NdOverlay to organize curves by week - hover will auto-include week info hv.NdOverlay({week: hv.Curve(df, 'hour', week, label=f'Week {week}') for week in df.columns[:-1]}, kdims='Week')\ .opts( hv.opts.Curve(tools=['hover'], line_width=1), hv.opts.NdOverlay(legend_position='right') )
Key improvements:
- Cleaner syntax: The dictionary comprehension for
NdOverlayis far more readable than usingreduceto merge curves one by one. - Hover shows week number: By using
NdOverlaywithkdims='Week', the hover tool automatically displays the corresponding week for each point, along with the hour and value.
If you prefer Overlay instead, this also works (and is still cleaner than reduce):
hv.Overlay([hv.Curve(df, 'hour', week, label=f'Week {week}') for week in df.columns[:-1]])\ .opts( hv.opts.Curve(tools=['hover'], line_width=1), hv.opts.Overlay(legend_position='right') )
The hover tool will pull the week number directly from the curve's label here.
2. Direct Bokeh Implementation
If you want to skip Holoviews entirely, you can build this directly with Bokeh's native API. We'll manually add each curve and configure the hover tool to show all three pieces of info: hour, value, and week.
from bokeh.plotting import figure, show from bokeh.models import HoverTool, ColumnDataSource import pandas as pd import numpy as np # Regenerate your DataFrame np.random.seed(42) df = pd.DataFrame(np.random.randint(0, 1000, size=(24,53))) df['hour'] = range(24) df.rename(columns={col: str(col) for col in df.columns[:-1]}, inplace=True) # Create base figure p = figure(title='Hourly Values by Week', x_axis_label='Hour', y_axis_label='Value', tools='pan,box_zoom,reset,save') # Loop through each week column to add curves and hover tools for week in df.columns[:-1]: # Create a data source with explicit week info for hover source = ColumnDataSource(data=dict( hour=df['hour'], value=df[week], week=[week]*len(df) )) # Add the line to the figure p.line('hour', 'value', source=source, legend_label=f'Week {week}', line_width=1) # Add a hover tool specific to this line hover = HoverTool(renderers=[p.renderers[-1]], tooltips=[ ('Hour', '@hour'), ('Value', '@value'), ('Week', '@week') ]) p.add_tools(hover) # Tweak legend for better usability p.legend.location = 'top_right' p.legend.click_policy = 'hide' # Optional: let users click legend to hide/show lines show(p)
This gives you full control over the plot and hover behavior, plus added interactivity like hiding lines via the legend.
内容的提问来源于stack exchange,提问作者Dror

