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:
display(Default): Renders plots as SVG and streams them via file descriptor 3 (fd3) to the CodeGrade Code Editor output.save: Renders plots to a specified format (see below for supported formats) and saves them to a local directory.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
- plotnine: ggplot2-style grammar of graphics (install with
- Tested with both
pyplot.show()and figure managershow()methods
Troubleshooting
Plots not appearing in CodeGrade UI:
- Verify
MPLBACKEND=cg_plot_captureis set - Check that
CG_PLOT_MODEisdisplayorboth(notsave) - Ensure you're calling
plt.show()to trigger capture
Files not being saved:
- Verify
CG_PLOT_MODEissaveorboth(notdisplay) - Check that
CG_PLOT_FILENAMEincludes 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0b9911c9c495261f2f6a26af065660c1fb3d55755fc37ef92d09d9d0882a0a30
|
|
| MD5 |
49d853380d43ab982a76d9e85bc8c061
|
|
| BLAKE2b-256 |
f465d71505a3b2d6cd175a201d3cdfac3a1b44c23d3afa782241b059d486eb12
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cg_plot_capture-1.0.1.tar.gz -
Subject digest:
0b9911c9c495261f2f6a26af065660c1fb3d55755fc37ef92d09d9d0882a0a30 - Sigstore transparency entry: 834566505
- Sigstore integration time:
-
Permalink:
CodeGra-de/CodeGra.de@5ba70728af938b7dab06021ddd2a74895e0f9d33 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/CodeGra-de
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
production_build.yml@5ba70728af938b7dab06021ddd2a74895e0f9d33 -
Trigger Event:
push
-
Statement type:
File details
Details for the file cg_plot_capture-1.0.1-py3-none-any.whl.
File metadata
- Download URL: cg_plot_capture-1.0.1-py3-none-any.whl
- Upload date:
- Size: 7.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0702b4f5cc25383d1b342048bd076cde00f79fa3061f4b2fc01f33d0b20693f9
|
|
| MD5 |
449f87d459eb93aa4a3c6cb29c0012ce
|
|
| BLAKE2b-256 |
f2fe0eb80605ab9062ee2cb6edee0e6f37e294f6adb23e61239598b5a3d85f58
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cg_plot_capture-1.0.1-py3-none-any.whl -
Subject digest:
0702b4f5cc25383d1b342048bd076cde00f79fa3061f4b2fc01f33d0b20693f9 - Sigstore transparency entry: 834566648
- Sigstore integration time:
-
Permalink:
CodeGra-de/CodeGra.de@5ba70728af938b7dab06021ddd2a74895e0f9d33 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/CodeGra-de
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
production_build.yml@5ba70728af938b7dab06021ddd2a74895e0f9d33 -
Trigger Event:
push
-
Statement type: