Skip to main content

Capture and send matplotlib plots via send_file

Project description

cg-plot-capture

A custom Matplotlib backend designed for CodeGrade. This backend captures plots generated during script execution and handles them according to a configurable mode: displaying them in CodeGrade Code Editor output, saving them to disk, or both.

It uses the Matplotlib Canvas-based API and requires Matplotlib >= 3.6.

Installation

Installing the package can be done using pip:

python -m pip install cg-plot-capture

If you are using plotnine, you can install using the following command:

Optional: Install with plotnine or seaborn

To use plotnine you can install using pip:

python -m pip install cg-plot-capture[plotnine]

python -m pip install cg-plot-capture[seaborn]

Quick start

The simplest way to use the backend is to set the MPLBACKEND environment variable:

export MPLBACKEND=cg_plot_capture
python3 your_script.py

By default, plots are rendered as SVG and displayed in the CodeGrade Code Editor output. No files are saved to disk.

Configuration

Configuration is handled entirely via environment variables.

MPLBACKEND (Required)

  • Description: Used to set the backend so that anything output from Matplotlib will be correctly handled. Without this nothing will be displaying. It must be set for every script which uses it.
  • Values: cg_plot_capture

CG_PLOT_MODE (Optional)

  • Description: Determines the operation mode of the backend.
  • Values: display, save, both.
  • Default: 'display'

The backend operates in one of three modes, controlled by the CG_PLOT_MODE environment variable:

  1. display (Default): Renders plots as SVG and streams them via file descriptor 3 (fd3) to the CodeGrade Code Editor output.
  2. save: Renders plots to a specified format (see below for supported formats) and saves them to a local directory.
  3. both: Performs both displaying and saving.

CG_PLOT_FILENAME (Optional)

  • Description: Template for plot filenames. Controls both the filename and output location.
  • Default: 'plot_{i}.png'
  • Placeholders:
    • {i}: Counter (required)

Template system:

  • Use {i} as a placeholder for the sequential counter (required)
  • Include path separators to organize plots into directories
  • Specify the file extension to control the output format
  • Use Python format string syntax (e.g., {i:03d} for zero-padding)

Supported Formats:

png, pdf, svg, jpg, jpeg, eps, ps, tif, tiff, webp, pgf, raw, rgba, svgz

⚠️ Counter Resets Warning:

The {i} counter resets to 1 for each script execution. When running multiple scripts with save or both mode, files may be overwritten unless you use different paths or filenames per script.

Examples:

  • 'plot_{i}.png'plot_1.png, plot_2.png, ...
  • './results/fig_{i}.pdf'results/fig_1.pdf, results/fig_2.pdf, ...
  • 'analysis_{i:03d}.svg'analysis_001.svg, analysis_002.svg, ...

Example usage

Example 1: Basic display

Show plots in the CodeGrade UI without saving files:

export MPLBACKEND=cg_plot_capture
python3 student_script.py

Example 2: Basic display and save

This example shows a setup to display and save the plot output using a folder and format of your choice. With this you'd need to use these environment variables in every step you're running. See the next example on how to set it for all steps in your AutoTest configuration.

export MPLBACKEND=cg_plot_capture
export CG_PLOT_MODE="both"
export CG_PLOT_FILENAME="./artifacts/plot_{i}.pdf"
python3 student_script.py

Example 3: One-time configuration using cg_bash_env

Optionally, you can set the configuration one time, so you don't have to set it for every step which makes use of cg-plot-capture. By setting this in the AutoTest Setup or first thing in Test, these are available throughout your configuration.

cat >> ~/.cg_bash_env << 'EOF'
export MPLBACKEND=cg_plot_capture
export CG_PLOT_MODE="both"
export CG_PLOT_FILENAME="./all_plots/plot_{i}.png"
EOF

After this, all scripts in subsequent test steps will use these settings. You can still override CG_PLOT_FILENAME for individual scripts if needed.

Example 4: Running multiple scripts

When running multiple scripts, update the filename template for each to avoid overwrites:

# Script 1
export CG_PLOT_FILENAME="./plots/script1_{i}.png"
python3 script1.py

# Script 2
export CG_PLOT_FILENAME="./plots/script2_{i}.png"
python3 script2.py

Alternatively, use separate directories:

# Script 1
export CG_PLOT_FILENAME="./script1_plots/plot_{i}.png"
python3 script1.py

# Script 2
export CG_PLOT_FILENAME="./script2_plots/plot_{i}.png"
python3 script2.py

Runtime Method

Alternatively, after installing the package, you can invoke it within a Python script using matplotlib.use() before importing pyplot:

import matplotlib
matplotlib.use('module://cg_plot_capture')

import matplotlib.pyplot as plt

plt.plot([1, 2, 3], [4, 5, 6])
plt.show() # Triggers the capture (Stream, Save, or Both)

Limitations and notes

Thread safety: This backend is NOT thread-safe. Multiple threads calling plt.show() or show() simultaneously may produce corrupted output or duplicate filenames. This matches matplotlib's own threading limitations in which figures should only be created and shown from the main thread. Multiprocessing, on the other hand, IS safe.

Multiprocessing is safe and fully supported.

Counter Behavior

The {i} counter:

  • Starts at 1 when each script begins
  • Increments with each plt.show() call
  • Resets to 1 when a new script starts
  • Is local to each Python process (safe for multiprocessing)

Interactive Mode

This backend operates in non-interactive mode. Functions like plt.ion() have no effect. All plots are captured when plt.show() is called.

Compatibility

  • Requires Matplotlib >= 3.6
  • Works with standard Matplotlib plotting
  • Compatible with any library that uses Matplotlib, including:
    • plotnine: ggplot2-style grammar of graphics (install with [plotnine] extra)
    • seaborn: Statistical data visualization (install with [seaborn] extra)
    • pandas plotting: DataFrame.plot() methods work automatically
  • Tested with both pyplot.show() and figure manager show() methods

Troubleshooting

Plots not appearing in CodeGrade UI:

  • Verify MPLBACKEND=cg_plot_capture is set
  • Check that CG_PLOT_MODE is display or both (not save)
  • Ensure you're calling plt.show() to trigger capture

Files not being saved:

  • Verify CG_PLOT_MODE is save or both (not display)
  • Check that CG_PLOT_FILENAME includes a valid path
  • Check file permissions on the output directory

Files being overwritten:

  • See Example 4 for running multiple scripts
  • Each script resets the counter to 1
  • Use different paths or filenames per script

Format not recognized:

  • Check that your extension is in the supported formats list
  • Matplotlib determines format from the file extension in CG_PLOT_FILENAME

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cg_plot_capture-1.0.1.tar.gz (7.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cg_plot_capture-1.0.1-py3-none-any.whl (7.7 kB view details)

Uploaded Python 3

File details

Details for the file cg_plot_capture-1.0.1.tar.gz.

File metadata

  • Download URL: cg_plot_capture-1.0.1.tar.gz
  • Upload date:
  • Size: 7.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for cg_plot_capture-1.0.1.tar.gz
Algorithm Hash digest
SHA256 0b9911c9c495261f2f6a26af065660c1fb3d55755fc37ef92d09d9d0882a0a30
MD5 49d853380d43ab982a76d9e85bc8c061
BLAKE2b-256 f465d71505a3b2d6cd175a201d3cdfac3a1b44c23d3afa782241b059d486eb12

See more details on using hashes here.

Provenance

The following attestation bundles were made for cg_plot_capture-1.0.1.tar.gz:

Publisher: production_build.yml on CodeGra-de/CodeGra.de

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cg_plot_capture-1.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for cg_plot_capture-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0702b4f5cc25383d1b342048bd076cde00f79fa3061f4b2fc01f33d0b20693f9
MD5 449f87d459eb93aa4a3c6cb29c0012ce
BLAKE2b-256 f2fe0eb80605ab9062ee2cb6edee0e6f37e294f6adb23e61239598b5a3d85f58

See more details on using hashes here.

Provenance

The following attestation bundles were made for cg_plot_capture-1.0.1-py3-none-any.whl:

Publisher: production_build.yml on CodeGra-de/CodeGra.de

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page