Of course. This is an excellent question because combining Mayavi for 3D visualization with PDFs for report generation is a very powerful workflow in science and engineering.

Here’s a comprehensive guide covering different methods, from the most common to more advanced techniques.
Summary of Methods
| Method | Best For | Pros | Cons |
|---|---|---|---|
| Matplotlib Backend | Quick plots, compatibility with Matplotlib | Easy to use, familiar API | Mayavi features might be limited |
| Save as Image | High-quality static figures | Full Mayavi power, simple | Not vector-based (can pixelate when scaled) |
| E-Links (Vector Graphics) | High-quality, scalable figures in PDFs | Vector format, looks perfect at any size | More complex setup, requires svg2pdf |
| Interactive Embedding | Dynamic reports (Jupyter, Qt) | Interactive 3D plots in the PDF | Requires PDF reader with JavaScript support |
Method 1: Using the Matplotlib Backend (Easiest)
Mayavi can be used as a backend for Matplotlib. This is the simplest way to get a Mayavi plot into a Matplotlib figure, which can then be saved directly to a PDF.
How it works: You configure Matplotlib to use mayavi.mlab as its plotting engine and then use standard Matplotlib commands.
Example Code:

import numpy as np
from mayavi import mlab
import matplotlib.pyplot as plt
# 1. Configure Matplotlib to use the Mayavi backend
mlab.options.backend = 'matplotlib'
# 2. Create a figure using Matplotlib
fig = plt.figure(figsize=(8, 6))
# 3. Plot using Mayavi's mlab functions
# The plot will be drawn on the Matplotlib figure
x, y = np.mgrid[-3:3:100j, -3:3:100j]
z = np.sin(x**2 + y**2) / (x**2 + y**2)
# The 'figure' keyword tells mlab which Matplotlib figure to use
mlab.surf(z, warp_scale='auto', figure=fig)
mlab.xlabel('X axis')
mlab.ylabel('Y axis')
mlab.zlabel('Z axis')"Mayavi Plot in Matplotlib Figure")
# 4. Save the Matplotlib figure to a PDF
# This will save the Mayavi plot as a raster image within the PDF
plt.savefig('mayavi_matplotlib.pdf', dpi=300, bbox_inches='tight')
print("Saved mayavi_matplotlib.pdf")
# To display the plot (optional)
# plt.show()
Pros:
- Very straightforward if you already know Matplotlib.
- A single
savefigcall is all you need.
Cons:
- The plot is saved as a raster (image) inside the PDF, not as a vector graphic. This means it can appear pixelated if you zoom in or print at a high resolution.
- You lose some of Mayavi's advanced interactive features when embedded this way.
Method 2: Save as Image and Embed (Common & Practical)
This is a very common and effective workflow. You generate the plot with Mayavi, save it as a high-resolution image (PNG, TIFF, etc.), and then embed that image into a PDF using a library like reportlab or PyPDF2.
Example Code:
import numpy as np
from mayavi import mlab
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Image, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
# --- Step 1: Generate and save the Mayavi plot as an image ---
print("Generating Mayavi plot...")
x, y = np.mgrid[-3:3:100j, -3:3:100j]
z = np.sin(x**2 + y**2) / (x**2 + y**2)
# Create a new figure window
fig = mlab.figure(size=(800, 600))
mlab.surf(z, warp_scale='auto')
mlab.xlabel('X axis')
mlab.ylabel('Y axis')
mlab.zlabel('Z axis')"Mayavi Plot as Embedded Image")
# Save the figure to a high-quality image file
# Use a high DPI for better quality in the PDF
mlab.savefig('mayavi_plot.png', size=(800, 600))
print("Saved mayavi_plot.png")
# Close the Mayavi figure to free resources
mlab.close(fig)
# --- Step 2: Create a PDF and embed the image ---
print("Creating PDF...")
doc = SimpleDocTemplate("report_with_image.pdf", pagesize=letter)
styles = getSampleStyleSheet()
Story = []
# Add a title paragraph= Paragraph("<b>My Scientific Report</b>", styles['h1'])
Story.append(p_title)
# Add some text
p_text = Paragraph("This report contains a 3D surface plot generated with Mayavi. "
"The plot was saved as a PNG and embedded into this PDF.", styles['Normal'])
Story.append(p_text)
# Add the image
# You can specify width/height to scale it
try:
im = Image("mayavi_plot.png", width=500, height=375)
Story.append(im)
except Exception as e:
print(f"Could not embed image: {e}")
# Build the PDF
doc.build(Story)
print("Saved report_with_image.pdf")
Pros:
- Simple to implement.
- You get the full power and quality of Mayavi's rendering engine.
- You have full control over the final PDF layout using libraries like
reportlab.
Cons:
- The plot is still a raster image, not a scalable vector graphic.
Method 3: Save as E-Links (Vector Graphics - Highest Quality)
This is the most advanced method and produces the highest-quality results. It involves saving the Mayavi plot as a vector graphic format (like SVG) and then converting it to a format that can be embedded as a vector in a PDF (like PDF or EPS via inkscape or svg2pdf).
How it works:
- Save the Mayavi scene as an SVG file.
- Use a command-line tool (like
inkscape) or a Python library to convert the SVG to a PDF. - Embed this new vector PDF into your final report PDF.
Example Code:
import numpy as np
from mayavi import mlab
import subprocess
import os
# --- Step 1: Generate and save the Mayavi plot as an SVG ---
print("Generating Mayavi plot as SVG...")
x, y = np.mgrid[-3:3:100j, -3:3:100j]
z = np.sin(x**2 + y**2) / (x**2 + y**2)
mlab.surf(z, warp_scale='auto')
mlab.xlabel('X axis')
mlab.ylabel('Y axis')
mlab.zlabel('Z axis')"Mayavi Plot as Vector Graphic")
# Save as SVG
mlab.savefig('mayavi_plot.svg')
print("Saved mayavi_plot.svg")
# Close the Mayavi figure
mlab.close(fig)
# --- Step 2: Convert SVG to PDF using Inkscape ---
# Make sure Inkscape is installed and in your system's PATH.
# On Ubuntu/Debian: sudo apt-get install inkscape
# On macOS (with Homebrew): brew install --cask inkscape
# On Windows: Download from Inkscape.org and add to PATH.
svg_file = 'mayavi_plot.svg'
pdf_file_vector = 'mayavi_plot_vector.pdf'
try:
# Use Inkscape to convert SVG to PDF
# The '--export-pdf' flag specifies the output format
subprocess.run(['inkscape', '--export-pdf=' + pdf_file_vector, svg_file], check=True)
print(f"Converted {svg_file} to {pdf_file_vector} using Inkscape.")
except (subprocess.CalledProcessError, FileNotFoundError):
print("Inkscape not found. Skipping SVG to PDF conversion.")
print("Please install Inkscape to use this method.")
# --- Step 3: Embed the vector PDF into a report PDF (using ReportLab) ---
# This is similar to Method 2, but we embed the vector PDF instead of a PNG.
if os.path.exists(pdf_file_vector):
print("Creating final report PDF with embedded vector graphic...")
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, KeepInFrame
from reportlab.lib.styles import getSampleStyleSheet
doc = SimpleDocTemplate("report_with_vector.pdf", pagesize=letter)
styles = getSampleStyleSheet()
Story = []
p_title = Paragraph("<b>High-Quality Vector Report</b>", styles['h1'])
Story.append(p_title)
p_text = Paragraph("This report contains a 3D plot embedded as a **vector graphic**. "
"It can be scaled to any size without losing quality.", styles['Normal'])
Story.append(p_text)
# Use KeepInFrame to handle the PDF page size correctly
vector_pdf = Image(pdf_file_vector, width=400, height=300, kind='vector')
Story.append(KeepInFrame(400, 300, [vector_pdf]))
doc.build(Story)
print("Saved report_with_vector.pdf")
Pros:
- Scalable Vector Graphics: The plot will be perfectly sharp at any zoom level or print size.
- Highest possible quality for publications.
Cons:
- Complex setup: Requires installing Inkscape (or similar tools like
svg2pdf). - Mayavi's SVG export is not perfect and might not support all features or look identical to the on-screen render.
Method 4: Interactive Embedding in Jupyter
If your "PDF" is actually a Jupyter Notebook exported to PDF, you can embed interactive Mayavi plots. When the notebook is viewed in a browser (like JupyterLab), the plot is fully interactive. When exported to PDF, it becomes a static image, but the interactivity is preserved in the .ipynb file.
Example in a Jupyter Notebook Cell:
# This code must be run in a Jupyter Notebook or similar environment import numpy as np from mayavi import mlab x, y = np.mgrid[-3:3:100j, -3:3:100j] z = np.sin(x**2 + y**2) / (x**2 + y**2) # mlab in a notebook automatically creates an interactive widget mlab.surf(z, warp_scale='auto') mlab.show() # Not always needed in notebooks, but good practice
How to get it into a PDF:
- Run the code in your Jupyter Notebook.
- Use the "Print" function in your browser (Ctrl+P / Cmd+P) and save as "PDF".
- Alternatively, use
nbconvertto convert the.ipynbfile to a PDF:jupyter nbconvert --to pdf my_notebook.ipynb.
Pros:
- Provides interactive exploration within the notebook environment.
- Excellent for sharing results with colleagues for them to explore.
Cons:
- The interactivity is lost when exported to PDF. It becomes a static screenshot.
- The final PDF is not a self-contained vector graphic.
Recommendation
- For quick reports and presentations, use Method 1 (Matplotlib Backend) or Method 2 (Image Embed). They are the most practical.
- For scientific publications or high-quality reports where image clarity is paramount, use Method 3 (E-Links / Vector Graphics). The extra effort is worth it for the final quality.
- For interactive exploration and sharing workflows, use Method 4 (Jupyter Notebook).
