kaxe 1.8.1.dev2__tar.gz → 1.8.1.dev4__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.
- {kaxe-1.8.1.dev2/src/kaxe.egg-info → kaxe-1.8.1.dev4}/PKG-INFO +39 -4
- kaxe-1.8.1.dev4/README.md +88 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/pyproject.toml +1 -1
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/window.py +33 -4
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/d3/plot3d.py +4 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/grid.py +33 -4
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/viewer/client.py +11 -2
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/viewer/server.py +4 -0
- kaxe-1.8.1.dev4/src/kaxe/viewer/window.py +582 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4/src/kaxe.egg-info}/PKG-INFO +39 -4
- kaxe-1.8.1.dev4/tests/test_viewer.py +295 -0
- kaxe-1.8.1.dev2/README.md +0 -53
- kaxe-1.8.1.dev2/src/kaxe/viewer/window.py +0 -339
- kaxe-1.8.1.dev2/tests/test_viewer.py +0 -140
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/LICENSE +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/MANIFEST.in +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/setup.cfg +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/__init__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/__main__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/_require_3d.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/_require_viewer.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/chart/__init__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/chart/bar.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/chart/box.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/chart/pie.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/chart/qqplot.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/cli.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/__init__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/axis.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/bounds.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/color.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/d3/backend.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/d3/camera.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/d3/helper.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/d3/hud.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/d3/objects/__init__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/d3/objects/color.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/d3/objects/line.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/d3/objects/point.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/d3/objects/pointer.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/d3/objects/triangle.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/d3/openglrender.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/d3/translator.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/draw.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/fileloader.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/helper.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/ipython_display.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/legend.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/line.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/marker.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/palette.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/profiler.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/progress.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/round.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/shapes.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/styles.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/svg.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/svg_pdf.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/symbol.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/text.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/core/thin.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/data/__init__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/data/excel.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/__init__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/_lazy.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d2/__init__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d2/arrow.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d2/bubble.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d2/contour.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d2/equation.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d2/fill.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d2/function.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d2/guide_grid.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d2/inequality.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d2/map.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d2/parameter.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d2/pillar.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d2/point.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d3/__init__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d3/base.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d3/function.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d3/mesh.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d3/point.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/d3/potato.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/function.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/legend.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/mapdata.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/point.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/objects/text.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/__init__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/_lazy.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/box.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/constants.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/d3/__init__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/d3/axes.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/d3/geometry.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/d3/variants.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/double.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/empty.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/log.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/polar.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/standard.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/themes.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/zoom.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/plot/zoom_connector.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/project/__init__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/project/codec.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/project/context.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/project/document.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/project/registry.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/project/sample.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/project/sampled_curve.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/project/serializers.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/project/window.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/__init__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/__init__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.bright-oblique.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.bright-roman.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.bright-semibold.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.bright-semiboldoblique.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.classical-serif-italic.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.concrete-bold.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.concrete-bolditalic.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.concrete-italic.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.concrete-roman.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-bold.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-boldoblique.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-demi-condensed-demicondensed.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-medium.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-oblique.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.serif-bold.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.serif-bolditalic.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.serif-extra-boldslanted.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.serif-extra-romanslanted.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.serif-italic.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.serif-roman.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.serif-upright-italic-uprightitalic.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-bold.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-bolditalic.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-italic.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-light.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-lightoblique.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-regular.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-variable-width-italic.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-variable-width-medium.ttf +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/computer-modern-family/readme.txt +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/resources/logo-small.png +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/viewer/__init__.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe/viewer/cli.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe.egg-info/SOURCES.txt +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe.egg-info/dependency_links.txt +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe.egg-info/entry_points.txt +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe.egg-info/requires.txt +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/src/kaxe.egg-info/top_level.txt +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/tests/test.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/tests/test2.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/tests/test3.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/tests/test_4.py +0 -0
- {kaxe-1.8.1.dev2 → kaxe-1.8.1.dev4}/tests/test_5.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kaxe
|
|
3
|
-
Version: 1.8.1.
|
|
3
|
+
Version: 1.8.1.dev4
|
|
4
4
|
Summary: A small graphing tool for functions, points, equations and more
|
|
5
5
|
Author-email: Valter Yde Daugberg <valteryde@hotmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/valteryde/kaxe
|
|
@@ -44,9 +44,9 @@ Documentation: [kaxe.readthedocs.io](https://kaxe.readthedocs.io/en/latest/)
|
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
46
|
pip install kaxe # 2D plotting (default)
|
|
47
|
-
pip install kaxe[
|
|
48
|
-
pip install kaxe[
|
|
49
|
-
pip install kaxe[
|
|
47
|
+
pip install kaxe[viewer] # add interactive desktop viewer (pyglet)
|
|
48
|
+
pip install kaxe[3d] # add 3D plotting (OpenGL)
|
|
49
|
+
pip install kaxe[pdf] # add PDF export
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
## Quick example
|
|
@@ -59,10 +59,45 @@ plt.add(kaxe.Function2D(lambda x: x**2 - 4))
|
|
|
59
59
|
plt.add(kaxe.Points2D([1, 2, 3], [1, 4, 9]))
|
|
60
60
|
plt.theme(kaxe.Themes.A4Medium)
|
|
61
61
|
plt.title("$x^2 - 4$")
|
|
62
|
+
plt.show() # streams to viewer if open, or opens system viewer
|
|
62
63
|
plt.save("figure.png")
|
|
63
64
|
plt.save("figure.svg")
|
|
64
65
|
```
|
|
65
66
|
|
|
67
|
+
## Interactive Plot Viewer (Infinite Canvas)
|
|
68
|
+
|
|
69
|
+
Kaxe includes a dedicated, lightweight OpenGL workspace powered by [pyglet](https://pyglet.org) so you can arrange, inspect, and compare multiple plots on an infinite canvas without cluttering your desktop with preview windows.
|
|
70
|
+
|
|
71
|
+
1. **Start the viewer** in a terminal:
|
|
72
|
+
```bash
|
|
73
|
+
kaxe viewer
|
|
74
|
+
```
|
|
75
|
+
2. **Tag and show your plots**:
|
|
76
|
+
```python
|
|
77
|
+
# Tag plots with an ID to manage them on the board:
|
|
78
|
+
plt1 = kaxe.Plot().id("loss").title("Training Loss")
|
|
79
|
+
plt1.show()
|
|
80
|
+
|
|
81
|
+
plt2 = kaxe.Plot().id("accuracy").title("Validation Accuracy")
|
|
82
|
+
plt2.show()
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
When the viewer is open, `.show()` instantly streams plots to cards on your canvas. If you re-run code with the same ID, the card updates in-place and preserves previous runs as versions (`v1`, `v2`, etc.). If the viewer is closed, `.show()` automatically falls back to your operating system's default viewer.
|
|
86
|
+
|
|
87
|
+
**Canvas & Card Controls:**
|
|
88
|
+
* **Click & Drag on a Card**: Move that card freely across the canvas
|
|
89
|
+
* **Click & Drag on Empty Space**: Pan the camera across the workspace
|
|
90
|
+
* **Mouse Scroll**: Smooth zoom anchored to cursor
|
|
91
|
+
* **`[A]`**: Auto-arrange all cards in a neat row
|
|
92
|
+
* **`[Space]` or `[R]`**: Fit all cards on the canvas into view
|
|
93
|
+
* **`[1]`**: View canvas at 100% native pixel scale
|
|
94
|
+
* **`[←]` / `[→]`**: Cycle through versions (`v1`, `v2`, ...) of the selected card
|
|
95
|
+
* **`[Backspace]` / `[Delete]`**: Remove the selected card from the board
|
|
96
|
+
* **`[C]`** *(or Cmd/Ctrl+C)*: Copy selected plot to system clipboard
|
|
97
|
+
* **`[S]`** *(or Cmd/Ctrl+S)*: Save selected plot to timestamped PNG
|
|
98
|
+
* **`[H]`**: Toggle status & shortcuts HUD
|
|
99
|
+
|
|
100
|
+
|
|
66
101
|
See the [getting started guide](https://kaxe.readthedocs.io/en/latest/pages/start.html), [recipes](https://kaxe.readthedocs.io/en/latest/pages/recipes.html), [styling guide](https://kaxe.readthedocs.io/en/latest/pages/styling.html), and [export guide](https://kaxe.readthedocs.io/en/latest/pages/export.html) for the full API.
|
|
67
102
|
|
|
68
103
|
## Goals
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
|
|
2
|
+
# Kaxe
|
|
3
|
+
|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
Kaxe is a lightweight, pure-Python plotting library for publication-quality figures in LaTeX documents. Create plots and charts with a simple object-oriented API, style them for A4 pages, and export to PNG or SVG.
|
|
7
|
+
|
|
8
|
+
Documentation: [kaxe.readthedocs.io](https://kaxe.readthedocs.io/en/latest/)
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install kaxe # 2D plotting (default)
|
|
14
|
+
pip install kaxe[viewer] # add interactive desktop viewer (pyglet)
|
|
15
|
+
pip install kaxe[3d] # add 3D plotting (OpenGL)
|
|
16
|
+
pip install kaxe[pdf] # add PDF export
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick example
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
import kaxe
|
|
23
|
+
|
|
24
|
+
plt = kaxe.Plot([-5, 5, -5, 5])
|
|
25
|
+
plt.add(kaxe.Function2D(lambda x: x**2 - 4))
|
|
26
|
+
plt.add(kaxe.Points2D([1, 2, 3], [1, 4, 9]))
|
|
27
|
+
plt.theme(kaxe.Themes.A4Medium)
|
|
28
|
+
plt.title("$x^2 - 4$")
|
|
29
|
+
plt.show() # streams to viewer if open, or opens system viewer
|
|
30
|
+
plt.save("figure.png")
|
|
31
|
+
plt.save("figure.svg")
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Interactive Plot Viewer (Infinite Canvas)
|
|
35
|
+
|
|
36
|
+
Kaxe includes a dedicated, lightweight OpenGL workspace powered by [pyglet](https://pyglet.org) so you can arrange, inspect, and compare multiple plots on an infinite canvas without cluttering your desktop with preview windows.
|
|
37
|
+
|
|
38
|
+
1. **Start the viewer** in a terminal:
|
|
39
|
+
```bash
|
|
40
|
+
kaxe viewer
|
|
41
|
+
```
|
|
42
|
+
2. **Tag and show your plots**:
|
|
43
|
+
```python
|
|
44
|
+
# Tag plots with an ID to manage them on the board:
|
|
45
|
+
plt1 = kaxe.Plot().id("loss").title("Training Loss")
|
|
46
|
+
plt1.show()
|
|
47
|
+
|
|
48
|
+
plt2 = kaxe.Plot().id("accuracy").title("Validation Accuracy")
|
|
49
|
+
plt2.show()
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
When the viewer is open, `.show()` instantly streams plots to cards on your canvas. If you re-run code with the same ID, the card updates in-place and preserves previous runs as versions (`v1`, `v2`, etc.). If the viewer is closed, `.show()` automatically falls back to your operating system's default viewer.
|
|
53
|
+
|
|
54
|
+
**Canvas & Card Controls:**
|
|
55
|
+
* **Click & Drag on a Card**: Move that card freely across the canvas
|
|
56
|
+
* **Click & Drag on Empty Space**: Pan the camera across the workspace
|
|
57
|
+
* **Mouse Scroll**: Smooth zoom anchored to cursor
|
|
58
|
+
* **`[A]`**: Auto-arrange all cards in a neat row
|
|
59
|
+
* **`[Space]` or `[R]`**: Fit all cards on the canvas into view
|
|
60
|
+
* **`[1]`**: View canvas at 100% native pixel scale
|
|
61
|
+
* **`[←]` / `[→]`**: Cycle through versions (`v1`, `v2`, ...) of the selected card
|
|
62
|
+
* **`[Backspace]` / `[Delete]`**: Remove the selected card from the board
|
|
63
|
+
* **`[C]`** *(or Cmd/Ctrl+C)*: Copy selected plot to system clipboard
|
|
64
|
+
* **`[S]`** *(or Cmd/Ctrl+S)*: Save selected plot to timestamped PNG
|
|
65
|
+
* **`[H]`**: Toggle status & shortcuts HUD
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
See the [getting started guide](https://kaxe.readthedocs.io/en/latest/pages/start.html), [recipes](https://kaxe.readthedocs.io/en/latest/pages/recipes.html), [styling guide](https://kaxe.readthedocs.io/en/latest/pages/styling.html), and [export guide](https://kaxe.readthedocs.io/en/latest/pages/export.html) for the full API.
|
|
69
|
+
|
|
70
|
+
## Goals
|
|
71
|
+
|
|
72
|
+
Kaxe was made to create simple, aesthetic graphs for articles, reports, and other academic work in LaTeX:
|
|
73
|
+
|
|
74
|
+
* Plots that fit the look of LaTeX documents (Computer Modern math via [fondi](https://github.com/valteryde/fondi))
|
|
75
|
+
* A straightforward object-oriented interface: create a window, add objects, style, save
|
|
76
|
+
|
|
77
|
+
## Examples of plots
|
|
78
|
+
|
|
79
|
+

|
|
80
|
+

|
|
81
|
+

|
|
82
|
+

|
|
83
|
+

|
|
84
|
+

|
|
85
|
+

|
|
86
|
+

|
|
87
|
+

|
|
88
|
+

|
|
@@ -647,25 +647,54 @@ class Window(AttrObject):
|
|
|
647
647
|
logging.info('Total time to save {}s'.format(str(round(time.time() - totStartTime, 4))))
|
|
648
648
|
|
|
649
649
|
|
|
650
|
-
def
|
|
650
|
+
def id(self, plot_id: str):
|
|
651
|
+
"""Assign a persistent identifier to this plot for the Kaxe Viewer."""
|
|
652
|
+
self.plot_id = str(plot_id)
|
|
653
|
+
return self
|
|
654
|
+
|
|
655
|
+
def show(self, id: Optional[str] = None):
|
|
651
656
|
"""
|
|
652
|
-
Show the current image using `Pillow.Image.Show`
|
|
657
|
+
Show the current image using `Pillow.Image.Show` or the Kaxe Viewer.
|
|
653
658
|
|
|
654
659
|
If a cached image is available, it will be used to save the file.
|
|
655
660
|
Otherwise, the image will be generated and then saved.
|
|
656
661
|
|
|
662
|
+
Parameters
|
|
663
|
+
----------
|
|
664
|
+
id : str, optional
|
|
665
|
+
Identifier for this plot when sent to the Kaxe Viewer canvas.
|
|
666
|
+
|
|
657
667
|
Examples
|
|
658
668
|
--------
|
|
659
|
-
>>> plt.show(
|
|
669
|
+
>>> plt.show()
|
|
670
|
+
>>> plt.show(id="my_graph_1")
|
|
660
671
|
"""
|
|
672
|
+
if id is not None:
|
|
673
|
+
self.plot_id = str(id)
|
|
674
|
+
|
|
661
675
|
data = to_png_bytes(self)
|
|
662
676
|
if is_notebook():
|
|
663
677
|
display_png_bytes(data)
|
|
664
|
-
elif try_show_in_viewer(
|
|
678
|
+
elif try_show_in_viewer(
|
|
679
|
+
data,
|
|
680
|
+
title=getattr(self, "titleText", ""),
|
|
681
|
+
plot_id=getattr(self, "plot_id", None),
|
|
682
|
+
):
|
|
665
683
|
return
|
|
666
684
|
else:
|
|
667
685
|
Image.open(BytesIO(data)).show()
|
|
668
686
|
|
|
687
|
+
def open(self, id: Optional[str] = None):
|
|
688
|
+
"""
|
|
689
|
+
Show the current image or stream to viewer (alias for show()).
|
|
690
|
+
|
|
691
|
+
Examples
|
|
692
|
+
--------
|
|
693
|
+
>>> plt.open()
|
|
694
|
+
>>> plt.open(id="my_graph_1")
|
|
695
|
+
"""
|
|
696
|
+
return self.show(id=id)
|
|
697
|
+
|
|
669
698
|
def _repr_png_(self):
|
|
670
699
|
if not is_notebook():
|
|
671
700
|
return None
|
|
@@ -547,6 +547,10 @@ class Plot3D(Plot3DAxesMixin, Window):
|
|
|
547
547
|
else:
|
|
548
548
|
self.save(None).show()
|
|
549
549
|
|
|
550
|
+
def open(self, gui=True):
|
|
551
|
+
"""Show the current plot (alias for show())."""
|
|
552
|
+
return self.show(gui=gui)
|
|
553
|
+
|
|
550
554
|
def title(self, firstAxis=None, secondAxis=None, thirdAxis=None):
|
|
551
555
|
"""
|
|
552
556
|
Adds title to the plot.
|
|
@@ -490,25 +490,54 @@ class Grid(AttrObject):
|
|
|
490
490
|
img.save(fname, format="png")
|
|
491
491
|
|
|
492
492
|
|
|
493
|
-
def
|
|
493
|
+
def id(self, plot_id: str):
|
|
494
|
+
"""Assign a persistent identifier to this grid for the Kaxe Viewer."""
|
|
495
|
+
self.plot_id = str(plot_id)
|
|
496
|
+
return self
|
|
497
|
+
|
|
498
|
+
def show(self, id: Optional[str] = None):
|
|
494
499
|
"""
|
|
495
|
-
Show the current image using `Pillow.Image.Show`
|
|
500
|
+
Show the current image using `Pillow.Image.Show` or the Kaxe Viewer.
|
|
496
501
|
|
|
497
502
|
If a cached image is available, it will be used to save the file.
|
|
498
503
|
Otherwise, the image will be generated and then saved.
|
|
499
504
|
|
|
505
|
+
Parameters
|
|
506
|
+
----------
|
|
507
|
+
id : str, optional
|
|
508
|
+
Identifier for this grid when sent to the Kaxe Viewer canvas.
|
|
509
|
+
|
|
500
510
|
Examples
|
|
501
511
|
--------
|
|
502
|
-
>>>
|
|
512
|
+
>>> grid.show()
|
|
513
|
+
>>> grid.show(id="my_grid_1")
|
|
503
514
|
"""
|
|
515
|
+
if id is not None:
|
|
516
|
+
self.plot_id = str(id)
|
|
517
|
+
|
|
504
518
|
data = to_png_bytes(self)
|
|
505
519
|
if is_notebook():
|
|
506
520
|
display_png_bytes(data)
|
|
507
|
-
elif try_show_in_viewer(
|
|
521
|
+
elif try_show_in_viewer(
|
|
522
|
+
data,
|
|
523
|
+
title="Grid",
|
|
524
|
+
plot_id=getattr(self, "plot_id", None),
|
|
525
|
+
):
|
|
508
526
|
return
|
|
509
527
|
else:
|
|
510
528
|
Image.open(BytesIO(data)).show()
|
|
511
529
|
|
|
530
|
+
def open(self, id: Optional[str] = None):
|
|
531
|
+
"""
|
|
532
|
+
Show the current grid or stream to viewer (alias for show()).
|
|
533
|
+
|
|
534
|
+
Examples
|
|
535
|
+
--------
|
|
536
|
+
>>> grid.open()
|
|
537
|
+
>>> grid.open(id="my_grid_1")
|
|
538
|
+
"""
|
|
539
|
+
return self.show(id=id)
|
|
540
|
+
|
|
512
541
|
def _repr_png_(self):
|
|
513
542
|
if not is_notebook():
|
|
514
543
|
return None
|
|
@@ -46,6 +46,7 @@ def is_viewer_active(port: Optional[int] = None, timeout: float = 0.03) -> bool:
|
|
|
46
46
|
def send_to_viewer(
|
|
47
47
|
data: bytes,
|
|
48
48
|
title: str = "",
|
|
49
|
+
plot_id: Optional[str] = None,
|
|
49
50
|
port: Optional[int] = None,
|
|
50
51
|
timeout: float = 2.0,
|
|
51
52
|
) -> bool:
|
|
@@ -58,9 +59,11 @@ def send_to_viewer(
|
|
|
58
59
|
|
|
59
60
|
url = f"http://127.0.0.1:{port}/show"
|
|
60
61
|
safe_title = urllib.parse.quote(title or "")
|
|
62
|
+
safe_id = urllib.parse.quote(plot_id or "")
|
|
61
63
|
headers = {
|
|
62
64
|
"Content-Type": "image/png",
|
|
63
65
|
"X-Kaxe-Title": safe_title,
|
|
66
|
+
"X-Kaxe-Id": safe_id,
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
req = urllib.request.Request(url, data=data, headers=headers, method="POST")
|
|
@@ -71,12 +74,18 @@ def send_to_viewer(
|
|
|
71
74
|
return False
|
|
72
75
|
|
|
73
76
|
|
|
74
|
-
def try_show_in_viewer(
|
|
77
|
+
def try_show_in_viewer(
|
|
78
|
+
data: bytes,
|
|
79
|
+
title: str = "",
|
|
80
|
+
plot_id: Optional[str] = None,
|
|
81
|
+
) -> bool:
|
|
75
82
|
"""Convenience helper: probe port and send image if viewer is alive.
|
|
76
83
|
|
|
77
84
|
Returns True if sent to viewer, False if fallback is needed.
|
|
78
85
|
"""
|
|
79
86
|
port = get_viewer_port()
|
|
80
87
|
if is_viewer_active(port):
|
|
81
|
-
|
|
88
|
+
if send_to_viewer(data, title=title, plot_id=plot_id, port=port):
|
|
89
|
+
print("[Kaxe] Plot streamed to viewer", flush=True)
|
|
90
|
+
return True
|
|
82
91
|
return False
|
|
@@ -40,9 +40,13 @@ class PlotRequestHandler(BaseHTTPRequestHandler):
|
|
|
40
40
|
raw_title = self.headers.get("X-Kaxe-Title", "")
|
|
41
41
|
title = urllib.parse.unquote(raw_title) if raw_title else ""
|
|
42
42
|
|
|
43
|
+
raw_id = self.headers.get("X-Kaxe-Id", "")
|
|
44
|
+
plot_id = urllib.parse.unquote(raw_id) if raw_id else ""
|
|
45
|
+
|
|
43
46
|
item: Dict[str, Any] = {
|
|
44
47
|
"data": img_bytes,
|
|
45
48
|
"title": title,
|
|
49
|
+
"plot_id": plot_id,
|
|
46
50
|
}
|
|
47
51
|
self.plot_queue.put(item)
|
|
48
52
|
|