ai
  • Crypto News
  • Ai
  • eSports
  • Bitcoin
  • Ethereum
  • Blockchain
Home»Ai»How to Build a Fully Interactive, Real-Time Visualization Dashboard Using Bokeh and Custom JavaScript?
Ai

How to Build a Fully Interactive, Real-Time Visualization Dashboard Using Bokeh and Custom JavaScript?

Share
Facebook Twitter LinkedIn Pinterest Email

In this tutorial, we create a fully interactive, visually compelling data visualization dashboard using Bokeh. We start by turning raw data into insightful plots, then enhance them with features such as linked brushing, color gradients, and real-time filters powered by dropdowns and sliders. As we progress, we bring our dashboard to life with Custom JavaScript (CustomJS) interactivity, enabling instant browser-side responses without a single Python callback. By blending the best of Python’s analytical strength with JavaScript’s responsiveness, we build a seamless, dynamic dashboard experience that redefines how we visualize and interact with data. Check out the FULL CODES here.

!pip install bokeh pandas numpy scipy -q


import numpy as np
import pandas as pd
from bokeh.io import output_notebook, show, export_png, output_file
from bokeh.plotting import figure
from bokeh.layouts import row, column, gridplot
from bokeh.models import (
   ColumnDataSource, HoverTool, LassoSelectTool, BoxSelectTool, TapTool,
   ColorBar, LinearColorMapper, BasicTicker, PrintfTickFormatter, Slider,
   Select, CheckboxGroup, CustomJS, CDSView, BooleanFilter, Div, Button
)
from bokeh.palettes import Viridis256
from bokeh.models.widgets import DataTable, TableColumn


output_notebook()


np.random.seed(42)
N = 300
data = pd.DataFrame({
   "temp_c": 20 + 5 * np.random.randn(N),
   "pressure_kpa": 101 + 3 * np.random.randn(N),
   "humidity_pct": 40 + 15 * np.random.randn(N),
   "sensor_id": np.random.choice(["A1","A2","B7","C3"], size=N),
   "timestep": np.arange(N)
})


source_main = ColumnDataSource(data)


p_scatter = figure(title="Temperature vs Pressure", width=400, height=300,
                  x_axis_label="Temperature (°C)", y_axis_label="Pressure (kPa)",
                  tools="pan,wheel_zoom,reset")


scat = p_scatter.circle(x="temp_c", y="pressure_kpa", size=8, fill_alpha=0.6,
                       fill_color="orange", line_color="black", source=source_main,
                       legend_label="Sensor Readings")


hover = HoverTool(tooltips=[
   ("Temp (°C)", "@temp_c{0.0}"), ("Pressure", "@pressure_kpa{0.0} kPa"),
   ("Humidity", "@humidity_pct{0.0}%"), ("Sensor", "@sensor_id"),
   ("Timestep", "@timestep")], renderers=[scat])
p_scatter.add_tools(hover)
p_scatter.legend.location = "top_left"
show(p_scatter)

We begin by setting up our environment and importing all the necessary libraries. We then create a synthetic dataset and visualize temperature against pressure using a simple scatter plot with hover functionality. This helps us establish a foundation for our interactive dashboard. Check out the FULL CODES here.

p_humidity = figure(title="Humidity vs Temperature (Linked Selection)", width=400, height=300,
                   x_axis_label="Temperature (°C)", y_axis_label="Humidity (%)",
                   tools="pan,wheel_zoom,reset,box_select,lasso_select,tap")


r2 = p_humidity.square(x="temp_c", y="humidity_pct", size=8, fill_alpha=0.6,
                      fill_color="navy", line_color="white", source=source_main)


p_humidity.add_tools(HoverTool(tooltips=[
   ("Temp (°C)", "@temp_c{0.0}"), ("Humidity", "@humidity_pct{0.0}%"),
   ("Sensor", "@sensor_id")], renderers=[r2]))


layout_linked = row(p_scatter, p_humidity)
show(layout_linked)

We extend our visualization by adding another plot that links humidity and temperature through shared data. We use linked brushing so that selections in one plot automatically reflect in the other, helping us analyze relationships across multiple variables simultaneously. Check out the FULL CODES here.

color_mapper = LinearColorMapper(palette=Viridis256, low=data["humidity_pct"].min(),
                                high=data["humidity_pct"].max())


p_color = figure(title="Pressure vs Humidity (Colored by Humidity)", width=500, height=350,
                x_axis_label="Pressure (kPa)", y_axis_label="Humidity (%)",
                tools="pan,wheel_zoom,reset,box_select,lasso_select")


r3 = p_color.circle(x="pressure_kpa", y="humidity_pct", size=8, fill_alpha=0.8,
                   line_color=None, color={"field": "humidity_pct", "transform": color_mapper},
                   source=source_main)


color_bar = ColorBar(color_mapper=color_mapper, ticker=BasicTicker(desired_num_ticks=5),
                    formatter=PrintfTickFormatter(format="%4.1f%%"), label_standoff=8,
                    border_line_color=None, location=(0,0), title="Humidity %")


p_color.add_layout(color_bar, "right")
show(p_color)

We enhance our visualization by introducing a continuous color mapping feature to represent humidity levels. By adding a color bar and gradient, we make our chart more informative and intuitive, allowing us to interpret variations visually. Check out the FULL CODES here.

sensor_options = sorted(data["sensor_id"].unique().tolist())
sensor_select = Select(title="Sensor ID Filter", value=sensor_options[0], options=sensor_options)
temp_slider = Slider(title="Max Temperature (°C)",
                    start=float(data["temp_c"].min()),
                    end=float(data["temp_c"].max()), step=0.5,
                    value=float(data["temp_c"].max()))


columns_available = ["temp_c", "pressure_kpa", "humidity_pct", "sensor_id", "timestep"]
checkbox_group = CheckboxGroup(labels=columns_available,
                              active=list(range(len(columns_available))))


def filter_mask(sensor_val, max_temp):
   return [(s == sensor_val) and (t Interactive Filters"), sensor_select,
                            temp_slider, Div(text="Columns in Table"), checkbox_group)
dashboard_layout = row(column(p_filtered, table_widget), dashboard_controls)
show(dashboard_layout)

We introduce interactivity through widgets such as dropdowns, sliders, and checkboxes. We dynamically filter data and update tables in real time, enabling us to easily explore different subsets and attributes of the dataset. Check out the FULL CODES here.

mini_source = ColumnDataSource({
   "x": np.linspace(0, 2*np.pi, 80),
   "y": np.sin(np.linspace(0, 2*np.pi, 80))
})


p_wave = figure(title="Sine Wave (CustomJS: Enlarge points)", width=400, height=250,
               tools="pan,wheel_zoom,reset")


wave_render = p_wave.circle(x="x", y="y", size=6, fill_alpha=0.8,
                           fill_color="green", line_color="black", source=mini_source)


js_callback = CustomJS(args=dict(r=wave_render),
                      code="const new_size = r.glyph.size.value + 2; r.glyph.size = new_size;")


grow_button = Button(label="Enlarge points (CustomJS)", button_type="success")
grow_button.js_on_click(js_callback)
show(column(p_wave, grow_button))

We implement a JavaScript-based interaction using Bokeh’s CustomJS. We create a sine wave visualization and allow users to enlarge the plot markers with a button click, demonstrating client-side control without any Python callbacks. Check out the FULL CODES here.

stream_source = ColumnDataSource({"t": [], "val": []})


p_stream = figure(title="Streaming Sensor Value", width=500, height=250,
                 x_axis_label="timestep", y_axis_label="value",
                 tools="pan,wheel_zoom,reset")


p_stream.line(x="t", y="val", source=stream_source, line_width=3, line_alpha=0.8)
p_stream.circle(x="t", y="val", source=stream_source, size=6, fill_color="red")
show(p_stream)


for t in range(10):
   new_point = {"t": [t], "val": [np.sin(t/2) + 0.2*np.random.randn()]}
   stream_source.stream(new_point, rollover=200)


show(p_stream)

We simulate a live data stream by continuously adding new data points to our plot. We watch the visualization update dynamically, showcasing how Bokeh can handle real-time data and provide instant visual feedback.

In conclusion, we create a fully functional, real-time, and browser-interactive dashboard that showcases the full potential of Bokeh. We learn how to visualize multiple dimensions of data, dynamically filter and update visuals, and even harness JavaScript integration to make instant, client-side updates directly within the browser. This hands-on experience shows us how Bokeh effortlessly merges Python and JavaScript, empowering us to design dashboards that are not just interactive but intelligent, responsive, and production-ready.


Check out the FULL CODES here. Feel free to check out our GitHub Page for Tutorials, Codes and Notebooks. Also, feel free to follow us on Twitter and don’t forget to join our 100k+ ML SubReddit and Subscribe to our Newsletter. Wait! are you on telegram? now you can join us on telegram as well.


Asif Razzaq is the CEO of Marktechpost Media Inc.. As a visionary entrepreneur and engineer, Asif is committed to harnessing the potential of Artificial Intelligence for social good. His most recent endeavor is the launch of an Artificial Intelligence Media Platform, Marktechpost, which stands out for its in-depth coverage of machine learning and deep learning news that is both technically sound and easily understandable by a wide audience. The platform boasts of over 2 million monthly views, illustrating its popularity among audiences.

🙌 Follow MARKTECHPOST: Add us as a preferred source on Google.

Share. Facebook Twitter Pinterest LinkedIn Tumblr Email

Related Posts

Finding return on AI investments across industries

octobre 28, 2025

The Download: Microsoft’s stance on erotic AI, and an AI hype mystery

octobre 28, 2025

Meet Pyversity Library: How to Improve Retrieval Systems by Diversifying the Results Using Pyversity?

octobre 28, 2025

The Download: What to make of OpenAI’s Atlas browser, and how to make climate progress

octobre 27, 2025
Add A Comment

Comments are closed.

Top Posts

SwissCryptoDaily.ch delivers the latest cryptocurrency news, market insights, and expert analysis. Stay informed with daily updates from the world of blockchain and digital assets.

We're social. Connect with us:

Facebook X (Twitter) Instagram Pinterest YouTube
Top Insights

Finding return on AI investments across industries

octobre 28, 2025

TradFi will have to use public blockchains: FG Nexus CEO

octobre 28, 2025

How to Turn ChatGPT Into Your Personal Crypto Trading Assistant

octobre 28, 2025
Get Informed

Subscribe to Updates

Get the latest creative news from FooBar about art, design and business.

Facebook X (Twitter) Instagram Pinterest
  • About us
  • Get In Touch
  • Cookies Policy
  • Privacy-Policy
  • Terms and Conditions
© 2025 Swisscryptodaily.ch.

Type above and press Enter to search. Press Esc to cancel.