kaxe 1.4.4.dev12__tar.gz → 1.4.4.dev14__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.4.4.dev12/src/kaxe.egg-info → kaxe-1.4.4.dev14}/PKG-INFO +1 -1
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/pyproject.toml +1 -1
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/axis.py +1 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/helper.py +31 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/svg.py +74 -14
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/window.py +36 -3
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d2/function.py +2 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d2/point.py +21 -12
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/grid.py +25 -2
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14/src/kaxe.egg-info}/PKG-INFO +1 -1
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/LICENSE +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/MANIFEST.in +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/README.md +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/setup.cfg +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/__init__.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/chart/__init__.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/chart/bar.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/chart/box.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/chart/pie.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/chart/qqplot.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/__init__.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/color.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/d3/backend.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/d3/camera.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/d3/helper.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/d3/hud.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/d3/objects/__init__.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/d3/objects/color.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/d3/objects/line.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/d3/objects/point.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/d3/objects/pointer.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/d3/objects/triangle.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/d3/openglrender.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/d3/translator.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/draw.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/fileloader.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/legend.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/line.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/marker.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/profiler.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/round.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/shapes.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/styles.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/svg_pdf.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/symbol.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/core/text.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/data/__init__.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/data/excel.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/__init__.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/_lazy.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d2/__init__.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d2/arrow.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d2/bubble.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d2/contour.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d2/equation.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d2/fill.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d2/map.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d2/parameter.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d2/pillar.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d3/__init__.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d3/base.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d3/function.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d3/mesh.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d3/point.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/d3/potato.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/function.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/legend.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/mapdata.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/point.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/objects/text.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/__init__.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/_lazy.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/box.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/constants.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/d3/__init__.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/d3/axes.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/d3/geometry.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/d3/plot3d.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/d3/variants.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/double.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/empty.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/log.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/polar.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/standard.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/themes.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/zoom.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/plot/zoom_connector.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/__init__.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/__init__.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.bright-oblique.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.bright-roman.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.bright-semibold.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.bright-semiboldoblique.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.classical-serif-italic.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.concrete-bold.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.concrete-bolditalic.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.concrete-italic.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.concrete-roman.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-bold.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-boldoblique.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-demi-condensed-demicondensed.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-medium.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-oblique.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.serif-bold.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.serif-bolditalic.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.serif-extra-boldslanted.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.serif-extra-romanslanted.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.serif-italic.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.serif-roman.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.serif-upright-italic-uprightitalic.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-bold.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-bolditalic.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-italic.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-light.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-lightoblique.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-regular.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-variable-width-italic.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-variable-width-medium.ttf +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/readme.txt +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/logo-small.png +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/symbolcross.png +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/symboldonut.png +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/symbollollipop.png +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/symboltriangle.png +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe.egg-info/SOURCES.txt +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe.egg-info/dependency_links.txt +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe.egg-info/requires.txt +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe.egg-info/top_level.txt +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/tests/test.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/tests/test2.py +0 -0
- {kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/tests/test3.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kaxe
|
|
3
|
-
Version: 1.4.4.
|
|
3
|
+
Version: 1.4.4.dev14
|
|
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
|
|
@@ -127,6 +127,37 @@ def insideBox(box, point):
|
|
|
127
127
|
return True
|
|
128
128
|
|
|
129
129
|
|
|
130
|
+
def segment_break_threshold(parent) -> float:
|
|
131
|
+
"""Pixel y delta above which a new polyline segment should start."""
|
|
132
|
+
box = parent.windowBox
|
|
133
|
+
return (box[3] - box[1]) * 0.45
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def should_break_polyline_segment(
|
|
137
|
+
p1: tuple[float, float],
|
|
138
|
+
p2: tuple[float, float],
|
|
139
|
+
parent,
|
|
140
|
+
) -> bool:
|
|
141
|
+
"""Break when a segment looks like a wrap-around, not a normal diagonal."""
|
|
142
|
+
dx = abs(p2[0] - p1[0])
|
|
143
|
+
dy = abs(p2[1] - p1[1])
|
|
144
|
+
if dy <= segment_break_threshold(parent):
|
|
145
|
+
return False
|
|
146
|
+
return dy > dx * 1.5
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def plot_window_clip_rect_svg(plot) -> tuple[float, float, float, float]:
|
|
150
|
+
"""Return plot windowBox as an SVG clip rect (x, y, width, height), y-down."""
|
|
151
|
+
box = plot.windowBox
|
|
152
|
+
canvas_h = plot.getSize()[1]
|
|
153
|
+
return (
|
|
154
|
+
float(box[0]),
|
|
155
|
+
float(canvas_h - box[3]),
|
|
156
|
+
float(box[2] - box[0]),
|
|
157
|
+
float(box[3] - box[1]),
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
130
161
|
def shell(a):
|
|
131
162
|
def __shell__():
|
|
132
163
|
return a
|
|
@@ -57,6 +57,9 @@ class SvgDocument:
|
|
|
57
57
|
self._width, self._height = int(size[0]), int(size[1])
|
|
58
58
|
self._elements: list[ET.Element] = []
|
|
59
59
|
self._fondi_font_css: Optional[str] = None
|
|
60
|
+
self._clip_defs: list[ET.Element] = []
|
|
61
|
+
self._clip_counter = 0
|
|
62
|
+
self._active_group: Optional[ET.Element] = None
|
|
60
63
|
|
|
61
64
|
@property
|
|
62
65
|
def height(self) -> int:
|
|
@@ -69,12 +72,48 @@ class SvgDocument:
|
|
|
69
72
|
def flip_y(self, y: float) -> float:
|
|
70
73
|
return flip_y(y, self._height)
|
|
71
74
|
|
|
75
|
+
def _register_clip_rect(self, x: float, y: float, width: float, height: float) -> str:
|
|
76
|
+
clip_id = f"kaxe-clip-{self._clip_counter}"
|
|
77
|
+
self._clip_counter += 1
|
|
78
|
+
clip_path = ET.Element(
|
|
79
|
+
f"{{{SVG_NS}}}clipPath",
|
|
80
|
+
{"id": clip_id},
|
|
81
|
+
)
|
|
82
|
+
ET.SubElement(
|
|
83
|
+
clip_path,
|
|
84
|
+
f"{{{SVG_NS}}}rect",
|
|
85
|
+
{
|
|
86
|
+
"x": str(round(x, 3)),
|
|
87
|
+
"y": str(round(y, 3)),
|
|
88
|
+
"width": str(round(width, 3)),
|
|
89
|
+
"height": str(round(height, 3)),
|
|
90
|
+
},
|
|
91
|
+
)
|
|
92
|
+
self._clip_defs.append(clip_path)
|
|
93
|
+
return clip_id
|
|
94
|
+
|
|
95
|
+
def push_clip_layer(self, x: float, y: float, width: float, height: float) -> None:
|
|
96
|
+
"""Clip subsequent elements to a rectangle in SVG top-down coordinates."""
|
|
97
|
+
clip_id = self._register_clip_rect(x, y, width, height)
|
|
98
|
+
group = ET.Element(
|
|
99
|
+
f"{{{SVG_NS}}}g",
|
|
100
|
+
{"clip-path": f"url(#{clip_id})"},
|
|
101
|
+
)
|
|
102
|
+
self._elements.append(group)
|
|
103
|
+
self._active_group = group
|
|
104
|
+
|
|
105
|
+
def pop_clip_layer(self) -> None:
|
|
106
|
+
self._active_group = None
|
|
107
|
+
|
|
72
108
|
def add_element(self, tag: str, attribs: dict[str, Any]) -> ET.Element:
|
|
73
109
|
el = ET.Element(
|
|
74
110
|
f"{{{SVG_NS}}}{tag}",
|
|
75
111
|
{k: str(v) for k, v in attribs.items() if v is not None},
|
|
76
112
|
)
|
|
77
|
-
self.
|
|
113
|
+
if self._active_group is not None:
|
|
114
|
+
self._active_group.append(el)
|
|
115
|
+
else:
|
|
116
|
+
self._elements.append(el)
|
|
78
117
|
return el
|
|
79
118
|
|
|
80
119
|
def add_rect(
|
|
@@ -285,9 +324,11 @@ class SvgDocument:
|
|
|
285
324
|
rotate: float = 0,
|
|
286
325
|
rotate_center: Optional[tuple[float, float]] = None,
|
|
287
326
|
) -> None:
|
|
288
|
-
"""Place an image; y is in kaxe coords (y-up)
|
|
327
|
+
"""Place an image; y is in kaxe coords (y-up) unless y_coord='svg_top'."""
|
|
289
328
|
href = pil_to_data_uri(img)
|
|
290
|
-
if y_coord == "
|
|
329
|
+
if y_coord == "svg_top":
|
|
330
|
+
svg_top = y
|
|
331
|
+
elif y_coord == "top":
|
|
291
332
|
svg_top = self.flip_y(y)
|
|
292
333
|
else:
|
|
293
334
|
svg_top = self.flip_y(y) - img.height
|
|
@@ -347,7 +388,10 @@ class SvgDocument:
|
|
|
347
388
|
group = ET.Element(f"{{{SVG_NS}}}g", {"transform": transform})
|
|
348
389
|
for child in list(inner):
|
|
349
390
|
group.append(copy.deepcopy(child))
|
|
350
|
-
self.
|
|
391
|
+
if self._active_group is not None:
|
|
392
|
+
self._active_group.append(group)
|
|
393
|
+
else:
|
|
394
|
+
self._elements.append(group)
|
|
351
395
|
|
|
352
396
|
def serialize(self) -> str:
|
|
353
397
|
root = ET.Element(
|
|
@@ -359,15 +403,22 @@ class SvgDocument:
|
|
|
359
403
|
"viewBox": f"0 0 {self._width} {self._height}",
|
|
360
404
|
},
|
|
361
405
|
)
|
|
362
|
-
if self._fondi_font_css is not None:
|
|
406
|
+
if self._fondi_font_css is not None or self._clip_defs:
|
|
363
407
|
defs = ET.SubElement(root, f"{{{SVG_NS}}}defs")
|
|
364
|
-
|
|
365
|
-
|
|
408
|
+
if self._fondi_font_css is not None:
|
|
409
|
+
style = ET.SubElement(defs, f"{{{SVG_NS}}}style")
|
|
410
|
+
style.text = self._fondi_font_css
|
|
411
|
+
for clip_el in self._clip_defs:
|
|
412
|
+
defs.append(clip_el)
|
|
366
413
|
for el in self._elements:
|
|
367
414
|
root.append(el)
|
|
368
415
|
body = ET.tostring(root, encoding="unicode")
|
|
369
|
-
|
|
370
|
-
|
|
416
|
+
try:
|
|
417
|
+
from fondi.backends.svg import _ascii_safe_svg_markup
|
|
418
|
+
|
|
419
|
+
body = _ascii_safe_svg_markup(body)
|
|
420
|
+
except ImportError:
|
|
421
|
+
pass
|
|
371
422
|
return '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n' + body
|
|
372
423
|
|
|
373
424
|
def to_pdf(self, fname: Optional[Union[str, BytesIO]] = None) -> bytes:
|
|
@@ -408,14 +459,23 @@ def embed_svg_children(
|
|
|
408
459
|
children: list[ET.Element],
|
|
409
460
|
tx: float,
|
|
410
461
|
ty: float,
|
|
462
|
+
*,
|
|
463
|
+
clip_rect: Optional[tuple[float, float, float, float]] = None,
|
|
411
464
|
) -> None:
|
|
412
|
-
"""Embed copied SVG children at top-left offset (SVG y-down coordinates).
|
|
465
|
+
"""Embed copied SVG children at top-left offset (SVG y-down coordinates).
|
|
466
|
+
|
|
467
|
+
clip_rect is optional (x, y, width, height) in the embedded cell's local SVG space.
|
|
468
|
+
"""
|
|
413
469
|
if not children:
|
|
414
470
|
return
|
|
415
|
-
|
|
416
|
-
f"{{
|
|
417
|
-
|
|
418
|
-
|
|
471
|
+
attribs: dict[str, str] = {
|
|
472
|
+
"transform": f"translate({round(tx, 3)},{round(ty, 3)})",
|
|
473
|
+
}
|
|
474
|
+
if clip_rect is not None:
|
|
475
|
+
cx, cy, cw, ch = clip_rect
|
|
476
|
+
clip_id = doc._register_clip_rect(cx, cy, cw, ch)
|
|
477
|
+
attribs["clip-path"] = f"url(#{clip_id})"
|
|
478
|
+
group = ET.Element(f"{{{SVG_NS}}}g", attribs)
|
|
419
479
|
for child in children:
|
|
420
480
|
group.append(copy.deepcopy(child))
|
|
421
481
|
doc._elements.append(group)
|
|
@@ -418,7 +418,8 @@ class Window(AttrObject):
|
|
|
418
418
|
self.__includeAllAgain__()
|
|
419
419
|
|
|
420
420
|
|
|
421
|
-
self.
|
|
421
|
+
self.shape_layers = sorted(self.shapes, key=lambda x: x[1])
|
|
422
|
+
self.shapes = [i[0] for i in self.shape_layers]
|
|
422
423
|
|
|
423
424
|
# add style padding
|
|
424
425
|
self.addPaddingCondition(*self.getAttr('outerPadding'))
|
|
@@ -494,7 +495,23 @@ class Window(AttrObject):
|
|
|
494
495
|
background = shapes.Rectangle(0, 0, winSize[0], winSize[1], color=self.getAttr('backgroundColor'))
|
|
495
496
|
background.draw(doc)
|
|
496
497
|
|
|
497
|
-
|
|
498
|
+
box = self.windowBox
|
|
499
|
+
doc.push_clip_layer(
|
|
500
|
+
box[0],
|
|
501
|
+
winSize[1] - box[3],
|
|
502
|
+
box[2] - box[0],
|
|
503
|
+
box[3] - box[1],
|
|
504
|
+
)
|
|
505
|
+
for shape, z in getattr(self, "shape_layers", [(s, 0) for s in self.shapes]):
|
|
506
|
+
if z >= 2:
|
|
507
|
+
continue
|
|
508
|
+
shape.draw(doc)
|
|
509
|
+
if self.showProgressBar: pbar.update()
|
|
510
|
+
doc.pop_clip_layer()
|
|
511
|
+
|
|
512
|
+
for shape, z in getattr(self, "shape_layers", [(s, 0) for s in self.shapes]):
|
|
513
|
+
if z < 2:
|
|
514
|
+
continue
|
|
498
515
|
shape.draw(doc)
|
|
499
516
|
if self.showProgressBar: pbar.update()
|
|
500
517
|
|
|
@@ -524,7 +541,23 @@ class Window(AttrObject):
|
|
|
524
541
|
background = shapes.Rectangle(0, 0, winSize[0], winSize[1], color=self.getAttr('backgroundColor'))
|
|
525
542
|
background.draw(doc)
|
|
526
543
|
|
|
527
|
-
|
|
544
|
+
box = self.windowBox
|
|
545
|
+
doc.push_clip_layer(
|
|
546
|
+
box[0],
|
|
547
|
+
winSize[1] - box[3],
|
|
548
|
+
box[2] - box[0],
|
|
549
|
+
box[3] - box[1],
|
|
550
|
+
)
|
|
551
|
+
for shape, z in getattr(self, "shape_layers", [(s, 0) for s in self.shapes]):
|
|
552
|
+
if z >= 2:
|
|
553
|
+
continue
|
|
554
|
+
shape.draw(doc)
|
|
555
|
+
if self.showProgressBar: pbar.update()
|
|
556
|
+
doc.pop_clip_layer()
|
|
557
|
+
|
|
558
|
+
for shape, z in getattr(self, "shape_layers", [(s, 0) for s in self.shapes]):
|
|
559
|
+
if z < 2:
|
|
560
|
+
continue
|
|
528
561
|
shape.draw(doc)
|
|
529
562
|
if self.showProgressBar: pbar.update()
|
|
530
563
|
|
|
@@ -130,6 +130,8 @@ class Function2D:
|
|
|
130
130
|
)
|
|
131
131
|
|
|
132
132
|
if parent.inside(px, py) or parent.inside(*self.__lastPoint__):
|
|
133
|
+
if should_break_polyline_segment(self.__lastPoint__, (px, py), parent):
|
|
134
|
+
self.lineSegments.append([])
|
|
133
135
|
self.lineSegments[-1].append(parent.clamp(self.__lastPoint__[0], self.__lastPoint__[1]))
|
|
134
136
|
self.lineSegments[-1].append(parent.clamp(px, py))
|
|
135
137
|
else:
|
|
@@ -136,25 +136,34 @@ class Points2D:
|
|
|
136
136
|
|
|
137
137
|
|
|
138
138
|
def __finalizeConnectedLine__(self, parent, line_width):
|
|
139
|
-
|
|
139
|
+
segments = [[]]
|
|
140
140
|
for x_val, y_val in zip(self.x, self.y):
|
|
141
141
|
px, py = parent.pixel(x_val, y_val)
|
|
142
142
|
if px is None or py is None:
|
|
143
143
|
continue
|
|
144
144
|
if not parent.inside(px, py):
|
|
145
145
|
continue
|
|
146
|
-
|
|
146
|
+
point = parent.clamp(px, py)
|
|
147
|
+
if segments[-1] and should_break_polyline_segment(segments[-1][-1], point, parent):
|
|
148
|
+
segments.append([])
|
|
149
|
+
segments[-1].append(point)
|
|
147
150
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
151
|
+
for points in segments:
|
|
152
|
+
if len(points) < 2:
|
|
153
|
+
continue
|
|
154
|
+
if len(points) == 2:
|
|
155
|
+
x0, y0 = points[0]
|
|
156
|
+
x1, y1 = points[1]
|
|
157
|
+
line = shapes.Line(
|
|
158
|
+
x0, y0, x1, y1,
|
|
159
|
+
color=self.color,
|
|
160
|
+
width=line_width,
|
|
161
|
+
batch=self.batch,
|
|
162
|
+
center=True,
|
|
163
|
+
)
|
|
164
|
+
self.lines.append(line)
|
|
165
|
+
continue
|
|
166
|
+
shapes.LineSegment(points, color=self.color, width=line_width, batch=self.batch)
|
|
158
167
|
|
|
159
168
|
|
|
160
169
|
def draw(self, *args, **kwargs):
|
|
@@ -94,6 +94,7 @@ class Grid(AttrObject):
|
|
|
94
94
|
"""
|
|
95
95
|
|
|
96
96
|
self.__legends = legends
|
|
97
|
+
self._invalidate_bake_cache()
|
|
97
98
|
|
|
98
99
|
|
|
99
100
|
def theme(self, theme):
|
|
@@ -110,10 +111,23 @@ class Grid(AttrObject):
|
|
|
110
111
|
plot.__included__ = []
|
|
111
112
|
plot.__baked__ = False
|
|
112
113
|
plot.__bakedImage__ = False
|
|
114
|
+
if hasattr(plot, "shape_layers"):
|
|
115
|
+
plot.shape_layers = []
|
|
116
|
+
for axis in (getattr(plot, "firstAxis", None), getattr(plot, "secondAxis", None)):
|
|
117
|
+
if axis is not None:
|
|
118
|
+
axis.markers = []
|
|
119
|
+
axis.title = None
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _invalidate_bake_cache(self):
|
|
123
|
+
self.__bakedImage__ = False
|
|
124
|
+
self.__bakedSvg__ = None
|
|
125
|
+
self.__bakedPdf__ = None
|
|
113
126
|
|
|
114
127
|
|
|
115
128
|
def _apply_cell_styles(self, plot, cellWidth, cellHeight):
|
|
116
129
|
self._reset_cell_bake_state(plot)
|
|
130
|
+
plot.showLegend = False
|
|
117
131
|
plot.style(
|
|
118
132
|
width=cellWidth,
|
|
119
133
|
height=cellHeight,
|
|
@@ -315,12 +329,18 @@ class Grid(AttrObject):
|
|
|
315
329
|
xml = plot.__ioBytes.read().decode("utf-8")
|
|
316
330
|
root = parse_svg_root(xml)
|
|
317
331
|
children, fondi_css = extract_svg_children(root)
|
|
318
|
-
embed_svg_children(
|
|
332
|
+
embed_svg_children(
|
|
333
|
+
doc,
|
|
334
|
+
children,
|
|
335
|
+
px,
|
|
336
|
+
py,
|
|
337
|
+
clip_rect=plot_window_clip_rect_svg(plot),
|
|
338
|
+
)
|
|
319
339
|
merge_fondi_css(doc, fondi_css)
|
|
320
340
|
else:
|
|
321
341
|
plot.__ioBytes.seek(0)
|
|
322
342
|
img = Image.open(plot.__ioBytes)
|
|
323
|
-
doc.add_image(img, px, py, y_coord="
|
|
343
|
+
doc.add_image(img, px, py, y_coord="svg_top")
|
|
324
344
|
|
|
325
345
|
x += cellWidth + gapcol
|
|
326
346
|
|
|
@@ -364,6 +384,7 @@ class Grid(AttrObject):
|
|
|
364
384
|
|
|
365
385
|
"""
|
|
366
386
|
|
|
387
|
+
self._invalidate_bake_cache()
|
|
367
388
|
self.grid.append(row)
|
|
368
389
|
|
|
369
390
|
|
|
@@ -377,6 +398,8 @@ class Grid(AttrObject):
|
|
|
377
398
|
A list of plots to be added as a column in the grid.
|
|
378
399
|
"""
|
|
379
400
|
|
|
401
|
+
self._invalidate_bake_cache()
|
|
402
|
+
|
|
380
403
|
for i, plot in enumerate(column):
|
|
381
404
|
|
|
382
405
|
if i >= len(self.grid):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kaxe
|
|
3
|
-
Version: 1.4.4.
|
|
3
|
+
Version: 1.4.4.dev14
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.bright-roman.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.serif-bold.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.serif-italic.ttf
RENAMED
|
File without changes
|
{kaxe-1.4.4.dev12 → kaxe-1.4.4.dev14}/src/kaxe/resources/computer-modern-family/cmu.serif-roman.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|