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.2.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.2-py3-none-any.whl (7.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: cg_plot_capture-1.0.2.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.2.tar.gz
Algorithm Hash digest
SHA256 c6e658c4262b35a0c260e5eb83fc1799a84d01f3d3b63577c50302b93a76da1d
MD5 59df5e15bc44667aeee3106c98f2ce40
BLAKE2b-256 e922a5278e2b279e25467806affadf627c4118c3f21ef6ce1e2c4fc6593d9e58

See more details on using hashes here.

Provenance

The following attestation bundles were made for cg_plot_capture-1.0.2.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.2-py3-none-any.whl.

File metadata

File hashes

Hashes for cg_plot_capture-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 d5e3e015c607a43c6a9409faa5bf9b3739276739fa8d3d020d45dc915a3c4125
MD5 3e850adee4cc1ef39ac6115d3db8192e
BLAKE2b-256 ed676d78da5b1676b153064b4414c92850f6a445d80bbbae8fa39b749200d6f2

See more details on using hashes here.

Provenance

The following attestation bundles were made for cg_plot_capture-1.0.2-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