多数据源绘图可行性及客户端数据源合并链接方案咨询
Hey there! Let's walk through your questions about working with multiple data sources in Bokeh clearly:
1. 是否支持从多种数据源绘制数据?
Absolutely! Bokeh fully supports using multiple ColumnDataSource instances in a single plot. You can assign different sources to different glyphs (e.g., a line from source1 and circles from source2), or even combine data from multiple sources for a single glyph—you just need to use the right approach to link them, which leads into your next question.
2. 是否可基于多个数据源创建绘图?
Your core idea is solid, but the sample code you provided has a small issue: Bokeh's glyph methods (like circle()) don't actually have a sources parameter.
To create a glyph that uses data from multiple sources, you have two main options:
- Option 1 (Python-side merge): Combine the data into a single
ColumnDataSourcebefore plotting. But this doesn't fit your later requirement of independent updates, so let's focus on the better option... - Option 2 (Client-side linking): Use client-side JavaScript to pull data from multiple sources and feed it to your glyph. This is the way to go if you need to update sources independently.
Here's a corrected setup that lays the groundwork for your third question:
from bokeh.models import ColumnDataSource, figure from bokeh.plotting import show # Your original sources source1 = ColumnDataSource({'x': [1,2,3]}) source2 = ColumnDataSource({'y': [5,5,7]}) # A combined source that will hold merged data for the glyph combined_source = ColumnDataSource({'x': [], 'y': []}) p = figure(plot_width=400, plot_height=400) # We'll use the combined source for the circle glyph p.circle(x='x', y='y', size=20, source=combined_source)
3. 是否可在客户端通过自定义JavaScript合并、组合或链接数据源?
Yes! This is exactly the right solution for your use case—keeping the static source2 untouched most of the time, only updating the frequently changing source1 to save bandwidth.
We can add a CustomJS callback that automatically merges data from source1 and source2 whenever either source updates, then triggers the plot to refresh. Here's the full working code:
from bokeh.models import ColumnDataSource, CustomJS, figure from bokeh.plotting import show # Static data source (rarely updated) source2 = ColumnDataSource({'y': [5,5,7]}) # Frequently updated data source source1 = ColumnDataSource({'x': [1,2,3]}) # Combined source for the plot combined_source = ColumnDataSource({'x': [], 'y': []}) p = figure(plot_width=400, plot_height=400) p.circle(x='x', y='y', size=20, source=combined_source) # CustomJS to merge data on the client side merge_callback = CustomJS( args=dict(s1=source1, s2=source2, combined=combined_source), code=""" // Make sure both sources have matching data lengths if (s1.data.x.length !== s2.data.y.length) return; // Merge the data from both sources combined.data = { x: s1.data.x, y: s2.data.y }; // Tell Bokeh the combined source has changed to update the plot combined.change.emit(); """ ) # Attach the callback to both sources so changes trigger a merge source1.js_on_change('data', merge_callback) source2.js_on_change('data', merge_callback) # Trigger the callback once initially to load the default data merge_callback.trigger('data', source1.data, source1.data) show(p)
How this works:
- When you update
source1(e.g., via anAjaxDataSourceor pushing updates from the server), only the newxvalues are sent over the network. source2stays static, so it never needs to be retransmitted.- The client-side JS automatically merges the latest
xfromsource1with the staticyfromsource2, updating the plot without extra server overhead.
You can also extend the CustomJS code to do more complex data transformations (like calculations, filtering, or reshaping) if needed—all happens directly in the browser, no server round-trip required.
内容的提问来源于stack exchange,提问作者Leevi L

