Basic Scatter Plot — Bokeh

A fundamental 2D scatter plot that displays the relationship between two numeric variables by plotting points on a Cartesian coordinate system. This visualization is essential for exploring correlations, identifying patterns, detecting outliers, and understanding the distribution of paired data points.

Basic Scatter Plot rendered with Bokeh

Python source (Bokeh)

""" anyplot.ai
scatter-basic: Basic Scatter Plot
Library: bokeh 3.9.0 | Python 3.14.4
Quality: 90/100 | Updated: 2026-04-23
"""

import os

import numpy as np
from bokeh.io import export_png, output_file, save
from bokeh.models import ColumnDataSource, HoverTool
from bokeh.plotting import figure


THEME = os.getenv("ANYPLOT_THEME", "light")
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
BRAND = "#009E73"

# Data — study hours vs exam scores, moderate positive correlation
np.random.seed(42)
n_points = 180
study_hours = np.random.uniform(0.8, 9.6, n_points)
exam_scores = study_hours * 7.2 + np.random.normal(0, 6.5, n_points) + 26
exam_scores = np.clip(exam_scores, 18, 99)

source = ColumnDataSource(data={"study_hours": study_hours, "exam_scores": exam_scores})

# Plot
p = figure(
    width=4800,
    height=2700,
    title="scatter-basic · bokeh · anyplot.ai",
    x_axis_label="Study Hours per Day",
    y_axis_label="Exam Score (%)",
    toolbar_location=None,
    x_range=(0, 10.5),
    y_range=(10, 104),
)

scatter_renderer = p.scatter(
    x="study_hours", y="exam_scores", source=source, size=34, color=BRAND, alpha=0.7, line_color=PAGE_BG, line_width=1.2
)

# HoverTool — Bokeh's distinctive interactive feature (HTML only; PNG stays clean)
hover = HoverTool(
    renderers=[scatter_renderer],
    tooltips=[("Study Hours", "@study_hours{0.1} hrs"), ("Exam Score", "@exam_scores{0.0}%")],
)
p.add_tools(hover)

# Typography — sized for 4800×2700 canvas
p.title.text_font_size = "42pt"
p.title.text_font_style = "bold"
p.title.text_color = INK
p.title.align = "center"

p.xaxis.axis_label_text_font_size = "32pt"
p.yaxis.axis_label_text_font_size = "32pt"
p.xaxis.axis_label_text_font_style = "normal"
p.yaxis.axis_label_text_font_style = "normal"
p.xaxis.major_label_text_font_size = "24pt"
p.yaxis.major_label_text_font_size = "24pt"
p.xaxis.axis_label_standoff = 28
p.yaxis.axis_label_standoff = 28

# Theme-adaptive chrome
p.background_fill_color = PAGE_BG
p.border_fill_color = PAGE_BG
p.outline_line_color = None

p.xaxis.axis_label_text_color = INK
p.yaxis.axis_label_text_color = INK
p.xaxis.major_label_text_color = INK_SOFT
p.yaxis.major_label_text_color = INK_SOFT
p.xaxis.axis_line_color = INK_SOFT
p.yaxis.axis_line_color = INK_SOFT
p.xaxis.major_tick_line_color = INK_SOFT
p.yaxis.major_tick_line_color = INK_SOFT
p.xaxis.minor_tick_line_color = None
p.yaxis.minor_tick_line_color = None

# Clean L-frame: keep left+bottom axis lines only (handled above via axis_line_color)
p.xgrid.grid_line_color = INK
p.ygrid.grid_line_color = INK
p.xgrid.grid_line_alpha = 0.10
p.ygrid.grid_line_alpha = 0.10
p.xgrid.grid_line_width = 2
p.ygrid.grid_line_width = 2

p.xaxis.ticker.desired_num_ticks = 10
p.yaxis.ticker.desired_num_ticks = 8

# Save
export_png(p, filename=f"plot-{THEME}.png")
output_file(f"plot-{THEME}.html", title="scatter-basic · bokeh · anyplot.ai")
save(p)

Part of Basic Scatter Plot on anyplot.ai.

Other implementations