rustplotlib 1.0.0__tar.gz → 1.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/Cargo.lock +1 -1
  2. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/Cargo.toml +1 -1
  3. rustplotlib-1.0.1/PKG-INFO +404 -0
  4. rustplotlib-1.0.1/README.md +383 -0
  5. rustplotlib-1.0.1/ROADMAP.md +171 -0
  6. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/pyproject.toml +1 -1
  7. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/pyplot.py +46 -6
  8. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/bar.rs +48 -0
  9. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/fill_between.rs +28 -0
  10. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/hist.rs +5 -0
  11. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/image.rs +75 -44
  12. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/line2d.rs +122 -0
  13. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/mod.rs +5 -0
  14. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/scatter.rs +23 -0
  15. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/axes.rs +345 -0
  16. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/figure.rs +104 -15
  17. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/lib.rs +1 -0
  18. rustplotlib-1.0.1/src/svg_renderer.rs +241 -0
  19. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/tests/test_figure.py +4 -1
  20. rustplotlib-1.0.0/PKG-INFO +0 -292
  21. rustplotlib-1.0.0/README.md +0 -271
  22. rustplotlib-1.0.0/ROADMAP.md +0 -201
  23. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/.github/workflows/ci.yml +0 -0
  24. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/.gitignore +0 -0
  25. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/LICENSE +0 -0
  26. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/dados/Data/PerfisTemp_rustplotlib.py +0 -0
  27. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/__init__.py +0 -0
  28. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/animation.py +0 -0
  29. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/backends/__init__.py +0 -0
  30. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/backends/backend_inline.py +0 -0
  31. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/backends/backend_pdf.py +0 -0
  32. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/colors.py +0 -0
  33. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/cycler.py +0 -0
  34. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/dates.py +0 -0
  35. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/font_manager.py +0 -0
  36. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/gridspec.py +0 -0
  37. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/mpl_toolkits/__init__.py +0 -0
  38. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/mpl_toolkits/mplot3d/__init__.py +0 -0
  39. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/patches.py +0 -0
  40. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/pyplot.pyi +0 -0
  41. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/style/__init__.py +0 -0
  42. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/ticker.py +0 -0
  43. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/python/rustplotlib/widgets.py +0 -0
  44. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/bar3d.rs +0 -0
  45. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/barh.rs +0 -0
  46. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/boxplot.rs +0 -0
  47. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/contour.rs +0 -0
  48. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/errorbar.rs +0 -0
  49. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/fill_betweenx.rs +0 -0
  50. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/hexbin.rs +0 -0
  51. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/legend.rs +0 -0
  52. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/line3d.rs +0 -0
  53. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/patches.rs +0 -0
  54. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/pie.rs +0 -0
  55. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/quiver.rs +0 -0
  56. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/scatter3d.rs +0 -0
  57. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/stem.rs +0 -0
  58. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/step.rs +0 -0
  59. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/streamplot.rs +0 -0
  60. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/surface3d.rs +0 -0
  61. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/violin.rs +0 -0
  62. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/artists/wireframe3d.rs +0 -0
  63. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/axes3d.rs +0 -0
  64. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/colors.rs +0 -0
  65. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/fonts/DejaVuSans.ttf +0 -0
  66. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/projection3d.rs +0 -0
  67. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/text.rs +0 -0
  68. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/ticker.rs +0 -0
  69. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/transforms.rs +0 -0
  70. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/src/window.rs +0 -0
  71. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/tests/test_3d.py +0 -0
  72. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/tests/test_benchmark.py +0 -0
  73. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/tests/test_colors.py +0 -0
  74. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/tests/test_phase6_7.py +0 -0
  75. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/tests/test_phase8.py +0 -0
  76. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/tests/test_pyplot.py +0 -0
  77. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/tests/test_ticker.py +0 -0
  78. {rustplotlib-1.0.0 → rustplotlib-1.0.1}/tests/test_transforms.py +0 -0
@@ -1368,7 +1368,7 @@ dependencies = [
1368
1368
 
1369
1369
  [[package]]
1370
1370
  name = "rustplotlib"
1371
- version = "1.0.0"
1371
+ version = "1.0.1"
1372
1372
  dependencies = [
1373
1373
  "ab_glyph",
1374
1374
  "numpy",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "rustplotlib"
3
- version = "1.0.0"
3
+ version = "1.0.1"
4
4
  edition = "2021"
5
5
  readme = "README.md"
6
6
 
@@ -0,0 +1,404 @@
1
+ Metadata-Version: 2.4
2
+ Name: rustplotlib
3
+ Version: 1.0.1
4
+ Classifier: Development Status :: 3 - Alpha
5
+ Classifier: Intended Audience :: Science/Research
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Programming Language :: Rust
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Topic :: Scientific/Engineering :: Visualization
10
+ Requires-Dist: numpy
11
+ License-File: LICENSE
12
+ Summary: Matplotlib drop-in replacement powered by Rust
13
+ Keywords: matplotlib,plotting,visualization,rust,performance
14
+ License: MIT
15
+ Requires-Python: >=3.9
16
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
17
+ Project-URL: Homepage, https://github.com/Thi4gon/rustplotlib
18
+ Project-URL: Issues, https://github.com/Thi4gon/rustplotlib/issues
19
+ Project-URL: Repository, https://github.com/Thi4gon/rustplotlib
20
+
21
+ # RustPlotLib
22
+
23
+ **Matplotlib reimplemented in Rust.** A high-performance drop-in replacement for Python's matplotlib, built from scratch with a native Rust rendering engine.
24
+
25
+ No Python runtime dependency for rendering. No wrappers. No subprocess calls. Pure Rust rasterization exposed to Python via [PyO3](https://pyo3.rs/).
26
+
27
+ [![CI](https://github.com/Thi4gon/rustplotlib/actions/workflows/ci.yml/badge.svg)](https://github.com/Thi4gon/rustplotlib/actions)
28
+ [![PyPI](https://img.shields.io/pypi/v/rustplotlib.svg)](https://pypi.org/project/rustplotlib/)
29
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
30
+ [![Python](https://img.shields.io/pypi/pyversions/rustplotlib.svg)](https://pypi.org/project/rustplotlib/)
31
+
32
+ ---
33
+
34
+ ## Why RustPlotLib?
35
+
36
+ | | matplotlib | Other Rust plotting libs | **rustplotlib** |
37
+ |---|---|---|---|
38
+ | Rendering engine | C/C++ (AGG) | None (wrap matplotlib or call Python) | **Rust native (tiny-skia)** |
39
+ | External dependencies | NumPy, Pillow, FreeType, etc. | Python + matplotlib required | **Zero** — self-contained |
40
+ | Performance | Baseline | Same or slower (subprocess overhead) | **Up to 30x faster** |
41
+ | Python API | Original | Rust-only or generates .py scripts | **Drop-in replacement** — same API |
42
+ | Approach | Interpreted + C extensions | Wrappers / code generators | **Full reimplementation in Rust** |
43
+
44
+ ---
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ pip install rustplotlib
50
+ ```
51
+
52
+ Supports Python 3.9-3.13 on macOS, Linux, and Windows (pre-built wheels available).
53
+
54
+ Or build from source (requires Rust 1.70+ and Python 3.9+):
55
+
56
+ ```bash
57
+ git clone https://github.com/Thi4gon/rustplotlib.git
58
+ cd rustplotlib
59
+ pip install maturin
60
+ maturin develop --release
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Usage
66
+
67
+ Just swap your import — everything else stays the same:
68
+
69
+ ```python
70
+ # Before:
71
+ # import matplotlib.pyplot as plt
72
+
73
+ # After:
74
+ import rustplotlib.pyplot as plt
75
+
76
+ plt.plot([1, 2, 3, 4], [1, 4, 2, 3], label="data")
77
+ plt.title("My Plot")
78
+ plt.xlabel("X")
79
+ plt.ylabel("Y")
80
+ plt.legend()
81
+ plt.grid(True)
82
+ plt.savefig("plot.png")
83
+ plt.show()
84
+ ```
85
+
86
+ ---
87
+
88
+ ## What's Implemented
89
+
90
+ ### 2D Plot Types (17 types)
91
+ | Function | Description |
92
+ |---|---|
93
+ | `plot()` | Line plots with color, linestyle, linewidth, markers, markevery, labels, alpha |
94
+ | `scatter()` | Scatter plots with per-point sizes, colors, markers, alpha |
95
+ | `bar()` / `barh()` | Vertical and horizontal bar charts (stacked via `bottom` param) |
96
+ | `hist()` | Histograms with configurable bins |
97
+ | `imshow()` | Image/heatmap display with 35+ colormaps |
98
+ | `fill_between()` / `fill_betweenx()` | Filled area between curves (vertical and horizontal) |
99
+ | `errorbar()` | Error bars with caps (xerr/yerr) |
100
+ | `step()` | Step plots (pre/post/mid) |
101
+ | `pie()` | Pie charts with labels |
102
+ | `boxplot()` | Box-and-whisker plots (Q1/median/Q3, whiskers, outliers) |
103
+ | `violinplot()` | Violin plots with Gaussian KDE |
104
+ | `stem()` | Stem plots with baseline |
105
+ | `contour()` / `contourf()` | Contour lines and filled contours (marching squares) |
106
+ | `hexbin()` | Hexagonal binning for 2D histograms |
107
+ | `quiver()` | Vector field arrows |
108
+ | `streamplot()` | Streamlines for vector fields (Euler integration) |
109
+
110
+ ### 3D Plot Types (5 types)
111
+ | Function | Description |
112
+ |---|---|
113
+ | `plot()` (3D) | 3D line plots |
114
+ | `scatter()` (3D) | 3D scatter with depth sorting |
115
+ | `plot_surface()` | 3D surface plots with colormaps |
116
+ | `plot_wireframe()` | 3D wireframe plots |
117
+ | `bar3d()` | 3D bar charts with shading |
118
+
119
+ ### Layout & Figure
120
+ | Function | Description |
121
+ |---|---|
122
+ | `subplots(nrows, ncols)` | Grid of axes with figsize/dpi |
123
+ | `subplot(nrows, ncols, index)` | Add single subplot |
124
+ | `subplot_mosaic()` | Named subplot layouts from ASCII art |
125
+ | `figure(figsize, dpi)` | Create new figure |
126
+ | `suptitle()` | Figure-level super title |
127
+ | `subplots_adjust()` | Control hspace/wspace between subplots |
128
+ | `tight_layout()` | Auto-adjust spacing |
129
+ | `add_subplot(projection='3d')` | Add 3D subplot |
130
+ | `clf()` / `cla()` / `close()` | Clear and close figures |
131
+ | `gcf()` / `gca()` | Get current figure/axes |
132
+
133
+ ### Axes Customization
134
+ | Function | Description |
135
+ |---|---|
136
+ | `title()` / `set_title()` | Plot title with fontsize |
137
+ | `xlabel()` / `ylabel()` | Axis labels with fontsize |
138
+ | `set_xlim()` / `set_ylim()` | Axis range limits |
139
+ | `set_xscale('log')` / `set_yscale('log')` | Logarithmic scale |
140
+ | `set_xticks()` / `set_yticks()` | Custom tick positions |
141
+ | `set_xticklabels()` / `set_yticklabels()` | Custom tick labels |
142
+ | `tick_params()` | Tick direction, length, width, labelsize |
143
+ | `set_aspect('equal')` | Equal aspect ratio |
144
+ | `invert_xaxis()` / `invert_yaxis()` | Invert axis direction |
145
+ | `axis('off')` | Hide axes completely |
146
+ | `set_facecolor()` | Axes background color |
147
+ | `spines['right'].set_visible(False)` | Spine customization |
148
+ | `twinx()` | Secondary y-axis |
149
+ | `legend()` | Legend with line+marker swatches and positioning |
150
+ | `grid()` | Grid lines with color, linewidth, linestyle, alpha, which |
151
+ | `text()` | Positioned text annotations |
152
+ | `annotate()` | Text with arrow pointing to data |
153
+ | `table()` | Data table inside axes |
154
+ | `axhline()` / `axvline()` | Horizontal/vertical reference lines |
155
+ | `axhspan()` / `axvspan()` | Shaded horizontal/vertical regions |
156
+ | `hlines()` / `vlines()` | Multiple reference lines with bounds |
157
+ | `colorbar()` | Color scale bar for imshow/contour |
158
+
159
+ ### Output Formats
160
+ | Method | Description |
161
+ |---|---|
162
+ | `savefig("file.png")` | Raster PNG (with dpi, transparent options) |
163
+ | `savefig("file.svg")` | Native vector SVG (real `<line>`, `<text>`, `<rect>` elements) |
164
+ | `savefig("file.pdf")` | PDF output |
165
+ | `show()` | Interactive window display |
166
+ | `PdfPages` | Multi-page PDF export |
167
+
168
+ ### Animation
169
+ | Feature | Description |
170
+ |---|---|
171
+ | `FuncAnimation` | Function-based animation with frame generation |
172
+ | GIF export | Save animations as GIF (via Pillow) |
173
+ | PNG sequence | Save animation frames as individual PNGs |
174
+
175
+ ### Styles & Themes
176
+ | Feature | Description |
177
+ |---|---|
178
+ | `style.use('dark_background')` | 6 built-in themes (default, dark_background, ggplot, seaborn, bmh, fivethirtyeight) |
179
+ | `rcParams` | Functional global configuration (30+ supported keys) |
180
+ | `set_facecolor()` | Figure and axes background colors |
181
+
182
+ ### Colors
183
+ - **Named:** 17 colors (red, blue, green, orange, purple, black, white, cyan, magenta, yellow, brown, pink, gray, olive, navy, teal, lime)
184
+ - **Shorthand:** `"r"`, `"g"`, `"b"`, `"c"`, `"m"`, `"y"`, `"k"`, `"w"`
185
+ - **Hex:** `"#FF0000"`, `"#f00"`, `"#FF000080"`
186
+ - **RGB/RGBA tuples:** `(1.0, 0.0, 0.0)`, `(1.0, 0.0, 0.0, 0.5)`
187
+
188
+ ### Linestyles & Markers
189
+ - **Linestyles:** `-` (solid), `--` (dashed), `-.` (dashdot), `:` (dotted)
190
+ - **Markers:** `.` `o` `s` `^` `v` `+` `x` `D` `*`
191
+ - **Format strings:** `"r--o"` = red + dashed + circle markers
192
+ - **markevery:** show marker every N points
193
+
194
+ ### Colormaps (35+)
195
+ `viridis` `plasma` `inferno` `magma` `cividis` `twilight` `turbo` `hot` `cool` `gray` `jet` `spring` `summer` `autumn` `winter` `copper` `bone` `pink` `binary` `gist_heat` `ocean` `terrain` `Blues` `Reds` `Greens` `YlOrRd` `YlGnBu` `RdYlBu` `RdBu` `PiYG` `PRGn` `BrBG` `Spectral` `Set1` `Set2` `Set3` `Pastel1` `Pastel2` `tab20`
196
+
197
+ ### Text Rendering
198
+ - Embedded DejaVu Sans font (no system font dependency)
199
+ - LaTeX-to-Unicode conversion (`$\theta$` -> theta, `$x_1$` -> x1, Greek letters, sub/superscripts, math operators)
200
+
201
+ ### Data Integration
202
+ - **Pandas:** plot directly from DataFrame/Series (optional dependency)
203
+ - **NumPy:** full array support
204
+ - **NaN handling:** automatic gaps in line plots for NaN/Inf values
205
+ - **Dates:** `date2num()`, `num2date()`, date formatters and locators
206
+ - **Categorical axes:** string-based x values automatically converted
207
+
208
+ ### Compatibility Modules
209
+ | Module | Status |
210
+ |---|---|
211
+ | `rustplotlib.pyplot` | Full implementation |
212
+ | `rustplotlib.style` | Full implementation (6 themes) |
213
+ | `rustplotlib.animation` | FuncAnimation + GIF export |
214
+ | `rustplotlib.widgets` | Stubs (Slider, Button, CheckButtons, RadioButtons, TextBox, Cursor) |
215
+ | `rustplotlib.font_manager` | FontProperties stub |
216
+ | `rustplotlib.ticker` | FormatStrFormatter stub |
217
+ | `rustplotlib.patches` | Rectangle, Circle, Polygon, FancyBboxPatch, Wedge |
218
+ | `rustplotlib.colors` | LinearSegmentedColormap, Normalize, LogNorm |
219
+ | `rustplotlib.dates` | Date conversion, formatters, locators |
220
+ | `rustplotlib.gridspec` | GridSpec, SubplotSpec |
221
+ | `rustplotlib.backends` | Backend system with `use()` |
222
+ | `rustplotlib.mpl_toolkits.mplot3d` | Axes3D for 3D plotting |
223
+
224
+ ---
225
+
226
+ ## Examples
227
+
228
+ ### Subplots
229
+
230
+ ```python
231
+ import rustplotlib.pyplot as plt
232
+ import numpy as np
233
+
234
+ fig, axes = plt.subplots(2, 2, figsize=(10, 8))
235
+
236
+ x = np.linspace(0, 10, 100)
237
+ axes[0][0].plot(x, np.sin(x), label="sin(x)")
238
+ axes[0][0].plot(x, np.cos(x), label="cos(x)", linestyle="--")
239
+ axes[0][0].set_title("Trigonometry")
240
+ axes[0][0].legend()
241
+ axes[0][0].grid(True)
242
+
243
+ axes[0][1].scatter(np.random.randn(200), np.random.randn(200), alpha=0.5)
244
+ axes[0][1].set_title("Random Scatter")
245
+
246
+ axes[1][0].bar([1, 2, 3, 4, 5], [3, 7, 2, 5, 8], color="green")
247
+ axes[1][0].set_title("Bar Chart")
248
+
249
+ axes[1][1].hist(np.random.randn(5000), bins=40, color="orange")
250
+ axes[1][1].set_title("Distribution")
251
+
252
+ fig.savefig("subplots.png")
253
+ ```
254
+
255
+ ### 3D Surface Plot
256
+
257
+ ```python
258
+ import rustplotlib.pyplot as plt
259
+ import numpy as np
260
+
261
+ fig = plt.figure(figsize=(10, 8))
262
+ ax = fig.add_subplot(111, projection='3d')
263
+
264
+ X = np.linspace(-5, 5, 50)
265
+ Y = np.linspace(-5, 5, 50)
266
+ X, Y = np.meshgrid(X, Y)
267
+ Z = np.sin(np.sqrt(X**2 + Y**2))
268
+
269
+ ax.plot_surface(X.tolist(), Y.tolist(), Z.tolist(), cmap='viridis')
270
+ ax.set_xlabel("X")
271
+ ax.set_ylabel("Y")
272
+ ax.set_zlabel("Z")
273
+ plt.savefig("surface3d.png")
274
+ ```
275
+
276
+ ### Dark Mode
277
+
278
+ ```python
279
+ import rustplotlib.pyplot as plt
280
+ import rustplotlib.style as style
281
+
282
+ style.use('dark_background')
283
+ plt.plot([1, 2, 3, 4], [1, 4, 2, 3], 'c-o', linewidth=2)
284
+ plt.title("Dark Mode")
285
+ plt.savefig("dark.png")
286
+ ```
287
+
288
+ ### Animation
289
+
290
+ ```python
291
+ import rustplotlib.pyplot as plt
292
+ from rustplotlib.animation import FuncAnimation
293
+ import numpy as np
294
+
295
+ fig, ax = plt.subplots()
296
+ x = np.linspace(0, 2 * np.pi, 100)
297
+
298
+ def update(frame):
299
+ ax.plot(x, np.sin(x + frame * 0.1), color='blue')
300
+ ax.set_title(f"Frame {frame}")
301
+
302
+ anim = FuncAnimation(fig, update, frames=50)
303
+ anim.save("wave.gif")
304
+ ```
305
+
306
+ ---
307
+
308
+ ## Performance Benchmark
309
+
310
+ Benchmarked against matplotlib on Apple Silicon (M-series). Each test runs 10 iterations, averaged:
311
+
312
+ | Benchmark | matplotlib | rustplotlib | Speedup |
313
+ |---|---|---|---|
314
+ | Line Plot (10k points) | 0.064s | 0.002s | **30.8x** |
315
+ | Scatter (5k points) | 0.029s | 0.017s | **1.7x** |
316
+ | Bar Chart (50 bars) | 0.023s | 0.002s | **9.6x** |
317
+ | Histogram (100k points) | 0.081s | 0.003s | **27.9x** |
318
+ | Subplots 2x2 | 0.041s | 0.002s | **26.7x** |
319
+
320
+ Run the benchmark yourself:
321
+ ```bash
322
+ python tests/test_benchmark.py
323
+ ```
324
+
325
+ ---
326
+
327
+ ## Tech Stack
328
+
329
+ | Component | Technology | Purpose |
330
+ |---|---|---|
331
+ | 2D Rendering | [tiny-skia](https://github.com/nickel-org/tiny-skia) | Rasterization (paths, shapes, antialiasing) |
332
+ | SVG Rendering | Custom SVG renderer | Native vector SVG output |
333
+ | Fonts | [ab_glyph](https://github.com/alexheretic/ab-glyph) | Text rendering with embedded DejaVu Sans |
334
+ | PNG output | [png](https://crates.io/crates/png) | PNG encoding |
335
+ | Window | [winit](https://github.com/rust-windowing/winit) + [softbuffer](https://github.com/rust-windowing/softbuffer) | Interactive display |
336
+ | 3D Projection | Custom | Orthographic 3D-to-2D with camera control |
337
+ | Python bindings | [PyO3](https://pyo3.rs/) + [maturin](https://www.maturin.rs/) | Rust-to-Python bridge |
338
+ | NumPy interop | [numpy](https://crates.io/crates/numpy) (PyO3) | Array conversion |
339
+
340
+ ---
341
+
342
+ ## Architecture
343
+
344
+ ```
345
+ Python: import rustplotlib.pyplot as plt
346
+ |
347
+ v
348
+ pyplot.py (matplotlib-compatible API layer)
349
+ |
350
+ v
351
+ PyO3 bridge (Rust <-> Python)
352
+ |
353
+ v
354
+ Rust core:
355
+ Figure --> Axes (2D) ---------> Artists (Line2D, Scatter, Bar, ...)
356
+ | |
357
+ --> Axes3D -----------> Artists3D (Line3D, Surface3D, ...)
358
+ |
359
+ v
360
+ Transform / Camera
361
+ |
362
+ +------------+------------+
363
+ | | |
364
+ tiny-skia SvgRenderer PDF gen
365
+ (raster) (vector) (document)
366
+ | | |
367
+ PNG SVG PDF
368
+ ```
369
+
370
+ ---
371
+
372
+ ## Security
373
+
374
+ - **Zero `unsafe` blocks** in the entire Rust codebase
375
+ - Path validation in `savefig()` (extension whitelist, path traversal rejection)
376
+ - Dimension validation (max 32768x32768 pixels)
377
+ - Unique temp file names (no symlink race conditions)
378
+ - Input validation on all PyO3 boundaries
379
+ - No `.unwrap()` on user-controlled data — proper error handling throughout
380
+
381
+ ---
382
+
383
+ ## Contributing
384
+
385
+ Contributions are welcome! This is an open-source project under the MIT license.
386
+
387
+ 1. Fork the repo
388
+ 2. Create a feature branch
389
+ 3. Open a PR against `master`
390
+ 4. PRs require at least 1 review before merging
391
+
392
+ **Priority areas for contribution:**
393
+ - Turning stub modules into full implementations (widgets, formatters/locators)
394
+ - Adding more colormaps with exact matplotlib data
395
+ - Improving SVG output fidelity
396
+ - Jupyter inline display support
397
+ - More comprehensive test coverage
398
+
399
+ ---
400
+
401
+ ## License
402
+
403
+ [MIT](LICENSE)
404
+