Skip to main content

climate-canvas

Python package and command line interface (CLI) for plotting climate impact study response surfaces and other climate change scenario visualizations.

plot

Example: The figure above is created by running the uv run climate-canvas response examples\complex_surface.csv --interp climate-canvas CLI command on the complex_surface.csv data distributed with the climate-canvas program.

Installation Instructions

System Requirements

climate-canvas requires python 3.12+. It aims to be multi-platform and has been run on Windows 11 and MacOS 14 and 15.

Clone or Fork climate-canvas from GitHub

The climate-canvas source code can be found here: https://github.com/JohnRushKucharski/climate-canvas is available under the GNU Version 3 General Public License.

It can be cloned or forked by following the normal cloning or forking instructions, which are available here: https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository and here: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo.

Installation with uv

climate-canvas is developed with uv, which can be used to simplify the installation process.

To install uv, follow the instructions here: https://docs.astral.sh/uv/getting-started/installation/.

Once uv is installed, use your favorite shell to go to the location of the local climate-canvas repository, e.g.

cd <PATH_TO_LOCAL>\climate-canvas

Next run:

uv sync --group test

This will create a python virtual environment (.venv) containing all the required climate-canvas dependencies, without affecting your system's global python environment.

The climate-canvas program should be ready for use as either a python package or command line utility. To test the command line interface (CLI) type the following command into your shell:

uv run climate-canvas --help

This should return help instructions for the climate-canvas CLI.

Basic Usage

The climate-canvas program can be extended as a python package or run through a command line interface (CLI).

The current version (0.1.0) only supports 2D climate response surface style plots. These are two-dimensional contour plots that show the impact of two variables plotted on the x and y axes on a response (i.e. z axis) variable whose values are plotted using contour lines and a colorbar. An example is shown below.

plot

Command Line Interface

The example above is created response command. From a shell run:

uv run climate-canvas response --help

To view help for the response command, i.e.:

plot

As the response help document describes the response command requires that a path to a .csv file containing plotting data be specified. Two example, data files are provided in the repository's examples/ directory. The following command, using on of these example files, reproduces the figure above:

uv run climate-canvas response examples\scenario_data.csv

The --interp flag can be used to bi-linearly interpolate between z-axis values. For example, running the following command (using the same data from the figure above) with the --interp flag produces the figure below:

uv run climate-canvas response examples\scenario_data.csv --interp

plot

The --fillin flag extends --interp to fill in grid cells that bilinear interpolation leaves blank because one or more of the cell's four corners is missing. It has no effect unless --interp is also set. For example:

uv run climate-canvas response examples\great_lakes\kingston_shoal_low_water_grid.csv --interp --fillin

The math behind --interp and --fillin

This section works through the exact arithmetic behind --interp (bilinear interpolation) and --fillin (Delaunay-linear fallback for missing data), using the smallest possible data sets — 2x2 grids with z-values between 0 and 1 — so every number can be checked by hand.

1. Bilinear interpolation on a complete grid — examples/simple.csv

This file defines a full 2x2 grid (no missing values):

z x=0 x=1
y=0 0 1
y=1 1 1

Bilinear interpolation first interpolates along x at each of the two known y-rows, then interpolates the result along y. For a query point (x, y), with px = x and py = y (since the grid spans exactly 0 to 1 here, the interpolation weight equals the coordinate):

z_x,y0 = z00*(1-px) + z01*px      # interpolate along x at y=0
z_x,y1 = z10*(1-px) + z11*px      # interpolate along x at y=1
z_x,y  = z_x,y0*(1-py) + z_x,y1*py  # interpolate the two results along y

At the midpoint (0.5, 0.5):

z_x,y0 = 0*(1-0.5) + 1*0.5 = 0.5
z_x,y1 = 1*(1-0.5) + 1*0.5 = 1.0
z_x,y  = 0.5*(1-0.5) + 1.0*0.5 = 0.75

Running uv run climate-canvas response examples\simple.csv --interp reproduces this: every point in the unit square is filled with the plane implied by these four corners (no blank cells, since the one cell in this grid has all four corners known — --fillin has no effect here). Without --interp, only the 4 known grid points are plotted (as 4 flat-colored quarter-cells); no interpolation is performed between them.

2. A missing corner — examples/simple_3points.csv

This file is identical, except the top-right corner is missing:

z x=0 x=1
y=0 0 1
y=1 1 NaN

There is only one cell in this grid, and one of its four corners is unknown, so:

  • Without --interp: the 3 known points are plotted as flat-colored quarter-cells; the (1, 1) corner's quarter-cell is blank. No interpolation happens.

  • With --interp only (--interp, no --fillin): bilinear interpolation strictly requires all four corners (see interpolate_2d in data_utilities.py) — with one corner missing, the entire cell returns NaN. The plot is blank everywhere except the 3 exact known grid points (which are always re-inserted into the resampled grid). See examples/simple_3points_interp.png.

  • With --interp --fillin: the missing cell falls back to delaunay_fill(), which triangulates only the 3 known points — (0, 0, z=0), (1, 0, z=1), (0, 1, z=1) — into a single triangle and fits the plane z = a + bx + cy through them:

    (0,0): a           = 0   ->  a = 0
    (1,0): a + b       = 1   ->  b = 1
    (0,1): a     + c   = 1   ->  c = 1
    
    z = x + y
    

    This plane is only used inside the triangle's convex hull, i.e. where x + y <= 1:

    • (0.25, 0.25) -> z = 0.25 + 0.25 = 0.5
    • (0.5, 0.5) (on the hull's edge, between the two known z=1 points) -> z = 0.5 + 0.5 = 1.0 (matches both known neighbors, as expected on their connecting edge)
    • (0.75, 0.75) -> x + y = 1.5 > 1, outside the hull, so this stays NaN (blank) — the same as the exact missing corner (1, 1) itself, which has x + y = 2 > 1.

    So --fillin fills the lower-left triangle (x + y <= 1, nearest the 3 known points) with the plane above, while the upper-right triangle (nearest the missing corner) stays blank. See examples/simple_3points_interp_fillin.png next to examples/simple_3points_interp.png for the before/after.

Because the bilinear surface (example 1) and the Delaunay plane (example 2) are fit independently, a visible seam can appear where a --fillin triangle borders a complete bilinear cell (the two surfaces aren't generally coplanar there). See docs/adr/0002-delaunay-linear-fillin-for-missing-grid-points.md for the full rationale and this trade-off.

As the help documentation shows titles for the figure, x, y, and z axes can be added as optional arguments.

The --threshold option sets the z-value that becomes the colormap's center (yellow) color, splitting the color range asymmetrically around it (and adjusting the contour levels to match). If omitted, it defaults to the midpoint of the data's z-value range. Use --color-map to change the matplotlib colormap (defaults to RdBu), and --color-map-ticks to set explicit colorbar tick values. If --threshold is given but --color-map-ticks is not, the colorbar ticks default to the same contour levels used for the black contour lines, since matplotlib's default tick locator is linear in data value and can otherwise cluster ticks into one visually-compressed half of the colorbar when threshold is far from the z-range's midpoint. E.g.:

uv run climate-canvas response examples\scenario_data.csv --threshold 0.2 --color-map RdYlBu

Multiple Response Surfaces (response-surfaces-grid Command)

The response-surfaces-grid command plots several response surfaces as subplots of one figure, arranged in a grid. Every subplot is rendered through the exact same pathway as the response command, so a subplot always matches what a standalone response call would draw for the same data/options.

Unlike response, which takes a .csv file, response-surfaces-grid takes a single Excel (.xlsx) workbook containing:

  • a main_config sheet: figure-wide options (key in column A, value in column B) -- suptitle, sharex, sharey, shared_colorbar, color_map, threshold, color_map_ticks, output_directory.
  • a main_layout sheet: column numbers across row 1 (B1:K1), row numbers down column A (A2:A11, max 10x10), and a subplot id in each interior cell. The same id repeated in adjacent cells makes that subplot span that rectangular block of grid cells.
  • one <id>_config sheet per subplot: the same options as response (interpolate, fillin, xlabel, ylabel, zlabel, title, threshold, color_map, color_map_ticks), same key-in-column-A/value-in-column-B shape as main_config.
  • one <id>_grid sheet per subplot: that subplot's x/y/z data, in the same grid shape as the CSV format response reads.

shared_colorbar (default false) controls whether every subplot uses its own color_map/threshold/color_map_ticks and its own colorbar (the default, matching a standalone response call exactly for each subplot), or all subplots share one color scale (main_config's own color_map/threshold/color_map_ticks) and one colorbar for the whole figure. output_directory, if set, saves the figure as a PNG named after the workbook's filename in that directory.

A runnable, pre-filled template workbook is provided at examples/response_surfaces_grid_template.xlsx (built by examples/build_response_surfaces_grid_template.py). Run it with:

uv run climate-canvas response-surfaces-grid examples\response_surfaces_grid_template.xlsx

plot

See docs/adr/0003-excel-driven-response-surfaces-grid-command.md and CONTEXT.md for the full schema/rationale.

Python API

plot_response_surface (in climate_canvas.plots_utilities) can also be called directly as a library function, e.g. from another package's CLI. It accepts several optional parameters not exposed by the response CLI command:

  • save_path (Path | None, default None): when provided, saves the figure to this path.
  • show (bool, default True): when False, skips the interactive plt.show() window (useful for batch/headless plotting, e.g. saving one plot per component in a loop). The figure is always closed after the call to avoid leaking matplotlib figures.
  • threshold (float | None, default None): z-value that becomes the colormap's center color. Defaults to the midpoint of the z-value range if None or outside that range.
  • color_map (str, default 'RdBu'): matplotlib colormap name.
  • color_map_ticks (list[float] | None, default None): explicit colorbar tick values. If None and threshold is given, defaults to the contour levels (5 below/above threshold plus threshold itself) instead of matplotlib's automatic tick locator.

The third element of the labels tuple (z label) is rendered as the colorbar's label, in addition to labels[0]/labels[1] being used as the x/y axis labels.

from climate_canvas.plots_utilities import plot_response_surface

plot_response_surface(xs, ys, zs, labels=('Precip Delta (%)', 'Temp Delta (C)', 'portion'),
                      save_path='surface.png', show=False, threshold=0.2)

plot_response_surfaces_grid (also in climate_canvas.plots_utilities) reads a workbook path and renders the multi-subplot figure described above:

from climate_canvas.plots_utilities import plot_response_surfaces_grid

plot_response_surfaces_grid('examples/response_surfaces_grid_template.xlsx', show=False)

Metadata

Release files for climate-canvas 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for climate-canvas 0.1.0
File Size Uploaded
climate_canvas-0.1.0.tar.gz 1.0 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for climate-canvas 0.1.0
File Interpreter ABI Platform
climate_canvas-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.1 MB

Release files / climate_canvas-0.1.0.tar.gz

Download URL climate_canvas-0.1.0.tar.gz
Size 1.0 MB
Tags Source
SHA-256 checksum
How to use checksums
87f03f65934a1d9de5ed007422d52e78c173e7c03831a17724815e29ec7b09d3
BLAKE2b-256 checksum
How to use checksums
3392563560b2b02e9e2701cc38ab9d8ffb66ad0b4febcd216917ac33fa0e2c50
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 7, 2026.

Transparency log

Release files / climate_canvas-0.1.0-py3-none-any.whl

Download URL climate_canvas-0.1.0-py3-none-any.whl
Size 34.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
179061af7ba6c0599796efd5b5dfe7ccdaccb38a5b548f7bcd6eb6c5c4e8b811
BLAKE2b-256 checksum
How to use checksums
e3b8845fc12e09d9ac5fc574ac5b3ca6d0ac104d1031abf45c199859808e61bf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page