glplot 0.1.7__tar.gz → 0.1.9__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.
- {glplot-0.1.7 → glplot-0.1.9}/CITATION.cff +14 -7
- {glplot-0.1.7 → glplot-0.1.9}/PKG-INFO +41 -21
- {glplot-0.1.7 → glplot-0.1.9}/README.md +33 -15
- {glplot-0.1.7 → glplot-0.1.9}/glplot/__init__.py +12 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/anim/processes.py +5 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/core/panel.py +81 -1
- {glplot-0.1.7 → glplot-0.1.9}/glplot/engine.py +96 -30
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/actions.py +1 -1
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/icons.py +28 -29
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/keys.py +84 -17
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/mathops.py +6 -1
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/annotate.py +53 -57
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/data_editor.py +81 -86
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/dynamics.py +9 -7
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/functions.py +16 -15
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/help.py +21 -23
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/mathlab.py +19 -19
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/objects3d.py +4 -5
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/palette.py +37 -42
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/pipeline.py +17 -17
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/presentation.py +7 -7
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/scene.py +26 -37
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/selection.py +10 -13
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/style.py +70 -56
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/timeline.py +28 -23
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/view3d.py +1 -1
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/theme.py +60 -61
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/widgets.py +64 -60
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/workspace.py +36 -29
- {glplot-0.1.7 → glplot-0.1.9}/glplot/managers/hud.py +68 -56
- {glplot-0.1.7 → glplot-0.1.9}/glplot/policy.py +1 -1
- {glplot-0.1.7 → glplot-0.1.9}/glplot/pyplot.py +721 -65
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/axes3d.py +6 -6
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/axis.py +61 -68
- glplot-0.1.9/glplot/renderers/colorbar.py +415 -0
- glplot-0.1.9/glplot/renderers/contour_labels.py +274 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/legend.py +35 -38
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/scatter.py +27 -8
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/text.py +5 -5
- {glplot-0.1.7 → glplot-0.1.9}/glplot/utils/preview.py +238 -13
- {glplot-0.1.7 → glplot-0.1.9}/glplot/utils/shaders.py +66 -1
- {glplot-0.1.7 → glplot-0.1.9}/pyproject.toml +27 -10
- {glplot-0.1.7 → glplot-0.1.9}/tests/conftest.py +1 -1
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_anim_processes.py +9 -2
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_animation_api.py +1 -1
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_axes.py +12 -13
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_axes3d.py +7 -8
- glplot-0.1.9/tests/test_contour_labels.py +132 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gallery_integration.py +9 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_3d_panels.py +2 -3
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_actions.py +63 -5
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_annotate.py +6 -4
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_import_safety.py +31 -13
- glplot-0.1.9/tests/test_gui_input_regressions.py +183 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_keys.py +71 -14
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_legend.py +11 -15
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_mathlab.py +13 -12
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_pipeline.py +4 -6
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_scene_delete.py +2 -3
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_style_layer_editor.py +3 -4
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_timeline_panel.py +7 -5
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_mpl_compat.py +276 -12
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_mpl_parity_surface.py +7 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_objects3d_preview.py +9 -7
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_outline_2d.py +1 -0
- {glplot-0.1.7 → glplot-0.1.9}/.gitignore +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/CHANGELOG.md +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/LICENSE +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/__main__.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/anim/__init__.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/anim/applier.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/anim/primitives.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/animation.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/backend.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/controllers.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/core/__init__.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/core/camera3d.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/core/context.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/core/layers.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/core/layout.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/core/legacy.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/core/timeline.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/__init__.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/app.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/clipboard.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/commands.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/dataio.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/datasets.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/dynamics.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/expressions.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/fuzzy.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/generators3d.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/history.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/layerops.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/layerops3d.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/__init__.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/panels/base.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/pipeline.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/gui/styles.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/managers/__init__.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/managers/axis.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/managers/effects.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/managers/hud_state.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/managers/picking.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/managers/renderer_manager.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/options.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/__init__.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/base.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/density.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/exact.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/fractal.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/geometry3d.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/interaction.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/line_family.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/patch.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/renderers/polyline.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/utils/__init__.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/utils/anim_export.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/utils/blending.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/utils/export.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/utils/gl_utils.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/utils/mpl_bridge.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/utils/mpl_process.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/glplot/utils/scale.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_anim_applier.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_anim_export.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_anim_primitives.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_animation_integration.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_api_consistency.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_axis_margins.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_blending_3d.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_camera3d.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_camera_anisotropy.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_camera_projections.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_compositing_3d.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_compositing_api.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_dataio.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_density_tint.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_edge_cases.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_effects_post.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_encodings.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_engine.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_export.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_fractal.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_function_layer.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_generators3d.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_generators3d_extra.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_geometry3d.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_clipboard.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_commands.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_data_editor.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_datasets.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_dynamics.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_engine_integration.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_expressions.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_fields.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_fuzzy.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_history.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_impostor_alignment.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_keyboard_capture.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_layer_colormaps.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_layer_kinds.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_layer_params.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_mathops.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_regression_r2.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_scene_order.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_styles.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_gui_styles_extra.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_helpers.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_impostor_scatter_fidelity.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_layerops3d.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_layers.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_mpl_bridge.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_mpl_compat_3d.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_mpl_process.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_options.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_outline.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_panels.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_performance_benchmarks.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_plot_style_api.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_polyline_lod.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_pyplot.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_pyplot_3d.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_pyplot_integration.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_regression.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_robustness.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_scatter_renderer.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_selection_model.py +0 -0
- {glplot-0.1.7 → glplot-0.1.9}/tests/test_timeline.py +0 -0
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
cff-version: 1.2.0
|
|
2
2
|
title: GLPlot - High-Performance GPU-Accelerated Plotting Library for Python
|
|
3
|
-
message:
|
|
3
|
+
message: >-
|
|
4
|
+
If you use GLPlot in your research, please cite it as below. Felix Riccius, Julian
|
|
5
|
+
Holland and Gianmarco Ducci contributed equally to this work.
|
|
4
6
|
type: software
|
|
5
7
|
authors:
|
|
6
8
|
- family-names: Lombardi
|
|
7
9
|
given-names: Juan Manuel
|
|
8
10
|
email: lombardi@fhi-berlin.mpg.de
|
|
9
11
|
affiliation: "Fritz Haber Institute of the Max Planck Society"
|
|
10
|
-
orcid: "https://orcid.org/
|
|
12
|
+
orcid: "https://orcid.org/0009-0002-3961-1426"
|
|
13
|
+
- family-names: Riccius
|
|
14
|
+
given-names: Felix
|
|
15
|
+
orcid: "https://orcid.org/0000-0002-1331-4469"
|
|
16
|
+
- family-names: Holland
|
|
17
|
+
given-names: Julian
|
|
18
|
+
orcid: "https://orcid.org/0000-0003-0134-1790"
|
|
19
|
+
- family-names: Ducci
|
|
20
|
+
given-names: Gianmarco
|
|
11
21
|
identifiers:
|
|
12
22
|
- type: url
|
|
13
23
|
value: "https://github.com/AkarisDimitry/GLPlot"
|
|
14
24
|
- type: url
|
|
15
25
|
value: "https://gitlab.mpcdf.mpg.de/jmlombardi/glplot"
|
|
16
|
-
- type: doi
|
|
17
|
-
description: "Zenodo deposit (pending - will be assigned upon publication)"
|
|
18
|
-
value: "10.5281/zenodo.pending"
|
|
19
26
|
repository-code: "https://github.com/AkarisDimitry/GLPlot"
|
|
20
27
|
repository: "https://github.com/AkarisDimitry/GLPlot"
|
|
21
28
|
url: "https://github.com/AkarisDimitry/GLPlot"
|
|
@@ -41,6 +48,6 @@ keywords:
|
|
|
41
48
|
- data visualization
|
|
42
49
|
license: MIT
|
|
43
50
|
status: "active development"
|
|
44
|
-
version: 0.1.
|
|
45
|
-
date-released: 2026-
|
|
51
|
+
version: 0.1.7
|
|
52
|
+
date-released: 2026-08-18
|
|
46
53
|
development-status: "Beta"
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: glplot
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Summary: High-performance OpenGL plotting library for Python
|
|
5
5
|
Project-URL: Homepage, https://github.com/AkarisDimitry/GLPlot
|
|
6
6
|
Project-URL: Repository, https://github.com/AkarisDimitry/GLPlot
|
|
7
7
|
Project-URL: Issues, https://github.com/AkarisDimitry/GLPlot/issues
|
|
8
|
+
Author: Felix Riccius, Julian Holland, Gianmarco Ducci
|
|
8
9
|
Author-email: Juan Manuel Lombardi <lombardi@fhi-berlin.mpg.de>
|
|
9
10
|
License: MIT
|
|
10
11
|
License-File: LICENSE
|
|
@@ -15,16 +16,15 @@ Classifier: Intended Audience :: Science/Research
|
|
|
15
16
|
Classifier: License :: OSI Approved :: MIT License
|
|
16
17
|
Classifier: Operating System :: OS Independent
|
|
17
18
|
Classifier: Programming Language :: Python :: 3
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
22
|
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
23
23
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
-
Requires-Python: >=3.
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
25
|
Requires-Dist: glfw>=2.5
|
|
26
|
-
Requires-Dist: imgui
|
|
27
|
-
Requires-Dist: matplotlib
|
|
26
|
+
Requires-Dist: imgui-bundle>=1.92
|
|
27
|
+
Requires-Dist: matplotlib<3.10,>=3.6
|
|
28
28
|
Requires-Dist: numpy>=1.23
|
|
29
29
|
Requires-Dist: pyopengl>=3.1.6
|
|
30
30
|
Requires-Dist: scipy>=1.9
|
|
@@ -32,11 +32,13 @@ Provides-Extra: dev
|
|
|
32
32
|
Requires-Dist: build>=1.0; extra == 'dev'
|
|
33
33
|
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
34
34
|
Requires-Dist: pytest-mock>=3.10; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest-timeout>=2.1; extra == 'dev'
|
|
35
36
|
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
36
37
|
Requires-Dist: twine>=4.0; extra == 'dev'
|
|
37
38
|
Provides-Extra: test
|
|
38
39
|
Requires-Dist: pytest-cov>=4.0; extra == 'test'
|
|
39
40
|
Requires-Dist: pytest-mock>=3.10; extra == 'test'
|
|
41
|
+
Requires-Dist: pytest-timeout>=2.1; extra == 'test'
|
|
40
42
|
Requires-Dist: pytest>=7.0; extra == 'test'
|
|
41
43
|
Description-Content-Type: text/markdown
|
|
42
44
|
|
|
@@ -46,7 +48,7 @@ Description-Content-Type: text/markdown
|
|
|
46
48
|
[](https://github.com/AkarisDimitry/GLPlot/actions/workflows/lint.yml)
|
|
47
49
|
[](https://github.com/AkarisDimitry/GLPlot/actions/workflows/build.yml)
|
|
48
50
|
[](LICENSE)
|
|
49
|
-
[](pyproject.toml)
|
|
50
52
|
|
|
51
53
|
GLPlot is a Python plotting library with a Matplotlib-like API that renders on the GPU
|
|
52
54
|
through OpenGL instead of the CPU. Plots that make Matplotlib chug — millions of points,
|
|
@@ -68,8 +70,8 @@ cd GLPlot
|
|
|
68
70
|
pip install -e .
|
|
69
71
|
```
|
|
70
72
|
|
|
71
|
-
Requires Python 3.
|
|
72
|
-
`imgui
|
|
73
|
+
Requires Python 3.11+. Core dependencies: numpy, scipy, matplotlib, glfw, PyOpenGL,
|
|
74
|
+
`imgui-bundle` (for the on-screen control panel).
|
|
73
75
|
|
|
74
76
|
## 30-second example
|
|
75
77
|
|
|
@@ -92,16 +94,18 @@ That's it — a real window opens, fully interactive (pan/zoom/rotate) from the
|
|
|
92
94
|
|
|
93
95
|
## Interactive Examples Gallery (Click any figure to view code)
|
|
94
96
|
|
|
95
|
-
Explore 2D plots, 3D scenes, and real-time animations. **Click on any figure or title below to expand its full Python code.**
|
|
97
|
+
Explore 2D plots, 3D scenes, and real-time animations. **Click on any figure or title below to expand its full Python code, or click the file link to view the script.**
|
|
96
98
|
|
|
97
99
|
### 📊 2D Visualizations
|
|
98
100
|
|
|
99
101
|
<details>
|
|
100
102
|
<summary>
|
|
101
103
|
<img src="examples/gallery/results/02_scatter_fill.png" alt="10M-point spiral scatter" width="650"/>
|
|
102
|
-
<br><b>🔍 Click to view code: 10-Million Point Spiral Scatter (<code>02_scatter_fill.py</code>)</b>
|
|
104
|
+
<br><b>🔍 Click to view code: 10-Million Point Spiral Scatter (<a href="examples/gallery/02_scatter_fill.py"><code>02_scatter_fill.py</code></a>)</b>
|
|
103
105
|
</summary>
|
|
104
106
|
|
|
107
|
+
📄 **Full script:** [`examples/gallery/02_scatter_fill.py`](examples/gallery/02_scatter_fill.py)
|
|
108
|
+
|
|
105
109
|
```python
|
|
106
110
|
import numpy as np
|
|
107
111
|
import glplot.pyplot as plt
|
|
@@ -126,9 +130,11 @@ plt.show()
|
|
|
126
130
|
<details>
|
|
127
131
|
<summary>
|
|
128
132
|
<img src="examples/gallery/results/10_massive_hist2d_density.png" alt="10M-sample 2D density histogram" width="650"/>
|
|
129
|
-
<br><b>🔍 Click to view code: 10M-Sample 2D Density Histogram (<code>10_massive_hist2d_density.py</code>)</b>
|
|
133
|
+
<br><b>🔍 Click to view code: 10M-Sample 2D Density Histogram (<a href="examples/gallery/10_massive_hist2d_density.py"><code>10_massive_hist2d_density.py</code></a>)</b>
|
|
130
134
|
</summary>
|
|
131
135
|
|
|
136
|
+
📄 **Full script:** [`examples/gallery/10_massive_hist2d_density.py`](examples/gallery/10_massive_hist2d_density.py)
|
|
137
|
+
|
|
132
138
|
```python
|
|
133
139
|
import numpy as np
|
|
134
140
|
import glplot.pyplot as plt
|
|
@@ -162,9 +168,11 @@ plt.show()
|
|
|
162
168
|
<details>
|
|
163
169
|
<summary>
|
|
164
170
|
<img src="examples/gallery/results/01_line_plot.png" alt="10,072-line oscilloscope ensemble" width="650"/>
|
|
165
|
-
<br><b>🔍 Click to view code: 10,072-Line Oscilloscope Ensemble (<code>01_line_plot.py</code>)</b>
|
|
171
|
+
<br><b>🔍 Click to view code: 10,072-Line Oscilloscope Ensemble (<a href="examples/gallery/01_line_plot.py"><code>01_line_plot.py</code></a>)</b>
|
|
166
172
|
</summary>
|
|
167
173
|
|
|
174
|
+
📄 **Full script:** [`examples/gallery/01_line_plot.py`](examples/gallery/01_line_plot.py)
|
|
175
|
+
|
|
168
176
|
```python
|
|
169
177
|
import colorsys
|
|
170
178
|
import numpy as np
|
|
@@ -212,9 +220,11 @@ plt.show()
|
|
|
212
220
|
<details>
|
|
213
221
|
<summary>
|
|
214
222
|
<img src="examples/gallery/results/07_projected_3d_cloud.png" alt="1M-point 3D Point Cloud" width="650"/>
|
|
215
|
-
<br><b>🔍 Click to view code: 1M-Point Circumstellar Dust Halo (<code>07_projected_3d_cloud.py</code>)</b>
|
|
223
|
+
<br><b>🔍 Click to view code: 1M-Point Circumstellar Dust Halo (<a href="examples/gallery/07_projected_3d_cloud.py"><code>07_projected_3d_cloud.py</code></a>)</b>
|
|
216
224
|
</summary>
|
|
217
225
|
|
|
226
|
+
📄 **Full script:** [`examples/gallery/07_projected_3d_cloud.py`](examples/gallery/07_projected_3d_cloud.py)
|
|
227
|
+
|
|
218
228
|
```python
|
|
219
229
|
import numpy as np
|
|
220
230
|
import glplot.pyplot as plt
|
|
@@ -253,9 +263,11 @@ plt.show()
|
|
|
253
263
|
<details>
|
|
254
264
|
<summary>
|
|
255
265
|
<img src="examples/gallery/results/13_volumetric_nebula.png" alt="1.75M-Point Volumetric Nebula" width="650"/>
|
|
256
|
-
<br><b>🔍 Click to view code: 1.75M-Point Volumetric Nebula (<code>13_volumetric_nebula.py</code>)</b>
|
|
266
|
+
<br><b>🔍 Click to view code: 1.75M-Point Volumetric Nebula (<a href="examples/gallery/13_volumetric_nebula.py"><code>13_volumetric_nebula.py</code></a>)</b>
|
|
257
267
|
</summary>
|
|
258
268
|
|
|
269
|
+
📄 **Full script:** [`examples/gallery/13_volumetric_nebula.py`](examples/gallery/13_volumetric_nebula.py)
|
|
270
|
+
|
|
259
271
|
```python
|
|
260
272
|
import numpy as np
|
|
261
273
|
import glplot.pyplot as plt
|
|
@@ -299,9 +311,11 @@ plt.show()
|
|
|
299
311
|
<details>
|
|
300
312
|
<summary>
|
|
301
313
|
<img src="examples/gallery/results/19_turbulent_vector_field_3d.png" alt="3D Turbulent Vector Field" width="650"/>
|
|
302
|
-
<br><b>🔍 Click to view code: 3D Turbulent Vector Field (<code>19_turbulent_vector_field_3d.py</code>)</b>
|
|
314
|
+
<br><b>🔍 Click to view code: 3D Turbulent Vector Field (<a href="examples/gallery/19_turbulent_vector_field_3d.py"><code>19_turbulent_vector_field_3d.py</code></a>)</b>
|
|
303
315
|
</summary>
|
|
304
316
|
|
|
317
|
+
📄 **Full script:** [`examples/gallery/19_turbulent_vector_field_3d.py`](examples/gallery/19_turbulent_vector_field_3d.py)
|
|
318
|
+
|
|
305
319
|
```python
|
|
306
320
|
import numpy as np
|
|
307
321
|
import glplot.pyplot as plt
|
|
@@ -342,9 +356,11 @@ plt.show()
|
|
|
342
356
|
<details>
|
|
343
357
|
<summary>
|
|
344
358
|
<img src="examples/gallery/results/28_chladni_wave_animation.gif" alt="Chladni wave animation" width="650"/>
|
|
345
|
-
<br><b>🔍 Click to view code: Animated Standing-Wave Interference (<code>28_chladni_wave_animation.py</code>)</b>
|
|
359
|
+
<br><b>🔍 Click to view code: Animated Standing-Wave Interference (<a href="examples/gallery/28_chladni_wave_animation.py"><code>28_chladni_wave_animation.py</code></a>)</b>
|
|
346
360
|
</summary>
|
|
347
361
|
|
|
362
|
+
📄 **Full script:** [`examples/gallery/28_chladni_wave_animation.py`](examples/gallery/28_chladni_wave_animation.py)
|
|
363
|
+
|
|
348
364
|
```python
|
|
349
365
|
import numpy as np
|
|
350
366
|
import glplot.animation as animation
|
|
@@ -394,9 +410,11 @@ plt.show()
|
|
|
394
410
|
<details>
|
|
395
411
|
<summary>
|
|
396
412
|
<img src="examples/gallery/animations/results/03_spectrum_analyzer_bars.gif" alt="Audio spectrum analyzer bars" width="650"/>
|
|
397
|
-
<br><b>🔍 Click to view code: Real-Time Audio Spectrum Analyzer (<code>03_spectrum_analyzer_bars.py</code>)</b>
|
|
413
|
+
<br><b>🔍 Click to view code: Real-Time Audio Spectrum Analyzer (<a href="examples/gallery/animations/03_spectrum_analyzer_bars.py"><code>03_spectrum_analyzer_bars.py</code></a>)</b>
|
|
398
414
|
</summary>
|
|
399
415
|
|
|
416
|
+
📄 **Full script:** [`examples/gallery/animations/03_spectrum_analyzer_bars.py`](examples/gallery/animations/03_spectrum_analyzer_bars.py)
|
|
417
|
+
|
|
400
418
|
```python
|
|
401
419
|
import numpy as np
|
|
402
420
|
import glplot.animation as animation
|
|
@@ -428,9 +446,11 @@ plt.show()
|
|
|
428
446
|
<details>
|
|
429
447
|
<summary>
|
|
430
448
|
<img src="examples/gallery/animations/results/01_orbiting_star_cluster.gif" alt="Orbiting star cluster" width="650"/>
|
|
431
|
-
<br><b>🔍 Click to view code: Differential Keplerian Star Cluster (<code>01_orbiting_star_cluster.py</code>)</b>
|
|
449
|
+
<br><b>🔍 Click to view code: Differential Keplerian Star Cluster (<a href="examples/gallery/animations/01_orbiting_star_cluster.py"><code>01_orbiting_star_cluster.py</code></a>)</b>
|
|
432
450
|
</summary>
|
|
433
451
|
|
|
452
|
+
📄 **Full script:** [`examples/gallery/animations/01_orbiting_star_cluster.py`](examples/gallery/animations/01_orbiting_star_cluster.py)
|
|
453
|
+
|
|
434
454
|
```python
|
|
435
455
|
import numpy as np
|
|
436
456
|
import glplot.animation as animation
|
|
@@ -540,7 +560,7 @@ pytest tests/test_pyplot.py::test_plot_accepts_y_only_and_returns_artists # one
|
|
|
540
560
|
```
|
|
541
561
|
|
|
542
562
|
6,800+ tests, run fully headless (no window is ever displayed) so they work in CI. The
|
|
543
|
-
matrix covers Python 3.
|
|
563
|
+
matrix covers Python 3.11–3.13 on Ubuntu, macOS, and Windows; `black`, `isort`, and `flake8`
|
|
544
564
|
are enforced on every push. See `examples/benchmark/` for reproducible performance
|
|
545
565
|
comparisons against Matplotlib, VisPy, fastplotlib, Datashader, and hvPlot, and `tools/`
|
|
546
566
|
for GPU/environment diagnostics.
|
|
@@ -557,7 +577,7 @@ for GPU/environment diagnostics.
|
|
|
557
577
|
```bibtex
|
|
558
578
|
@software{lombardi2026glplot,
|
|
559
579
|
title={GLPlot: High-Performance GPU-Accelerated Plotting Library for Python},
|
|
560
|
-
author={Lombardi, Juan Manuel},
|
|
580
|
+
author={Lombardi, Juan Manuel and Riccius, Felix and Holland, Julian and Ducci, Gianmarco},
|
|
561
581
|
year={2026},
|
|
562
582
|
url={https://github.com/AkarisDimitry/GLPlot},
|
|
563
583
|
doi={10.5281/zenodo.PLACEHOLDER}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://github.com/AkarisDimitry/GLPlot/actions/workflows/lint.yml)
|
|
5
5
|
[](https://github.com/AkarisDimitry/GLPlot/actions/workflows/build.yml)
|
|
6
6
|
[](LICENSE)
|
|
7
|
-
[](pyproject.toml)
|
|
8
8
|
|
|
9
9
|
GLPlot is a Python plotting library with a Matplotlib-like API that renders on the GPU
|
|
10
10
|
through OpenGL instead of the CPU. Plots that make Matplotlib chug — millions of points,
|
|
@@ -26,8 +26,8 @@ cd GLPlot
|
|
|
26
26
|
pip install -e .
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
Requires Python 3.
|
|
30
|
-
`imgui
|
|
29
|
+
Requires Python 3.11+. Core dependencies: numpy, scipy, matplotlib, glfw, PyOpenGL,
|
|
30
|
+
`imgui-bundle` (for the on-screen control panel).
|
|
31
31
|
|
|
32
32
|
## 30-second example
|
|
33
33
|
|
|
@@ -50,16 +50,18 @@ That's it — a real window opens, fully interactive (pan/zoom/rotate) from the
|
|
|
50
50
|
|
|
51
51
|
## Interactive Examples Gallery (Click any figure to view code)
|
|
52
52
|
|
|
53
|
-
Explore 2D plots, 3D scenes, and real-time animations. **Click on any figure or title below to expand its full Python code.**
|
|
53
|
+
Explore 2D plots, 3D scenes, and real-time animations. **Click on any figure or title below to expand its full Python code, or click the file link to view the script.**
|
|
54
54
|
|
|
55
55
|
### 📊 2D Visualizations
|
|
56
56
|
|
|
57
57
|
<details>
|
|
58
58
|
<summary>
|
|
59
59
|
<img src="examples/gallery/results/02_scatter_fill.png" alt="10M-point spiral scatter" width="650"/>
|
|
60
|
-
<br><b>🔍 Click to view code: 10-Million Point Spiral Scatter (<code>02_scatter_fill.py</code>)</b>
|
|
60
|
+
<br><b>🔍 Click to view code: 10-Million Point Spiral Scatter (<a href="examples/gallery/02_scatter_fill.py"><code>02_scatter_fill.py</code></a>)</b>
|
|
61
61
|
</summary>
|
|
62
62
|
|
|
63
|
+
📄 **Full script:** [`examples/gallery/02_scatter_fill.py`](examples/gallery/02_scatter_fill.py)
|
|
64
|
+
|
|
63
65
|
```python
|
|
64
66
|
import numpy as np
|
|
65
67
|
import glplot.pyplot as plt
|
|
@@ -84,9 +86,11 @@ plt.show()
|
|
|
84
86
|
<details>
|
|
85
87
|
<summary>
|
|
86
88
|
<img src="examples/gallery/results/10_massive_hist2d_density.png" alt="10M-sample 2D density histogram" width="650"/>
|
|
87
|
-
<br><b>🔍 Click to view code: 10M-Sample 2D Density Histogram (<code>10_massive_hist2d_density.py</code>)</b>
|
|
89
|
+
<br><b>🔍 Click to view code: 10M-Sample 2D Density Histogram (<a href="examples/gallery/10_massive_hist2d_density.py"><code>10_massive_hist2d_density.py</code></a>)</b>
|
|
88
90
|
</summary>
|
|
89
91
|
|
|
92
|
+
📄 **Full script:** [`examples/gallery/10_massive_hist2d_density.py`](examples/gallery/10_massive_hist2d_density.py)
|
|
93
|
+
|
|
90
94
|
```python
|
|
91
95
|
import numpy as np
|
|
92
96
|
import glplot.pyplot as plt
|
|
@@ -120,9 +124,11 @@ plt.show()
|
|
|
120
124
|
<details>
|
|
121
125
|
<summary>
|
|
122
126
|
<img src="examples/gallery/results/01_line_plot.png" alt="10,072-line oscilloscope ensemble" width="650"/>
|
|
123
|
-
<br><b>🔍 Click to view code: 10,072-Line Oscilloscope Ensemble (<code>01_line_plot.py</code>)</b>
|
|
127
|
+
<br><b>🔍 Click to view code: 10,072-Line Oscilloscope Ensemble (<a href="examples/gallery/01_line_plot.py"><code>01_line_plot.py</code></a>)</b>
|
|
124
128
|
</summary>
|
|
125
129
|
|
|
130
|
+
📄 **Full script:** [`examples/gallery/01_line_plot.py`](examples/gallery/01_line_plot.py)
|
|
131
|
+
|
|
126
132
|
```python
|
|
127
133
|
import colorsys
|
|
128
134
|
import numpy as np
|
|
@@ -170,9 +176,11 @@ plt.show()
|
|
|
170
176
|
<details>
|
|
171
177
|
<summary>
|
|
172
178
|
<img src="examples/gallery/results/07_projected_3d_cloud.png" alt="1M-point 3D Point Cloud" width="650"/>
|
|
173
|
-
<br><b>🔍 Click to view code: 1M-Point Circumstellar Dust Halo (<code>07_projected_3d_cloud.py</code>)</b>
|
|
179
|
+
<br><b>🔍 Click to view code: 1M-Point Circumstellar Dust Halo (<a href="examples/gallery/07_projected_3d_cloud.py"><code>07_projected_3d_cloud.py</code></a>)</b>
|
|
174
180
|
</summary>
|
|
175
181
|
|
|
182
|
+
📄 **Full script:** [`examples/gallery/07_projected_3d_cloud.py`](examples/gallery/07_projected_3d_cloud.py)
|
|
183
|
+
|
|
176
184
|
```python
|
|
177
185
|
import numpy as np
|
|
178
186
|
import glplot.pyplot as plt
|
|
@@ -211,9 +219,11 @@ plt.show()
|
|
|
211
219
|
<details>
|
|
212
220
|
<summary>
|
|
213
221
|
<img src="examples/gallery/results/13_volumetric_nebula.png" alt="1.75M-Point Volumetric Nebula" width="650"/>
|
|
214
|
-
<br><b>🔍 Click to view code: 1.75M-Point Volumetric Nebula (<code>13_volumetric_nebula.py</code>)</b>
|
|
222
|
+
<br><b>🔍 Click to view code: 1.75M-Point Volumetric Nebula (<a href="examples/gallery/13_volumetric_nebula.py"><code>13_volumetric_nebula.py</code></a>)</b>
|
|
215
223
|
</summary>
|
|
216
224
|
|
|
225
|
+
📄 **Full script:** [`examples/gallery/13_volumetric_nebula.py`](examples/gallery/13_volumetric_nebula.py)
|
|
226
|
+
|
|
217
227
|
```python
|
|
218
228
|
import numpy as np
|
|
219
229
|
import glplot.pyplot as plt
|
|
@@ -257,9 +267,11 @@ plt.show()
|
|
|
257
267
|
<details>
|
|
258
268
|
<summary>
|
|
259
269
|
<img src="examples/gallery/results/19_turbulent_vector_field_3d.png" alt="3D Turbulent Vector Field" width="650"/>
|
|
260
|
-
<br><b>🔍 Click to view code: 3D Turbulent Vector Field (<code>19_turbulent_vector_field_3d.py</code>)</b>
|
|
270
|
+
<br><b>🔍 Click to view code: 3D Turbulent Vector Field (<a href="examples/gallery/19_turbulent_vector_field_3d.py"><code>19_turbulent_vector_field_3d.py</code></a>)</b>
|
|
261
271
|
</summary>
|
|
262
272
|
|
|
273
|
+
📄 **Full script:** [`examples/gallery/19_turbulent_vector_field_3d.py`](examples/gallery/19_turbulent_vector_field_3d.py)
|
|
274
|
+
|
|
263
275
|
```python
|
|
264
276
|
import numpy as np
|
|
265
277
|
import glplot.pyplot as plt
|
|
@@ -300,9 +312,11 @@ plt.show()
|
|
|
300
312
|
<details>
|
|
301
313
|
<summary>
|
|
302
314
|
<img src="examples/gallery/results/28_chladni_wave_animation.gif" alt="Chladni wave animation" width="650"/>
|
|
303
|
-
<br><b>🔍 Click to view code: Animated Standing-Wave Interference (<code>28_chladni_wave_animation.py</code>)</b>
|
|
315
|
+
<br><b>🔍 Click to view code: Animated Standing-Wave Interference (<a href="examples/gallery/28_chladni_wave_animation.py"><code>28_chladni_wave_animation.py</code></a>)</b>
|
|
304
316
|
</summary>
|
|
305
317
|
|
|
318
|
+
📄 **Full script:** [`examples/gallery/28_chladni_wave_animation.py`](examples/gallery/28_chladni_wave_animation.py)
|
|
319
|
+
|
|
306
320
|
```python
|
|
307
321
|
import numpy as np
|
|
308
322
|
import glplot.animation as animation
|
|
@@ -352,9 +366,11 @@ plt.show()
|
|
|
352
366
|
<details>
|
|
353
367
|
<summary>
|
|
354
368
|
<img src="examples/gallery/animations/results/03_spectrum_analyzer_bars.gif" alt="Audio spectrum analyzer bars" width="650"/>
|
|
355
|
-
<br><b>🔍 Click to view code: Real-Time Audio Spectrum Analyzer (<code>03_spectrum_analyzer_bars.py</code>)</b>
|
|
369
|
+
<br><b>🔍 Click to view code: Real-Time Audio Spectrum Analyzer (<a href="examples/gallery/animations/03_spectrum_analyzer_bars.py"><code>03_spectrum_analyzer_bars.py</code></a>)</b>
|
|
356
370
|
</summary>
|
|
357
371
|
|
|
372
|
+
📄 **Full script:** [`examples/gallery/animations/03_spectrum_analyzer_bars.py`](examples/gallery/animations/03_spectrum_analyzer_bars.py)
|
|
373
|
+
|
|
358
374
|
```python
|
|
359
375
|
import numpy as np
|
|
360
376
|
import glplot.animation as animation
|
|
@@ -386,9 +402,11 @@ plt.show()
|
|
|
386
402
|
<details>
|
|
387
403
|
<summary>
|
|
388
404
|
<img src="examples/gallery/animations/results/01_orbiting_star_cluster.gif" alt="Orbiting star cluster" width="650"/>
|
|
389
|
-
<br><b>🔍 Click to view code: Differential Keplerian Star Cluster (<code>01_orbiting_star_cluster.py</code>)</b>
|
|
405
|
+
<br><b>🔍 Click to view code: Differential Keplerian Star Cluster (<a href="examples/gallery/animations/01_orbiting_star_cluster.py"><code>01_orbiting_star_cluster.py</code></a>)</b>
|
|
390
406
|
</summary>
|
|
391
407
|
|
|
408
|
+
📄 **Full script:** [`examples/gallery/animations/01_orbiting_star_cluster.py`](examples/gallery/animations/01_orbiting_star_cluster.py)
|
|
409
|
+
|
|
392
410
|
```python
|
|
393
411
|
import numpy as np
|
|
394
412
|
import glplot.animation as animation
|
|
@@ -498,7 +516,7 @@ pytest tests/test_pyplot.py::test_plot_accepts_y_only_and_returns_artists # one
|
|
|
498
516
|
```
|
|
499
517
|
|
|
500
518
|
6,800+ tests, run fully headless (no window is ever displayed) so they work in CI. The
|
|
501
|
-
matrix covers Python 3.
|
|
519
|
+
matrix covers Python 3.11–3.13 on Ubuntu, macOS, and Windows; `black`, `isort`, and `flake8`
|
|
502
520
|
are enforced on every push. See `examples/benchmark/` for reproducible performance
|
|
503
521
|
comparisons against Matplotlib, VisPy, fastplotlib, Datashader, and hvPlot, and `tools/`
|
|
504
522
|
for GPU/environment diagnostics.
|
|
@@ -515,7 +533,7 @@ for GPU/environment diagnostics.
|
|
|
515
533
|
```bibtex
|
|
516
534
|
@software{lombardi2026glplot,
|
|
517
535
|
title={GLPlot: High-Performance GPU-Accelerated Plotting Library for Python},
|
|
518
|
-
author={Lombardi, Juan Manuel},
|
|
536
|
+
author={Lombardi, Juan Manuel and Riccius, Felix and Holland, Julian and Ducci, Gianmarco},
|
|
519
537
|
year={2026},
|
|
520
538
|
url={https://github.com/AkarisDimitry/GLPlot},
|
|
521
539
|
doi={10.5281/zenodo.PLACEHOLDER}
|
|
@@ -23,6 +23,18 @@ Author: Juan Manuel Lombardi
|
|
|
23
23
|
Repository: https://github.com/AkarisDimitry/GLPlot
|
|
24
24
|
"""
|
|
25
25
|
|
|
26
|
+
try:
|
|
27
|
+
# Must run before anything imports the `glfw` package (`.engine` does, right below).
|
|
28
|
+
# imgui-bundle points pip's `glfw` at its own bundled libglfw via the PYGLFW_LIBRARY
|
|
29
|
+
# env var, but only if it gets a chance to set that *before* `glfw` loads its own
|
|
30
|
+
# copy -- otherwise both libglfw.3.dylib's end up loaded in the same process, and
|
|
31
|
+
# macOS logs "Class GLFWWindow is implemented in both ..." for every GLFW ObjC class
|
|
32
|
+
# (verified: importing imgui_bundle first eliminates the warning entirely; importing
|
|
33
|
+
# it after `glfw`, as a naive import order would, does not).
|
|
34
|
+
import imgui_bundle as _imgui_bundle # noqa: F401
|
|
35
|
+
except Exception: # pragma: no cover - imgui_bundle is optional at import time (GL-less use)
|
|
36
|
+
pass
|
|
37
|
+
|
|
26
38
|
from .engine import GPULinePlot
|
|
27
39
|
from .options import BlendMode, EngineOptions, RenderMode
|
|
28
40
|
|
|
@@ -111,6 +111,11 @@ per-quartile mean settles at -29.767, -29.772, -29.773, -29.773 and stays there.
|
|
|
111
111
|
the property that matters, and it is the property forward Euler does not have -- an Euler
|
|
112
112
|
two-body orbit gains energy monotonically and unwinds into a spiral within a few hundred
|
|
113
113
|
steps, which is not a small quantitative error but a qualitatively wrong picture.
|
|
114
|
+
|
|
115
|
+
The NBODY row is measured on Accelerate/arm64; six mutually gravitating bodies is a
|
|
116
|
+
chaotic system, so a different libm/BLAS (OpenBLAS/x86_64, as in Windows and Linux CI)
|
|
117
|
+
lands on a different point of the same bounded orbit family and measures a band around
|
|
118
|
+
5x larger. The other rows are far enough from chaos, or short enough, not to show this.
|
|
114
119
|
"""
|
|
115
120
|
|
|
116
121
|
from __future__ import annotations
|
|
@@ -18,7 +18,8 @@ origin, which is what ``glViewport`` wants).
|
|
|
18
18
|
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
21
|
-
from
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
from typing import TYPE_CHECKING, Any, List, Optional, Tuple
|
|
22
23
|
|
|
23
24
|
from ..controllers import CameraController
|
|
24
25
|
from .camera3d import Axes3DOptions, Camera3D
|
|
@@ -29,6 +30,61 @@ if TYPE_CHECKING:
|
|
|
29
30
|
from ..options import EngineOptions
|
|
30
31
|
|
|
31
32
|
|
|
33
|
+
@dataclass
|
|
34
|
+
class ColorbarSpec:
|
|
35
|
+
"""One colorbar attached to a :class:`Panel`, drawn as a screen-space overlay.
|
|
36
|
+
|
|
37
|
+
Deliberately not a :class:`Panel` itself: any rect registered on ``fig.panels`` is
|
|
38
|
+
click-to-activate and pan/zoom-able (see ``GPULinePlot._panel_index_at``), so a
|
|
39
|
+
colorbar built that way would silently steal "current axes" the moment a script did
|
|
40
|
+
``im = plt.imshow(...); plt.colorbar(); plt.title(...)`` -- the title would land on
|
|
41
|
+
the colorbar. A ``ColorbarSpec`` instead just describes a strip of the figure and is
|
|
42
|
+
drawn by :func:`glplot.renderers.colorbar.draw_colorbars`, in the same whole-window,
|
|
43
|
+
camera-free pixel space :meth:`GPULinePlot._draw_panel_borders` already draws in.
|
|
44
|
+
|
|
45
|
+
``norm`` is always a concrete, bounded ``matplotlib.colors.Normalize`` instance (never
|
|
46
|
+
a bare scale name and never unbounded) -- the single source of truth the gradient fill,
|
|
47
|
+
the tick locator, and the headless ``savefig()`` reconstruction all read alike, so the
|
|
48
|
+
live bar and the exported PNG cannot independently drift from what was actually asked
|
|
49
|
+
for.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
#: (x0, y0, w, h) in figure fractions, bottom-left origin -- same convention as
|
|
53
|
+
#: :attr:`Panel.rect_frac`, and the strip vacated from the host panel's own rect.
|
|
54
|
+
rect_frac: Tuple[float, float, float, float]
|
|
55
|
+
#: "vertical" for a right/left bar, "horizontal" for a top/bottom one.
|
|
56
|
+
orientation: str
|
|
57
|
+
#: Which edge of the host panel this bar sits against: "right", "left", "top" or
|
|
58
|
+
#: "bottom". Distinct from ``orientation`` because a caller can ask for either
|
|
59
|
+
#: independently, as matplotlib's own ``colorbar()`` does.
|
|
60
|
+
location: str
|
|
61
|
+
#: Colormap name, resolved (never ``None``) at ``colorbar()`` call time.
|
|
62
|
+
cmap: str
|
|
63
|
+
#: A concrete ``matplotlib.colors.Normalize`` (or subclass) instance with real
|
|
64
|
+
#: ``vmin``/``vmax`` already resolved.
|
|
65
|
+
norm: Any
|
|
66
|
+
#: Explicit tick positions, or ``None`` to auto-locate from ``norm``'s type.
|
|
67
|
+
ticks: Optional[Any] = None
|
|
68
|
+
#: A tick label format (matplotlib ``Formatter``, format string, or ``None`` to
|
|
69
|
+
#: auto-format from the locator).
|
|
70
|
+
format: Optional[Any] = None
|
|
71
|
+
#: The colorbar's own axis label (``Colorbar.set_label``), or ``None``.
|
|
72
|
+
label: Optional[str] = None
|
|
73
|
+
#: Matplotlib-parity placement knobs, stored for the headless reconstruction (which
|
|
74
|
+
#: rebuilds a real matplotlib colorbar and can honour them precisely); the live
|
|
75
|
+
#: renderer's own bar geometry does not re-derive a precise aspect-ratio width from
|
|
76
|
+
#: these -- see ``colorbar()``'s docstring.
|
|
77
|
+
fraction: float = 0.15
|
|
78
|
+
pad: float = 0.05
|
|
79
|
+
shrink: float = 1.0
|
|
80
|
+
aspect: float = 20.0
|
|
81
|
+
#: When True, the bar sits *inside* the host panel's own rect (over the plotted
|
|
82
|
+
#: content, near ``location``'s edge) instead of shrinking the panel to make room
|
|
83
|
+
#: outside it. Ticks/label flip to point inward, toward the panel's centre, since
|
|
84
|
+
#: there is no room outside the panel for them to point into.
|
|
85
|
+
inset: bool = False
|
|
86
|
+
|
|
87
|
+
|
|
32
88
|
class Panel:
|
|
33
89
|
"""One plotting region: its scene, camera, interaction state, and window rectangle."""
|
|
34
90
|
|
|
@@ -64,6 +120,30 @@ class Panel:
|
|
|
64
120
|
#: panel that is never animated costs one object and no frame time.
|
|
65
121
|
self.timeline = Timeline()
|
|
66
122
|
|
|
123
|
+
#: Colorbars drawn against this panel's edges. Metadata only -- never a
|
|
124
|
+
#: :class:`Panel` of its own, never registered on ``fig.panels`` -- so a
|
|
125
|
+
#: colorbar can never become the active/pannable axes. See
|
|
126
|
+
#: :class:`ColorbarSpec` for why.
|
|
127
|
+
self.colorbars: List["ColorbarSpec"] = []
|
|
128
|
+
|
|
129
|
+
#: This panel's own axis names and axes title.
|
|
130
|
+
#:
|
|
131
|
+
#: Per panel for the same reason the cameras and scenes are: a split figure plots
|
|
132
|
+
#: four different quantities and has to be able to *name* them four different
|
|
133
|
+
#: ways. These were figure-global until they lived here, so a 2x2 grid could only
|
|
134
|
+
#: ever carry one x-name, one y-name and one title between all four panels --
|
|
135
|
+
#: whichever call ran last won, and the other three axes went unlabelled.
|
|
136
|
+
#:
|
|
137
|
+
#: The engine forwards ``xlabel``/``ylabel`` to the active panel's copy (the same
|
|
138
|
+
#: delegation ``scene``/``camera``/``cache`` use), so ``gplt.xlabel(...)`` keeps
|
|
139
|
+
#: writing "the current axes' x-name" and every existing single-panel caller is
|
|
140
|
+
#: unaffected. ``title`` is *not* forwarded that way -- ``engine.title`` is also
|
|
141
|
+
#: the GLFW window caption and is assigned in ``__init__`` before any panel
|
|
142
|
+
#: exists -- so ``set_title`` writes both, and readers prefer this one.
|
|
143
|
+
self.xlabel: str = ""
|
|
144
|
+
self.ylabel: str = ""
|
|
145
|
+
self.title: str = ""
|
|
146
|
+
|
|
67
147
|
#: Explicit dimensionality: 2, 3, or ``None`` for "infer from the layers".
|
|
68
148
|
#:
|
|
69
149
|
#: None is the default and reproduces GLPlot's historical behaviour exactly — a
|