0
# Backends and Export
1
2
Output format control and GUI integration. Matplotlib provides multiple backend implementations for different platforms, display systems, and file formats, enabling flexible deployment across environments.
3
4
## Capabilities
5
6
### Backend Management
7
8
Functions for selecting and controlling matplotlib backends.
9
10
```python { .api }
11
import matplotlib
12
import matplotlib.pyplot as plt
13
14
# Core matplotlib backend functions
15
def use(backend, *, force=True) -> None:
16
"""Select the backend used for rendering and GUI integration."""
17
18
def get_backend() -> str:
19
"""Return the name of the current backend."""
20
21
def interactive(b=None) -> bool:
22
"""Set or query interactive mode."""
23
24
def is_interactive() -> bool:
25
"""Return whether plots are updated after every plotting command."""
26
27
# Pyplot backend and interaction functions
28
def switch_backend(newbackend) -> None:
29
"""Switch the default backend."""
30
31
def show(*args, **kwargs) -> None:
32
"""Display all figures and enter the GUI event loop if needed."""
33
34
def ion() -> None:
35
"""Turn on interactive mode."""
36
37
def ioff() -> None:
38
"""Turn off interactive mode."""
39
```
40
41
### Interactive Backends
42
43
GUI backends for interactive plotting and user interaction.
44
45
```python { .api }
46
# Qt-based backends
47
'Qt5Agg' # Qt5 with Anti-Grain Geometry (AGG) rendering
48
'Qt5Cairo' # Qt5 with Cairo rendering
49
50
# Tkinter backend
51
'TkAgg' # Tk with AGG rendering
52
'TkCairo' # Tk with Cairo rendering
53
54
# GTK backends
55
'GTK3Agg' # GTK3 with AGG rendering
56
'GTK3Cairo' # GTK3 with Cairo rendering
57
58
# Platform-specific backends
59
'MacOSX' # Native macOS Cocoa backend
60
'WX' # wxPython backend
61
'WXAgg' # wxPython with AGG rendering
62
63
# Web-based backend
64
'WebAgg' # Web browser-based interactive backend
65
'notebook' # Jupyter notebook integration
66
'nbagg' # Jupyter notebook with interactivity
67
```
68
69
### Non-Interactive Backends
70
71
File output backends for saving plots without GUI interaction.
72
73
```python { .api }
74
# Raster formats
75
'Agg' # Anti-Grain Geometry (PNG, RGBA)
76
'Cairo' # Cairo graphics (PNG, PDF, PS, SVG)
77
78
# Vector formats
79
'PDF' # Portable Document Format
80
'PS' # PostScript
81
'SVG' # Scalable Vector Graphics
82
83
# Additional formats
84
'PGF' # PGF/TikZ for LaTeX
85
'Template' # Template backend for custom output
86
```
87
88
### File Export Functions
89
90
Functions for saving plots to various file formats.
91
92
```python { .api }
93
def savefig(fname, *, dpi='figure', format=None, metadata=None,
94
bbox_inches=None, pad_inches=0.1, facecolor='auto',
95
edgecolor='auto', backend=None, **kwargs) -> None:
96
"""Save the current figure to a file."""
97
98
# Figure.savefig method
99
class Figure:
100
def savefig(self, fname, *, transparent=None, dpi='figure', format=None,
101
metadata=None, bbox_inches=None, pad_inches=0.1,
102
facecolor='auto', edgecolor='auto', backend=None,
103
**kwargs) -> None:
104
"""Save the figure to a file."""
105
```
106
107
### Backend Base Classes
108
109
Base classes for implementing custom backends.
110
111
```python { .api }
112
from matplotlib.backends.backend_bases import *
113
114
class FigureCanvasBase:
115
"""Abstract base class for figure canvas implementations."""
116
117
def draw(self) -> None:
118
"""Draw the figure."""
119
120
def draw_idle(self) -> None:
121
"""Request a draw when the GUI is idle."""
122
123
def print_figure(self, filename, **kwargs) -> None:
124
"""Print/save the figure to a file."""
125
126
def mpl_connect(self, s, func) -> int:
127
"""Connect a callback function to a matplotlib event."""
128
129
def mpl_disconnect(self, cid) -> None:
130
"""Disconnect a callback by connection id."""
131
132
class RendererBase:
133
"""Abstract base class for renderers."""
134
135
def draw_path(self, gc, path, transform, rgbFace=None) -> None:
136
"""Draw a path using the graphics context."""
137
138
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None) -> None:
139
"""Draw text at position (x, y)."""
140
141
def draw_image(self, gc, x, y, im, transform=None) -> None:
142
"""Draw an image at position (x, y)."""
143
144
class FigureManagerBase:
145
"""Abstract base class for figure window managers."""
146
147
def show(self) -> None:
148
"""Show the figure window."""
149
150
def destroy(self) -> None:
151
"""Destroy the figure window."""
152
153
def set_window_title(self, title) -> None:
154
"""Set the title of the figure window."""
155
```
156
157
### Format-Specific Options
158
159
Options and metadata for different output formats.
160
161
```python { .api }
162
# PNG format options
163
PNG_OPTIONS = {
164
'dpi': 'figure', # Resolution in dots per inch
165
'facecolor': 'auto', # Figure background color
166
'edgecolor': 'auto', # Figure edge color
167
'transparent': False, # Transparent background
168
'bbox_inches': None, # Bounding box (tight, or None)
169
'pad_inches': 0.1, # Padding around saved area
170
'metadata': None # PNG metadata dictionary
171
}
172
173
# PDF format options
174
PDF_OPTIONS = {
175
'dpi': 'figure',
176
'facecolor': 'auto',
177
'edgecolor': 'auto',
178
'bbox_inches': None,
179
'pad_inches': 0.1,
180
'metadata': None, # PDF metadata dictionary
181
'backend_pdf': None # Backend-specific options
182
}
183
184
# SVG format options
185
SVG_OPTIONS = {
186
'dpi': 'figure',
187
'facecolor': 'auto',
188
'edgecolor': 'auto',
189
'bbox_inches': None,
190
'pad_inches': 0.1,
191
'metadata': None, # SVG metadata
192
'svg.image_inline': True, # Embed images inline
193
'svg.fonttype': 'path' # How to handle fonts
194
}
195
196
# PostScript options
197
PS_OPTIONS = {
198
'dpi': 'figure',
199
'facecolor': 'auto',
200
'edgecolor': 'auto',
201
'bbox_inches': None,
202
'pad_inches': 0.1,
203
'papertype': 'auto', # Paper size
204
'orientation': 'portrait' # Page orientation
205
}
206
```
207
208
## Usage Examples
209
210
### Backend Selection
211
212
```python
213
import matplotlib
214
import matplotlib.pyplot as plt
215
import numpy as np
216
217
# Check current backend
218
print(f"Current backend: {matplotlib.get_backend()}")
219
220
# List available backends
221
print(f"Available interactive backends: {matplotlib.backend_bases.Backend}")
222
223
# Set specific backend (must be done before importing pyplot)
224
# matplotlib.use('TkAgg') # For Tkinter GUI
225
# matplotlib.use('Qt5Agg') # For Qt5 GUI
226
# matplotlib.use('Agg') # For non-interactive (file output only)
227
228
# Create a simple plot
229
x = np.linspace(0, 10, 100)
230
y = np.sin(x)
231
232
plt.figure(figsize=(10, 6))
233
plt.plot(x, y, 'b-', linewidth=2)
234
plt.title(f'Plot using {matplotlib.get_backend()} backend')
235
plt.xlabel('X')
236
plt.ylabel('sin(X)')
237
plt.grid(True)
238
plt.show()
239
```
240
241
### Saving to Multiple Formats
242
243
```python
244
import matplotlib.pyplot as plt
245
import numpy as np
246
247
# Create sample plot
248
x = np.linspace(0, 10, 100)
249
y1 = np.sin(x)
250
y2 = np.cos(x)
251
252
fig, ax = plt.subplots(figsize=(10, 6))
253
ax.plot(x, y1, 'b-', linewidth=2, label='sin(x)')
254
ax.plot(x, y2, 'r-', linewidth=2, label='cos(x)')
255
ax.set_xlabel('X')
256
ax.set_ylabel('Y')
257
ax.set_title('Trigonometric Functions')
258
ax.legend()
259
ax.grid(True)
260
261
# Save in different formats
262
formats = {
263
'PNG': {'format': 'png', 'dpi': 300, 'bbox_inches': 'tight'},
264
'PDF': {'format': 'pdf', 'bbox_inches': 'tight'},
265
'SVG': {'format': 'svg', 'bbox_inches': 'tight'},
266
'EPS': {'format': 'eps', 'bbox_inches': 'tight'},
267
'JPG': {'format': 'jpg', 'dpi': 150, 'bbox_inches': 'tight'}
268
}
269
270
for name, options in formats.items():
271
filename = f'trigonometric_plot.{options["format"]}'
272
try:
273
fig.savefig(filename, **options)
274
print(f"Saved as {filename}")
275
except Exception as e:
276
print(f"Could not save as {name}: {e}")
277
278
plt.show()
279
```
280
281
### High-Quality Publication Output
282
283
```python
284
import matplotlib.pyplot as plt
285
import numpy as np
286
287
# Set up for publication-quality output
288
plt.rcParams.update({
289
'font.size': 12,
290
'font.family': 'serif',
291
'text.usetex': False, # Set True if LaTeX is available
292
'figure.figsize': (8, 6),
293
'figure.dpi': 100,
294
'savefig.dpi': 300,
295
'savefig.format': 'pdf',
296
'savefig.bbox': 'tight',
297
'axes.linewidth': 1.2,
298
'axes.spines.top': False,
299
'axes.spines.right': False,
300
'xtick.major.size': 4,
301
'ytick.major.size': 4,
302
'legend.frameon': False
303
})
304
305
# Create publication-quality plot
306
x = np.linspace(0, 2*np.pi, 1000)
307
y1 = np.sin(x)
308
y2 = np.sin(2*x) * 0.5
309
y3 = np.sin(3*x) * 0.25
310
311
fig, ax = plt.subplots()
312
313
ax.plot(x, y1, 'k-', linewidth=1.5, label='$\\sin(x)$')
314
ax.plot(x, y2, 'k--', linewidth=1.5, label='$0.5\\sin(2x)$')
315
ax.plot(x, y3, 'k:', linewidth=1.5, label='$0.25\\sin(3x)$')
316
317
ax.set_xlabel('$x$ (radians)')
318
ax.set_ylabel('Amplitude')
319
ax.set_title('Harmonic Functions')
320
ax.legend(loc='upper right')
321
ax.grid(True, alpha=0.3, linewidth=0.5)
322
323
# Set custom axis limits and ticks
324
ax.set_xlim(0, 2*np.pi)
325
ax.set_xticks([0, np.pi/2, np.pi, 3*np.pi/2, 2*np.pi])
326
ax.set_xticklabels(['0', '$\\pi/2$', '$\\pi$', '$3\\pi/2$', '$2\\pi$'])
327
328
# Save with high quality settings
329
fig.savefig('publication_plot.pdf', dpi=300, bbox_inches='tight',
330
facecolor='white', edgecolor='none')
331
fig.savefig('publication_plot.png', dpi=600, bbox_inches='tight',
332
facecolor='white', edgecolor='none')
333
334
plt.show()
335
```
336
337
### Interactive Backend Comparison
338
339
```python
340
import matplotlib
341
import matplotlib.pyplot as plt
342
import numpy as np
343
344
def create_interactive_plot():
345
"""Create plot with interactive features."""
346
fig, ax = plt.subplots(figsize=(10, 6))
347
348
x = np.linspace(0, 10, 100)
349
y = np.sin(x)
350
351
line, = ax.plot(x, y, 'b-', linewidth=2)
352
ax.set_xlabel('X')
353
ax.set_ylabel('sin(X)')
354
ax.set_title(f'Interactive Plot - Backend: {matplotlib.get_backend()}')
355
ax.grid(True)
356
357
# Add interactive callback
358
def on_click(event):
359
if event.inaxes == ax:
360
print(f"Clicked at ({event.xdata:.2f}, {event.ydata:.2f})")
361
362
fig.canvas.mpl_connect('button_press_event', on_click)
363
364
return fig, ax
365
366
# Test different interactive backends
367
interactive_backends = ['Qt5Agg', 'TkAgg', 'MacOSX']
368
369
for backend in interactive_backends:
370
try:
371
# Note: In practice, backend should be set before importing pyplot
372
print(f"\\nTesting backend: {backend}")
373
374
# This would normally require restarting Python
375
# matplotlib.use(backend)
376
377
fig, ax = create_interactive_plot()
378
plt.show(block=False) # Non-blocking show
379
380
# Backend-specific features
381
if 'Qt' in matplotlib.get_backend():
382
print("Qt backend: Supports native zoom, pan, configure subplots")
383
elif 'Tk' in matplotlib.get_backend():
384
print("Tk backend: Lightweight, good for simple interactions")
385
elif 'MacOSX' in matplotlib.get_backend():
386
print("macOS backend: Native macOS integration")
387
388
except Exception as e:
389
print(f"Backend {backend} not available: {e}")
390
391
plt.show()
392
```
393
394
### Web-Based Backend
395
396
```python
397
import matplotlib
398
import matplotlib.pyplot as plt
399
import numpy as np
400
401
# Use WebAgg for web-based interaction
402
# matplotlib.use('WebAgg')
403
404
# Create interactive web plot
405
fig, ax = plt.subplots(figsize=(10, 6))
406
407
# Generate data
408
t = np.linspace(0, 4*np.pi, 200)
409
x = np.sin(t)
410
y = np.cos(t * 1.5)
411
412
ax.plot(t, x, 'b-', linewidth=2, label='sin(t)', alpha=0.8)
413
ax.plot(t, y, 'r-', linewidth=2, label='cos(1.5t)', alpha=0.8)
414
415
ax.set_xlabel('Time')
416
ax.set_ylabel('Amplitude')
417
ax.set_title('Interactive Web Plot')
418
ax.legend()
419
ax.grid(True, alpha=0.3)
420
421
# The WebAgg backend automatically creates a web server
422
# and opens the plot in a browser with zoom/pan controls
423
print("WebAgg backend creates interactive web interface")
424
print("Navigate to http://127.0.0.1:8988 to view the plot")
425
426
plt.show()
427
```
428
429
### Custom Metadata and Export Options
430
431
```python
432
import matplotlib.pyplot as plt
433
import numpy as np
434
from datetime import datetime
435
436
# Create plot with comprehensive metadata
437
fig, ax = plt.subplots(figsize=(10, 6))
438
439
x = np.linspace(0, 10, 100)
440
y = np.exp(-x/5) * np.sin(x)
441
442
ax.plot(x, y, 'b-', linewidth=2)
443
ax.set_xlabel('Distance (m)')
444
ax.set_ylabel('Amplitude')
445
ax.set_title('Exponentially Decaying Oscillation')
446
ax.grid(True, alpha=0.3)
447
448
# Comprehensive metadata
449
metadata_common = {
450
'Title': 'Exponentially Decaying Oscillation',
451
'Author': 'Scientific Computing Lab',
452
'Subject': 'Mathematical Visualization',
453
'Keywords': 'exponential decay, oscillation, mathematics',
454
'Creator': 'matplotlib',
455
'CreationDate': datetime.now(),
456
'Description': 'Plot showing exponential decay with oscillation'
457
}
458
459
# Format-specific exports with metadata
460
export_configs = {
461
'high_res_png': {
462
'filename': 'decay_oscillation_highres.png',
463
'format': 'png',
464
'dpi': 600,
465
'bbox_inches': 'tight',
466
'facecolor': 'white',
467
'edgecolor': 'none',
468
'metadata': metadata_common
469
},
470
'web_png': {
471
'filename': 'decay_oscillation_web.png',
472
'format': 'png',
473
'dpi': 150,
474
'bbox_inches': 'tight',
475
'facecolor': 'white',
476
'metadata': metadata_common
477
},
478
'vector_pdf': {
479
'filename': 'decay_oscillation_vector.pdf',
480
'format': 'pdf',
481
'bbox_inches': 'tight',
482
'metadata': metadata_common
483
},
484
'scalable_svg': {
485
'filename': 'decay_oscillation_scalable.svg',
486
'format': 'svg',
487
'bbox_inches': 'tight',
488
'metadata': metadata_common
489
}
490
}
491
492
# Export in all configured formats
493
for config_name, options in export_configs.items():
494
try:
495
fig.savefig(**options)
496
print(f"Exported {config_name}: {options['filename']}")
497
except Exception as e:
498
print(f"Failed to export {config_name}: {e}")
499
500
plt.show()
501
502
# Print file size comparison
503
import os
504
print("\\nFile size comparison:")
505
for config_name, options in export_configs.items():
506
filename = options['filename']
507
if os.path.exists(filename):
508
size_kb = os.path.getsize(filename) / 1024
509
print(f"{filename}: {size_kb:.1f} KB")
510
```