Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Examples/PlotTypes/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Plot Types
----------
A collection of short examples showing different plot types.
74 changes: 74 additions & 0 deletions Examples/PlotTypes/plot_3d.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""
3D Plotting
===========

Demonstrate the three 3-D geometry types supported by
:meth:`~anyplotlib.Axes.plot_surface`,
:meth:`~anyplotlib.Axes.scatter3d`, and
:meth:`~anyplotlib.Axes.plot3d`.
Drag to rotate, scroll to zoom, press **R** to reset the view.
"""
import numpy as np
import anyplotlib as vw

# ── Surface ───────────────────────────────────────────────────────────────────
x = np.linspace(-3, 3, 60)
y = np.linspace(-3, 3, 60)
XX, YY = np.meshgrid(x, y)
ZZ = np.sin(np.sqrt(XX ** 2 + YY ** 2))

fig, ax = vw.subplots(1, 1, figsize=(520, 480))
surf = ax.plot_surface(XX, YY, ZZ,
colormap="viridis",
x_label="x", y_label="y", z_label="sin(r)")

fig

# %%
# Scatter plot
# ------------

rng = np.random.default_rng(1)
n = 300
theta = rng.uniform(0, 2 * np.pi, n)
phi = rng.uniform(0, np.pi, n)
r = rng.uniform(0.6, 1.0, n)
xs = r * np.sin(phi) * np.cos(theta)
ys = r * np.sin(phi) * np.sin(theta)
zs = r * np.cos(phi)

fig2, ax2 = vw.subplots(1, 1, figsize=(480, 480))
sc = ax2.scatter3d(xs, ys, zs,
color="#4fc3f7", point_size=3,
x_label="x", y_label="y", z_label="z")

fig2

# %%
# 3-D line — parametric helix
# ----------------------------

t = np.linspace(0, 4 * np.pi, 300)
hx = np.cos(t)
hy = np.sin(t)
hz = t / (4 * np.pi)

fig3, ax3 = vw.subplots(1, 1, figsize=(480, 480))
ln = ax3.plot3d(hx, hy, hz,
color="#ff7043", linewidth=2,
x_label="cos t", y_label="sin t", z_label="t")

fig3

# %%
# Update the surface data live
# ----------------------------
# Call :meth:`~anyplotlib.Plot3D.set_data` to replace the geometry
# without recreating the panel.

ZZ2 = np.cos(np.sqrt(XX ** 2 + YY ** 2))
surf.set_data(XX, YY, ZZ2)
surf.set_colormap("plasma")
surf.set_view(azimuth=30, elevation=40)

fig
151 changes: 151 additions & 0 deletions Examples/PlotTypes/plot_bar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
"""
Bar Chart
=========

Demonstrate :meth:`~anyplotlib.Axes.bar` with:

* **Matplotlib-aligned API** — ``ax.bar(x, height, width, bottom, …)``
* Vertical and horizontal orientations, per-bar colours, category labels
* **Grouped bars** — pass a 2-D *height* array ``(N, G)``
* **Log-scale value axis** — ``log_scale=True``
* Live data updates via :meth:`~anyplotlib.PlotBar.set_data`
"""
import numpy as np
import anyplotlib as vw

rng = np.random.default_rng(7)

# ── 1. Vertical bar chart — monthly sales ────────────────────────────────────
# The first positional argument is now *x* (positions or labels), matching
# ``matplotlib.pyplot.bar(x, height, width=0.8, bottom=0.0, ...)``.
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
sales = np.array([42, 55, 48, 63, 71, 68, 74, 81, 66, 59, 52, 78],
dtype=float)

fig1, ax1 = vw.subplots(1, 1, figsize=(640, 340))
bar1 = ax1.bar(
months, # x — category strings become x_labels automatically
sales, # height
width=0.6,
color="#4fc3f7",
show_values=True,
units="Month",
y_units="Units sold",
)
fig1

# %%
# Horizontal bar chart — ranked items
# -------------------------------------
# Set ``orient="h"`` for a horizontal layout. Pass a list of CSS colours
# to ``colors`` to give each bar its own colour.

categories = ["NumPy", "SciPy", "Matplotlib", "Pandas", "Scikit-learn",
"PyTorch", "TensorFlow", "JAX", "Polars", "Dask"]
scores = np.array([95, 88, 91, 87, 83, 79, 76, 72, 68, 65], dtype=float)

palette = [
"#ef5350", "#ec407a", "#ab47bc", "#7e57c2", "#42a5f5",
"#26c6da", "#26a69a", "#66bb6a", "#d4e157", "#ffa726",
]

fig2, ax2 = vw.subplots(1, 1, figsize=(540, 400))
bar2 = ax2.bar(
categories,
scores,
orient="h",
colors=palette,
width=0.65,
show_values=True,
y_units="Popularity score",
)
fig2

# %%
# Grouped bar chart — quarterly comparison
# -----------------------------------------
# Pass a 2-D *height* array of shape ``(N, G)`` to draw *G* bars side by
# side for each category. Provide ``group_labels`` to show a legend and
# ``group_colors`` to customise each group's colour.

quarters = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
q_data = np.array([
[42, 58, 51], # Jan — Q1, Q2, Q3
[55, 61, 59], # Feb
[48, 70, 65], # Mar
[63, 75, 71], # Apr
[71, 69, 80], # May
[68, 83, 77], # Jun
], dtype=float) # shape (6, 3) → 6 categories, 3 groups

fig3, ax3 = vw.subplots(1, 1, figsize=(680, 340))
bar3 = ax3.bar(
quarters,
q_data,
width=0.8,
group_labels=["Q1", "Q2", "Q3"],
group_colors=["#4fc3f7", "#ff7043", "#66bb6a"],
show_values=False,
y_units="Sales",
)
fig3

# %%
# Log-scale value axis
# ---------------------
# Set ``log_scale=True`` for a logarithmic value axis. Non-positive values
# are clamped to ``1e-10`` — no error is raised. Tick marks are placed at
# each decade (10⁰, 10¹, 10², …) with faint minor gridlines at 2×, 3×, 5×
# multiples.

log_labels = ["A", "B", "C", "D", "E"]
log_vals = np.array([1, 10, 100, 1_000, 10_000], dtype=float)

fig4, ax4 = vw.subplots(1, 1, figsize=(500, 340))
bar4 = ax4.bar(
log_labels,
log_vals,
log_scale=True,
color="#ab47bc",
show_values=True,
y_units="Count (log scale)",
)
fig4

# %%
# Side-by-side comparison — update data live
# -------------------------------------------
# Place two :class:`~anyplotlib.PlotBar` panels in one figure.
# Call :meth:`~anyplotlib.PlotBar.set_data` to swap in Q2 data —
# the value-axis range recalculates automatically.

q1 = np.array([42, 55, 48, 63, 71, 68, 74, 81, 66, 59, 52, 78], dtype=float)
q2 = np.array([58, 61, 70, 75, 69, 83, 90, 88, 77, 64, 71, 95], dtype=float)
all_months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]

fig5, (ax_left, ax_right) = vw.subplots(1, 2, figsize=(820, 320))
bar_left = ax_left.bar(
all_months, q1, width=0.6,
color="#4fc3f7", show_values=False, y_units="Q1 sales",
)
bar_right = ax_right.bar(
all_months, q1, width=0.6,
color="#ff7043", show_values=False, y_units="Q2 sales",
)
bar_right.set_data(q2) # swap in Q2 — axis range recalculates automatically

fig5

# %%
# Mutate colours, annotations, and scale at runtime
# --------------------------------------------------
# :meth:`~anyplotlib.PlotBar.set_color` repaints all bars,
# :meth:`~anyplotlib.PlotBar.set_show_values` toggles labels,
# :meth:`~anyplotlib.PlotBar.set_log_scale` switches the
# value-axis between linear and logarithmic.

bar1.set_color("#ff7043")
bar1.set_show_values(False)
fig1
130 changes: 130 additions & 0 deletions Examples/PlotTypes/plot_image2d.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"""
2D Image with Histogram
=======================

Display a 2-D image with physical axes, a colourmap, and an interactive
histogram below — all wired together with draggable threshold widgets.

Layout
------
A :class:`~anyplotlib.GridSpec` with two rows puts the image
on top and a bar-chart histogram below. Two
:class:`~anyplotlib.widgets.VLineWidget` handles on the histogram mark the
``display_min`` / ``display_max`` thresholds; dragging them updates the
image colour scale in real time.

Key bindings on the image panel: **R** reset view · **C** toggle colorbar ·
**L** / **S** cycle colour-scale modes.

New ``imshow`` parameters
-------------------------
``cmap``
Colormap name passed directly to :meth:`~anyplotlib.Axes.imshow`
(e.g. ``"viridis"``, ``"inferno"``). Defaults to ``"gray"``.
``vmin`` / ``vmax``
Colormap clipping limits in data units. Values outside the range are
clamped to the colormap endpoints. Defaults to the data min/max.
``origin``
``"upper"`` (default) places row 0 at the top (image convention).
``"lower"`` places row 0 at the bottom (scientific / matrix convention)
and automatically reverses the y-axis so tick values increase upward.
"""
import numpy as np
import anyplotlib as apl


rng = np.random.default_rng(1)

# ── Synthetic diffraction pattern ─────────────────────────────────────────────
N = 256
x = np.linspace(-5, 5, N) # physical axis in nm
y = np.linspace(-5, 5, N)
XX, YY = np.meshgrid(x, y)
R = np.sqrt(XX ** 2 + YY ** 2)


def _ring(r, r0, width, amp):
return amp * np.exp(-0.5 * ((r - r0) / width) ** 2)


image = (
_ring(R, 0.0, 0.30, 1.00) # central spot
+ _ring(R, 2.1, 0.15, 0.55) # first-order ring
+ _ring(R, 4.2, 0.15, 0.25) # second-order ring
+ rng.normal(scale=0.04, size=(N, N))
)

# ── Layout: image (top, 3×) + histogram bar chart (bottom, 1×) ────────────────
gs = apl.GridSpec(2, 1, height_ratios=[3, 1])
fig = apl.Figure(figsize=(500, 640))
ax_img = fig.add_subplot(gs[0, 0])
ax_hist = fig.add_subplot(gs[1, 0])

# ── Image panel — cmap, vmin, vmax supplied directly to imshow ────────────────
vmin_init = float(image.min())
vmax_init = float(image.max())

# Pass cmap, vmin, and vmax directly — no separate set_colormap / set_clim call
# needed for the initial display.
v = ax_img.imshow(image, axes=[x, y], units="nm",
cmap="inferno", vmin=vmin_init, vmax=vmax_init)

# First-order spot markers in the same physical coordinates used by imshow
spot_nm = np.array([[ 2.1, 0.0], [-2.1, 0.0],
[ 0.0, 2.1], [ 0.0, -2.1]])
v.add_circles(spot_nm, name="spots", radius=7,
edgecolors="#00e5ff", facecolors="#00e5ff22",
labels=["g1", "g1_bar", "g2", "g2_bar"])

# ── Histogram bar chart ────────────────────────────────────────────────────────
counts, edges = np.histogram(image.ravel(), bins=64)
bin_centers = 0.5 * (edges[:-1] + edges[1:])

h = ax_hist.bar(counts, x_centers=bin_centers, orient="v",
color="#4fc3f7", y_units="count")

# ── Draggable threshold handles on the histogram ──────────────────────────────
wlo = h.add_vline_widget(vmin_init, color="#ff6e40") # low-threshold handle
whi = h.add_vline_widget(vmax_init, color="#ffffff") # high-threshold handle


@wlo.on_release
def _apply_low(event):
"""Update image display_min when the low handle is released."""
v.set_clim(vmin=event.x)


@whi.on_release
def _apply_high(event):
"""Update image display_max when the high handle is released."""
v.set_clim(vmax=event.x)


fig # Interactive

# %%
# Adjust colour map and display range
# ------------------------------------
# :meth:`~anyplotlib.Plot2D.set_colormap` switches the palette;
# :meth:`~anyplotlib.Plot2D.set_clim` adjusts the display range.
# Both are equivalent to passing ``cmap`` / ``vmin`` / ``vmax`` at construction.

v.set_colormap("viridis")
v.set_clim(vmin=0.0, vmax=0.8)

fig

# %%
# origin='lower' — scientific / matrix convention
# ------------------------------------------------
# Passing ``origin='lower'`` places row 0 of the data at the *bottom* of the
# image, matching the matplotlib / scientific convention. The y-axis is
# automatically reversed so tick values still increase upward.

mat = np.arange(64, dtype=float).reshape(8, 8) # row 0 = small values

fig2, ax2 = apl.subplots()
v2 = ax2.imshow(mat, cmap="plasma", origin="lower")

fig2 # Interactive

Loading
Loading