You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Bokeh多折线图配置HoverTool及多Y轴悬浮显示?

Let's break down and fix your issues step by step:

1. Fix the ColumnDataSource Length Mismatch Warning

Your initial warning pops up because you packed two lists (pop_pakistan and pop_india) into a single population column—this makes its length 2, while year has 6 entries. ColumnDataSource requires all columns to share the same length.

The correct approach is to store each country's population as a separate column in the data source:

source = ColumnDataSource(data=dict(
    year=year,
    pop_pakistan=pop_pakistan,
    pop_india=pop_india
))

Now every column has 6 entries, eliminating the mismatch warning entirely.

2. Configure HoverTool to Show Correct Per-Country Data

Your modified code uses the shared data source but doesn’t set up the HoverTool properly to display values specific to each line. Here are two reliable ways to fix this:

Method 1: Single HoverTool with Automatic Series Detection

Use Bokeh’s $name variable to dynamically reference the data column of the hovered glyph. First, set a name parameter for each glyph (matching the column name in your data source), then configure the tooltip to use @$name:

hover = HoverTool(
    tooltips=[
        ("Year", "@year"),
        ("Country", "$name"),
        ("Population (million)", "@$name{0.2f}")
    ],
    mode='vline'  # Optional: Shows tooltip for all points at the hovered x-value
)

# Add glyphs with name matching data columns
plot.line('year', 'pop_pakistan', line_width=2, line_color='green', legend='Pakistan', source=source, name='Pakistan')
plot.circle('year', 'pop_pakistan', fill_color="green", line_color='green', size=8, source=source, name='Pakistan')
plot.line('year', 'pop_india', line_width=2, line_color='orange', legend='India', source=source, name='India')
plot.circle('year', 'pop_india', fill_color="orange", line_color='orange', size=8, source=source, name='India')

plot.add_tools(hover)

The $name variable pulls the name value from the hovered glyph, and @$name fetches the corresponding population data from the ColumnDataSource automatically.

Method 2: Separate HoverTools for Each Series

If you want custom tooltips per country, create individual HoverTools and assign them to specific renderers:

# Create hover tool for Pakistan
hover_pak = HoverTool(
    tooltips=[
        ("Year", "@year"),
        ("Pakistan Population", "@pop_pakistan{0.2f} million")
    ],
    renderers=[plot.renderers[0], plot.renderers[1]]  # Target Pakistan's line and circle
)

# Create hover tool for India
hover_ind = HoverTool(
    tooltips=[
        ("Year", "@year"),
        ("India Population", "@pop_india{0.2f} million")
    ],
    renderers=[plot.renderers[2], plot.renderers[3]]  # Target India's line and circle
)

plot.add_tools(hover_pak, hover_ind)

Just double-check that the renderers list targets the correct glyphs (order matches the sequence you added them to the plot).

3. HoverTool for Multiple Y-Axes

If you’re using multiple Y axes (e.g., to handle different population scales for each country), the setup is similar—you just need to:

  1. Add a second Y axis to your figure
  2. Assign each glyph to its respective Y axis with y_range_name
  3. Ensure your ColumnDataSource includes all necessary data columns
  4. Configure the HoverTool as normal (it will still pull values directly from the source)

Here’s a quick example:

# Create figure with two Y axes
plot = figure(
    title='Population Graph of India and Pakistan',
    x_axis_label='Year',
    y_axis_label='Pakistan Population (million)',
    y_range=(40, 180)
)

# Add second Y axis for India
plot.extra_y_ranges = {"india": Range1d(start=400, end=1400)}
plot.add_layout(LinearAxis(y_range_name="india", axis_label="India Population (million)"), 'right')

# Shared data source (same as before)
source = ColumnDataSource(data=dict(
    year=year,
    pop_pakistan=pop_pakistan,
    pop_india=pop_india
))

# Add Pakistan's glyphs (uses default Y axis)
plot.line('year', 'pop_pakistan', line_width=2, line_color='green', legend='Pakistan', source=source, name='Pakistan')
plot.circle('year', 'pop_pakistan', fill_color="green", line_color='green', size=8, source=source, name='Pakistan')

# Add India's glyphs (assign to second Y axis)
plot.line('year', 'pop_india', line_width=2, line_color='orange', legend='India', source=source, name='India', y_range_name="india")
plot.circle('year', 'pop_india', fill_color="orange", line_color='orange', size=8, source=source, name='India', y_range_name="india")

# Reuse the same HoverTool from Method 1
hover = HoverTool(
    tooltips=[
        ("Year", "@year"),
        ("Country", "$name"),
        ("Population (million)", "@$name{0.2f}")
    ],
    mode='vline'
)
plot.add_tools(hover)

Full Working Code

Putting it all together, here’s the complete fixed code for a single Y axis:

from bokeh.models import HoverTool, ColumnDataSource
from bokeh.plotting import figure, output_file, show

if __name__ == '__main__':
    year = [1960, 1970, 1980, 1990, 2000, 2010]
    pop_pakistan = [44.91, 58.09, 78.07, 107.7, 138.5, 170.6]
    pop_india = [449.48, 553.57, 696.783, 870.133, 1000.4, 1309.1]
    
    output_file('line.html', mode='inline')
    
    plot = figure(title='Population Graph of India and Pakistan', x_axis_label='Year', y_axis_label='Population in million')
    
    # Correct ColumnDataSource setup
    source = ColumnDataSource(data=dict(
        year=year,
        pop_pakistan=pop_pakistan,
        pop_india=pop_india
    ))
    
    # Configure dynamic HoverTool
    hover = HoverTool(
        tooltips=[
            ("Year", "@year"),
            ("Country", "$name"),
            ("Population", "@$name{0.2f} million")
        ],
        mode='vline'
    )
    plot.add_tools(hover)
    
    # Add glyphs with matching names
    plot.line('year', 'pop_pakistan', line_width=2, line_color='green', legend='Pakistan', source=source, name='Pakistan')
    plot.circle('year', 'pop_pakistan', fill_color="green", line_color='green', size=8, source=source, name='Pakistan')
    plot.line('year', 'pop_india', line_width=2, line_color='orange', legend='India', source=source, name='India')
    plot.circle('year', 'pop_india', fill_color="orange", line_color='orange', size=8, source=source, name='India')
    
    # Optional: Adjust legend position
    plot.legend.location = 'top_left'
    
    show(plot)

内容的提问来源于stack exchange,提问作者Volatil3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:40:25