建設(shè)旅游網(wǎng)站的市場分析wordpress關(guān)于我們
鶴壁市浩天電氣有限公司
2026/01/22 08:22:50
建設(shè)旅游網(wǎng)站的市場分析,wordpress關(guān)于我們,東莞企業(yè)免費模版網(wǎng)站建設(shè),如何網(wǎng)站增加域名超越靜態(tài)圖表#xff1a;Bokeh可視化API的實時數(shù)據(jù)流與交互式應用開發(fā)深度解析
引言#xff1a;可視化開發(fā)的范式轉(zhuǎn)變
在數(shù)據(jù)科學和Web應用開發(fā)領(lǐng)域#xff0c;數(shù)據(jù)可視化已從簡單的靜態(tài)圖表演變?yōu)閺碗s的交互式應用程序。雖然Matplotlib和Seaborn等庫在靜態(tài)可視化領(lǐng)域表現(xiàn)出…超越靜態(tài)圖表Bokeh可視化API的實時數(shù)據(jù)流與交互式應用開發(fā)深度解析引言可視化開發(fā)的范式轉(zhuǎn)變在數(shù)據(jù)科學和Web應用開發(fā)領(lǐng)域數(shù)據(jù)可視化已從簡單的靜態(tài)圖表演變?yōu)閺碗s的交互式應用程序。雖然Matplotlib和Seaborn等庫在靜態(tài)可視化領(lǐng)域表現(xiàn)出色但它們難以滿足現(xiàn)代實時數(shù)據(jù)監(jiān)控、儀表盤開發(fā)和交互式數(shù)據(jù)探索的需求。Bokeh作為一個Python交互式可視化庫通過其獨特的架構(gòu)設(shè)計為開發(fā)者提供了構(gòu)建從簡單圖表到復雜數(shù)據(jù)應用的全套工具。本文將深入探討B(tài)okeh的高級特性特別關(guān)注其在實時數(shù)據(jù)流處理和復雜交互式應用開發(fā)方面的能力提供超越基礎(chǔ)教程的深度技術(shù)解析。Bokeh架構(gòu)深度解析雙模型系統(tǒng)bokeh.models與bokeh.plottingBokeh的核心設(shè)計理念是分離視覺表示和渲染邏輯這一設(shè)計通過兩個互補的API層實現(xiàn)# 低級模型API示例 - 完全控制 from bokeh.models import ColumnDataSource, Range1d, Circle, LinearAxis, Grid from bokeh.models import PanTool, WheelZoomTool, ResetTool, HoverTool from bokeh.plotting import figure, output_file, show from bokeh.layouts import column from bokeh.document import Document from bokeh.io import curdoc # 創(chuàng)建數(shù)據(jù)源 - Bokeh可視化核心 source ColumnDataSource(data{ x: [1, 2, 3, 4, 5], y: [6, 7, 2, 4, 5], category: [A, B, A, C, B], size: [10, 15, 8, 12, 20] }) # 使用低級模型構(gòu)建圖形 plot figure( title低級API構(gòu)建的圖表, x_rangeRange1d(0, 6), y_rangeRange1d(0, 10), width600, height400, toolspan,wheel_zoom,reset ) # 手動添加圖形元素 plot.add_glyph(source, Circle(xx, yy, sizesize, fill_colorcategory, fill_alpha0.6)) plot.add_layout(LinearAxis(axis_labelX軸), below) plot.add_layout(LinearAxis(axis_labelY軸), left) plot.add_layout(Grid(dimension0, tickerplot.xaxis[0].ticker)) plot.add_layout(Grid(dimension1, tickerplot.yaxis[0].ticker)) # 添加高級交互工具 hover HoverTool(tooltips[ (索引, $index), ((x,y), (x, y)), (類別, category), (大小, size) ]) plot.add_tools(hover)ColumnDataSourceBokeh的心臟ColumnDataSource不僅僅是數(shù)據(jù)容器它是Bokeh實現(xiàn)高效數(shù)據(jù)流和客戶端-服務(wù)器通信的核心。其獨特之處在于import numpy as np from bokeh.models import ColumnDataSource from bokeh.plotting import figure, show from bokeh.layouts import gridplot from bokeh.io import output_notebook output_notebook() # 高級ColumnDataSource使用 class StreamingDataSource: 自定義流式數(shù)據(jù)源演示ColumnDataSource的擴展性 def __init__(self, initial_dataNone): self._source ColumnDataSource(initial_data or {x: [], y: []}) self._callback_id None self._stream_count 0 def start_streaming(self, document, interval100): 啟動數(shù)據(jù)流更新 from tornado.ioloop import PeriodicCallback def stream_callback(): self._stream_count 1 new_data { x: [self._stream_count], y: [np.sin(self._stream_count * 0.1) np.random.normal(0, 0.1)] } self._source.stream(new_data, rollover100) # 保持最近100個點 self._callback_id PeriodicCallback(stream_callback, interval) self._callback_id.start() document.add_next_tick_callback(lambda: self._callback_id.start()) def stop_streaming(self): if self._callback_id: self._callback_id.stop() property def source(self): return self._source # 創(chuàng)建流式數(shù)據(jù)可視化 stream_source StreamingDataSource({x: [0], y: [0]}) plot figure(width800, height400, title實時數(shù)據(jù)流示例) plot.line(x, y, sourcestream_source.source, line_width2) plot.circle(x, y, sourcestream_source.source, size8) # 注意在實際Bokeh服務(wù)器應用中start_streaming需要在服務(wù)器回調(diào)中調(diào)用實時數(shù)據(jù)可視化Bokeh服務(wù)器的高級應用基于WebSocket的實時數(shù)據(jù)流架構(gòu)Bokeh服務(wù)器通過WebSocket連接實現(xiàn)瀏覽器和Python服務(wù)器之間的雙向通信這是其實時可視化能力的核心# bokeh_server_app.py # 完整的Bokeh服務(wù)器應用示例 from bokeh.io import curdoc from bokeh.models import ColumnDataSource, Slider, Button, Div from bokeh.layouts import column, row from bokeh.plotting import figure import numpy as np from datetime import datetime import asyncio class RealTimeMonitoringSystem: 實時監(jiān)控系統(tǒng)演示類 def __init__(self): # 初始化數(shù)據(jù)源 self.time_points 100 self.data_source ColumnDataSource({ timestamp: [datetime.now().timestamp() - i for i in range(self.time_points)], temperature: np.random.normal(25, 2, self.time_points).tolist(), pressure: np.random.normal(1000, 50, self.time_points).tolist(), humidity: np.random.normal(50, 10, self.time_points).tolist(), anomaly: [0] * self.time_points # 異常檢測標記 }) # 創(chuàng)建圖表 self.create_plots() self.setup_widgets() self.setup_layout() # 模擬數(shù)據(jù)更新任務(wù) self.update_task None def create_plots(self): 創(chuàng)建多個關(guān)聯(lián)的可視化圖表 # 溫度圖表 self.temp_plot figure( width800, height300, title實時溫度監(jiān)測, x_axis_label時間, y_axis_label溫度 (°C), x_axis_typedatetime, toolspan,wheel_zoom,box_zoom,reset,save ) self.temp_line self.temp_plot.line( timestamp, temperature, sourceself.data_source, line_width2, colorfirebrick, legend_label溫度 ) self.temp_plot.circle( timestamp, temperature, sourceself.data_source, size4, colorfirebrick, alpha0.6 ) # 異常檢測高亮異常點 anomaly_source ColumnDataSource({ x: [], y: [], label: [] }) self.temp_plot.triangle( xx, yy, sourceanomaly_source, size10, colorred, legend_label異常點 ) # 關(guān)聯(lián)直方圖 self.hist_plot figure( width400, height300, title溫度分布, x_axis_label溫度 (°C), y_axis_label頻次 ) # 添加交互 self.temp_plot.add_tools(HoverTool( tooltips[ (時間, timestamp{%F %T}), (溫度, temperature{0.0} °C), (濕度, humidity{0}%), (壓力, pressure{0} hPa) ], formatters{timestamp: datetime}, modevline )) def setup_widgets(self): 創(chuàng)建控制面板 self.sample_rate Slider( title采樣頻率 (Hz), start0.1, end10, value1, step0.1 ) self.threshold Slider( title異常閾值, start0, end10, value2, step0.1 ) self.start_btn Button(label開始監(jiān)控, button_typesuccess) self.stop_btn Button(label停止監(jiān)控, button_typedanger) self.reset_btn Button(label重置數(shù)據(jù), button_typewarning) self.status_div Div( texth4系統(tǒng)狀態(tài): 就緒/h4, style{color: green} ) # 連接回調(diào)函數(shù) self.start_btn.on_click(self.start_monitoring) self.stop_btn.on_click(self.stop_monitoring) self.reset_btn.on_click(self.reset_data) self.threshold.on_change(value, self.update_anomaly_detection) def start_monitoring(self): 開始實時監(jiān)控 if self.update_task and not self.update_task.done(): return async def update(): while True: await asyncio.sleep(1 / self.sample_rate.value) self.update_data() self.update_task asyncio.create_task(update()) self.status_div.text h4系統(tǒng)狀態(tài): 運行中/h4 self.status_div.style {color: blue} def update_data(self): 模擬數(shù)據(jù)更新 import random from datetime import datetime new_timestamp datetime.now().timestamp() new_temp 25 5 * np.sin(new_timestamp * 0.01) random.gauss(0, 1) new_pressure 1000 20 * np.sin(new_timestamp * 0.005) new_humidity 50 10 * np.sin(new_timestamp * 0.002) # 檢測異常 anomaly 1 if abs(new_temp - 25) self.threshold.value * 2 else 0 # 流式更新數(shù)據(jù) new_data { timestamp: [new_timestamp], temperature: [new_temp], pressure: [new_pressure], humidity: [new_humidity], anomaly: [anomaly] } self.data_source.stream(new_data, rollover500) # 更新統(tǒng)計信息 current_data self.data_source.data[temperature][-100:] mean_temp np.mean(current_data) std_temp np.std(current_data) # 更新直方圖數(shù)據(jù) hist, edges np.histogram(current_data, bins20) if not hasattr(self, hist_source): self.hist_source ColumnDataSource({ top: hist, left: edges[:-1], right: edges[1:] }) self.hist_plot.quad( toptop, bottom0, leftleft, rightright, sourceself.hist_source, fill_colornavy, alpha0.7 ) else: self.hist_source.data { top: hist, left: edges[:-1], right: edges[1:] } def update_anomaly_detection(self, attr, old, new): 更新異常檢測閾值 # 這里可以實現(xiàn)更復雜的異常檢測邏輯 pass def stop_monitoring(self): 停止監(jiān)控 if self.update_task: self.update_task.cancel() self.status_div.text h4系統(tǒng)狀態(tài): 已停止/h4 self.status_div.style {color: red} def reset_data(self): 重置所有數(shù)據(jù) self.data_source.data { timestamp: [], temperature: [], pressure: [], humidity: [], anomaly: [] } self.status_div.text h4系統(tǒng)狀態(tài): 已重置/h4 self.status_div.style {color: orange} def setup_layout(self): 設(shè)置應用布局 controls column( self.status_div, self.sample_rate, self.threshold, row(self.start_btn, self.stop_btn, self.reset_btn), width300 ) plots column(self.temp_plot, self.hist_plot) self.layout row(plots, controls) def get_layout(self): return self.layout # 創(chuàng)建并運行應用 monitoring_system RealTimeMonitoringSystem() curdoc().add_root(monitoring_system.get_layout()) curdoc().title 實時工業(yè)監(jiān)控系統(tǒng)高級交互功能與自定義擴展自定義JavaScript回調(diào)Bokeh允許在Python和JavaScript之間無縫切換實現(xiàn)復雜的客戶端交互# 自定義JavaScript工具和交互 from bokeh.models import CustomJS, TapTool, BoxSelectTool from bokeh.plotting import figure, show from bokeh.layouts import column from bokeh.models.widgets import Div import numpy as np # 創(chuàng)建數(shù)據(jù) x np.linspace(0, 4*np.pi, 200) y np.sin(x) phases np.linspace(0, 2*np.pi, 6) source ColumnDataSource(data{x: x, y: y}) # 主圖表 main_plot figure(width800, height400, title相位交互演示) main_line main_plot.line(x, y, sourcesource, line_width3) # 相位控制圖 phase_plot figure(width800, height150, title選擇相位, toolstap, toolbar_locationNone) phase_plot.xgrid.grid_line_color None phase_plot.ygrid.grid_line_color None # 創(chuàng)建相位指示器 phase_indicators [] for i, phase in enumerate(phases): # 相位指示器 phase_plot.vbar(xi, top1, width0.8, bottom0, colorlightgray, alpha0.5) # 相位標簽 phase_plot.text(xi, y0.5, text[f{phase:.1f}], text_aligncenter, text_baselinemiddle) # 添加自定義JavaScript回調(diào) phase_callback CustomJS(argsdict( sourcesource, phasesphases.tolist(), main_linemain_line ), code // 獲取選中的相位索引 const indices cb_data.source.selected.indices; if (indices.length 0) { const phaseIndex indices[0]; const selectedPhase phases[phaseIndex]; // 更新正弦波相位 const x source.data.x; const newY new Array(x.length); for (let i 0; i x.length; i) { newY[i] Math.sin(x[i] selectedPhase); } source.data.y newY; // 更新圖表顏色 const colors [#e41a1c, #377eb8, #4daf4a, #984ea3, #ff7f00, #ffff33]; main_line.glyph.line_color colors[phaseIndex % colors.length]; // 觸發(fā)更新 source.change.emit(); } ) # 添加點擊工具 phase_plot.add_tools(TapTool(callbackphase_callback)) # 信息顯示 info_div Div(text h3相位交互演示/h3 p點擊下方的相位條來改變正弦波的相位。/p p當前相位: span idphase-display0.0/span/p ) # 更新相位顯示的回調(diào) update_display CustomJS(argsdict(info_divinfo_div), code const phase cb_obj.data[y][0] || 0; const display document.getElementById(phase-display); display.textContent phase.toFixed(2); ) source.js_on_change(data, update_display) # 布局 layout column(info_div, main_plot, phase