kaxe 1.4.6.dev0__tar.gz → 1.4.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. {kaxe-1.4.6.dev0/src/kaxe.egg-info → kaxe-1.4.8}/PKG-INFO +1 -1
  2. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/pyproject.toml +1 -1
  3. kaxe-1.4.8/src/kaxe/core/bounds.py +143 -0
  4. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/d3/openglrender.py +2 -5
  5. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/window.py +16 -12
  6. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d2/function.py +82 -2
  7. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d3/function.py +94 -1
  8. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/function.py +6 -1
  9. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/polar.py +27 -2
  10. {kaxe-1.4.6.dev0 → kaxe-1.4.8/src/kaxe.egg-info}/PKG-INFO +1 -1
  11. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe.egg-info/SOURCES.txt +1 -0
  12. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/LICENSE +0 -0
  13. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/MANIFEST.in +0 -0
  14. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/README.md +0 -0
  15. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/setup.cfg +0 -0
  16. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/__init__.py +0 -0
  17. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/chart/__init__.py +0 -0
  18. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/chart/bar.py +0 -0
  19. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/chart/box.py +0 -0
  20. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/chart/pie.py +0 -0
  21. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/chart/qqplot.py +0 -0
  22. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/__init__.py +0 -0
  23. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/axis.py +0 -0
  24. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/color.py +0 -0
  25. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/d3/backend.py +0 -0
  26. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/d3/camera.py +0 -0
  27. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/d3/helper.py +0 -0
  28. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/d3/hud.py +0 -0
  29. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/d3/objects/__init__.py +0 -0
  30. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/d3/objects/color.py +0 -0
  31. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/d3/objects/line.py +0 -0
  32. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/d3/objects/point.py +0 -0
  33. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/d3/objects/pointer.py +0 -0
  34. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/d3/objects/triangle.py +0 -0
  35. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/d3/translator.py +0 -0
  36. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/draw.py +0 -0
  37. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/fileloader.py +0 -0
  38. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/helper.py +0 -0
  39. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/legend.py +0 -0
  40. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/line.py +0 -0
  41. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/marker.py +0 -0
  42. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/profiler.py +0 -0
  43. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/round.py +0 -0
  44. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/shapes.py +0 -0
  45. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/styles.py +0 -0
  46. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/svg.py +0 -0
  47. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/svg_pdf.py +0 -0
  48. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/symbol.py +0 -0
  49. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/core/text.py +0 -0
  50. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/data/__init__.py +0 -0
  51. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/data/excel.py +0 -0
  52. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/__init__.py +0 -0
  53. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/_lazy.py +0 -0
  54. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d2/__init__.py +0 -0
  55. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d2/arrow.py +0 -0
  56. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d2/bubble.py +0 -0
  57. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d2/contour.py +0 -0
  58. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d2/equation.py +0 -0
  59. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d2/fill.py +0 -0
  60. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d2/map.py +0 -0
  61. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d2/parameter.py +0 -0
  62. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d2/pillar.py +0 -0
  63. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d2/point.py +0 -0
  64. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d3/__init__.py +0 -0
  65. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d3/base.py +0 -0
  66. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d3/mesh.py +0 -0
  67. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d3/point.py +0 -0
  68. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/d3/potato.py +0 -0
  69. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/legend.py +0 -0
  70. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/mapdata.py +0 -0
  71. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/point.py +0 -0
  72. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/objects/text.py +0 -0
  73. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/__init__.py +0 -0
  74. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/_lazy.py +0 -0
  75. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/box.py +0 -0
  76. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/constants.py +0 -0
  77. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/d3/__init__.py +0 -0
  78. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/d3/axes.py +0 -0
  79. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/d3/geometry.py +0 -0
  80. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/d3/plot3d.py +0 -0
  81. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/d3/variants.py +0 -0
  82. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/double.py +0 -0
  83. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/empty.py +0 -0
  84. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/grid.py +0 -0
  85. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/log.py +0 -0
  86. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/standard.py +0 -0
  87. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/themes.py +0 -0
  88. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/zoom.py +0 -0
  89. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/plot/zoom_connector.py +0 -0
  90. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/__init__.py +0 -0
  91. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/__init__.py +0 -0
  92. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.bright-oblique.ttf +0 -0
  93. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.bright-roman.ttf +0 -0
  94. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.bright-semibold.ttf +0 -0
  95. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.bright-semiboldoblique.ttf +0 -0
  96. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.classical-serif-italic.ttf +0 -0
  97. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.concrete-bold.ttf +0 -0
  98. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.concrete-bolditalic.ttf +0 -0
  99. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.concrete-italic.ttf +0 -0
  100. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.concrete-roman.ttf +0 -0
  101. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-bold.ttf +0 -0
  102. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-boldoblique.ttf +0 -0
  103. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-demi-condensed-demicondensed.ttf +0 -0
  104. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-medium.ttf +0 -0
  105. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-oblique.ttf +0 -0
  106. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.serif-bold.ttf +0 -0
  107. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.serif-bolditalic.ttf +0 -0
  108. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.serif-extra-boldslanted.ttf +0 -0
  109. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.serif-extra-romanslanted.ttf +0 -0
  110. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.serif-italic.ttf +0 -0
  111. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.serif-roman.ttf +0 -0
  112. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.serif-upright-italic-uprightitalic.ttf +0 -0
  113. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-bold.ttf +0 -0
  114. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-bolditalic.ttf +0 -0
  115. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-italic.ttf +0 -0
  116. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-light.ttf +0 -0
  117. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-lightoblique.ttf +0 -0
  118. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-regular.ttf +0 -0
  119. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-variable-width-italic.ttf +0 -0
  120. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-variable-width-medium.ttf +0 -0
  121. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/computer-modern-family/readme.txt +0 -0
  122. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/logo-small.png +0 -0
  123. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/symbolcross.png +0 -0
  124. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/symboldonut.png +0 -0
  125. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/symbollollipop.png +0 -0
  126. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe/resources/symboltriangle.png +0 -0
  127. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe.egg-info/dependency_links.txt +0 -0
  128. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe.egg-info/requires.txt +0 -0
  129. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/src/kaxe.egg-info/top_level.txt +0 -0
  130. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/tests/test.py +0 -0
  131. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/tests/test2.py +0 -0
  132. {kaxe-1.4.6.dev0 → kaxe-1.4.8}/tests/test3.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kaxe
3
- Version: 1.4.6.dev0
3
+ Version: 1.4.8
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kaxe"
3
- version = "1.4.6.dev0"
3
+ version = "1.4.8"
4
4
  authors = [
5
5
  { name="Valter Yde Daugberg", email="valteryde@hotmail.com" },
6
6
  ]
@@ -0,0 +1,143 @@
1
+ """Coarse sampling helpers for auto-scaling plot windows from functions."""
2
+
3
+ import math
4
+ from typing import Callable, Optional, Sequence, Tuple
5
+
6
+ import numpy as np
7
+
8
+ from .helper import isRealNumber
9
+
10
+ DEFAULT_DOMAIN_1D = (-10.0, 10.0)
11
+ DEFAULT_DOMAIN_2D = (-10.0, 10.0, -10.0, 10.0)
12
+ DEFAULT_MARGIN = 0.05
13
+ BOUNDS_SAMPLES_1D = 128
14
+ BOUNDS_SAMPLES_2D = 32
15
+
16
+
17
+ def is_finite(value) -> bool:
18
+ return isRealNumber(value) and math.isfinite(value)
19
+
20
+
21
+ def apply_margin(lo: float, hi: float, fraction: float = DEFAULT_MARGIN) -> Tuple[float, float]:
22
+ if lo == hi:
23
+ return lo - 1.0, hi + 1.0
24
+ span = hi - lo
25
+ pad = span * fraction
26
+ return lo - pad, hi + pad
27
+
28
+
29
+ def resolve_interval(
30
+ user_domain: Optional[Sequence[float]],
31
+ plot_lo,
32
+ plot_hi,
33
+ default: Tuple[float, float],
34
+ ) -> Tuple[float, float]:
35
+ if plot_lo is not None and plot_hi is not None:
36
+ return float(plot_lo), float(plot_hi)
37
+ if user_domain is not None:
38
+ return float(user_domain[0]), float(user_domain[1])
39
+ return default
40
+
41
+
42
+ def sample_1d(
43
+ f: Callable,
44
+ x0: float,
45
+ x1: float,
46
+ n: int = BOUNDS_SAMPLES_1D,
47
+ ) -> Tuple[Optional[float], Optional[float], Optional[float], Optional[float]]:
48
+ if x0 == x1:
49
+ x0 -= 0.5
50
+ x1 += 0.5
51
+
52
+ xs = np.linspace(x0, x1, n)
53
+ ys = []
54
+ for x in xs:
55
+ try:
56
+ y = f(float(x))
57
+ except Exception:
58
+ continue
59
+ if is_finite(y):
60
+ ys.append(float(y))
61
+
62
+ if not ys:
63
+ return None, None, None, None
64
+
65
+ return float(x0), float(x1), min(ys), max(ys)
66
+
67
+
68
+ def sample_2d(
69
+ f: Callable,
70
+ x0: float,
71
+ x1: float,
72
+ y0: float,
73
+ y1: float,
74
+ n: int = BOUNDS_SAMPLES_2D,
75
+ ) -> Tuple[
76
+ Optional[float],
77
+ Optional[float],
78
+ Optional[float],
79
+ Optional[float],
80
+ Optional[float],
81
+ Optional[float],
82
+ ]:
83
+ if x0 == x1:
84
+ x0 -= 0.5
85
+ x1 += 0.5
86
+ if y0 == y1:
87
+ y0 -= 0.5
88
+ y1 += 0.5
89
+
90
+ xs = np.linspace(x0, x1, n)
91
+ ys = np.linspace(y0, y1, n)
92
+ x_grid, y_grid = np.meshgrid(xs, ys, indexing="ij")
93
+
94
+ zs = []
95
+ try:
96
+ z_vals = np.asarray(f(x_grid, y_grid), dtype=np.float64)
97
+ if z_vals.shape == x_grid.shape and np.issubdtype(z_vals.dtype, np.floating):
98
+ for z in z_vals.ravel():
99
+ if is_finite(z):
100
+ zs.append(float(z))
101
+ except Exception:
102
+ for x in xs:
103
+ for y in ys:
104
+ try:
105
+ z = f(float(x), float(y))
106
+ except Exception:
107
+ continue
108
+ if is_finite(z):
109
+ zs.append(float(z))
110
+
111
+ if not zs:
112
+ return None, None, None, None, None, None
113
+
114
+ return float(x0), float(x1), float(y0), float(y1), min(zs), max(zs)
115
+
116
+
117
+ def sample_polar_1d(
118
+ f: Callable,
119
+ n: int = BOUNDS_SAMPLES_1D,
120
+ ) -> Tuple[Optional[float], Optional[float]]:
121
+ rs = []
122
+ for i in range(n):
123
+ theta = 2.0 * math.pi * i / n
124
+ try:
125
+ r = f(theta)
126
+ except Exception:
127
+ continue
128
+ if is_finite(r):
129
+ rs.append(float(r))
130
+
131
+ if not rs:
132
+ return None, None
133
+
134
+ r_min = min(0.0, min(rs))
135
+ r_max = max(rs)
136
+ return apply_margin(r_min, r_max)
137
+
138
+
139
+ def append_axis_values(values: list, lo, hi):
140
+ if lo is not None:
141
+ values.append(lo)
142
+ if hi is not None:
143
+ values.append(hi)
@@ -13,7 +13,6 @@ from .objects.line import Line3D, FlatLine3D, Line3DObject, FlatLine3DObject
13
13
  from .objects.point import Point3D, Point3DObject
14
14
  import psutil
15
15
  process = psutil.Process()
16
- import sys
17
16
  import sdl2
18
17
  import sdl2.ext
19
18
  import sdl2.video
@@ -994,14 +993,12 @@ class OpenGLRender:
994
993
  lasttime = time.time()
995
994
  while sdl2.SDL_PollEvent(event):
996
995
  if event.type == sdl2.SDL_QUIT:
997
- running = False
998
996
  self.quit(gl_context, window)
999
- sys.exit()
997
+ return
1000
998
  elif event.type == sdl2.SDL_KEYDOWN:
1001
999
  if event.key.keysym.sym == sdl2.SDLK_ESCAPE:
1002
1000
  self.quit(gl_context, window)
1003
- running = False
1004
- sys.exit()
1001
+ return
1005
1002
 
1006
1003
  if event.key.keysym.sym == sdl2.SDLK_RETURN and (event.key.keysym.mod & sdl2.KMOD_ALT):
1007
1004
  # Toggle fullscreen on Alt+Enter
@@ -268,23 +268,27 @@ class Window(AttrObject):
268
268
  if len(self.windowAxis) != 6:
269
269
  [self.windowAxis.append(None) for _ in range(6 - len(self.windowAxis))]
270
270
 
271
- # har ingen effekt på 3D
272
271
  if sorted(self.windowAxis, key=lambda x: x==None)[-1] == None:
273
272
  x = []
274
273
  y = []
275
274
  z = []
276
275
  for i in self.objects:
277
- if hasattr(i, 'bounds'):
278
- bounds = i.bounds()
279
- x.append(bounds[0])
280
- x.append(bounds[1])
281
- y.append(bounds[2])
282
- y.append(bounds[3])
283
- try:
284
- z.append(bounds[4])
285
- z.append(bounds[5])
286
- except IndexError as e:
287
- pass
276
+ bounds_fn = getattr(i, 'bounds', None)
277
+ if callable(bounds_fn):
278
+ bounds = bounds_fn(plot_window=self.windowAxis, plot=self)
279
+ if bounds:
280
+ if bounds[0] is not None:
281
+ x.append(bounds[0])
282
+ if len(bounds) > 1 and bounds[1] is not None:
283
+ x.append(bounds[1])
284
+ if len(bounds) > 2 and bounds[2] is not None:
285
+ y.append(bounds[2])
286
+ if len(bounds) > 3 and bounds[3] is not None:
287
+ y.append(bounds[3])
288
+ if len(bounds) > 4 and bounds[4] is not None:
289
+ z.append(bounds[4])
290
+ if len(bounds) > 5 and bounds[5] is not None:
291
+ z.append(bounds[5])
288
292
  continue
289
293
 
290
294
  try:
@@ -1,5 +1,5 @@
1
1
 
2
- from typing import Callable
2
+ from typing import Callable, Optional, Sequence, Tuple, Union
3
3
  from .point import Points2D
4
4
  from ...core.styles import getRandomColor
5
5
  from ...core.color import to_rgba
@@ -7,9 +7,16 @@ from ...core.helper import *
7
7
  from ...core.shapes import shapes
8
8
  from ...core.symbol import symbol
9
9
  from ...core.helper import isRealNumber
10
+ from ...core.bounds import (
11
+ DEFAULT_DOMAIN_1D,
12
+ DEFAULT_MARGIN,
13
+ apply_margin,
14
+ resolve_interval,
15
+ sample_1d,
16
+ sample_polar_1d,
17
+ )
10
18
  from ...plot import identities
11
19
  from random import randint
12
- from typing import Union
13
20
 
14
21
  class Function2D:
15
22
  """
@@ -30,6 +37,11 @@ class Function2D:
30
37
  If greater than 0, the function plot line will be dotted with the specified distance between dots. Default is 0.
31
38
  dashed : int, optional
32
39
  If greater than 0, the function plot line will be dashed with the specified distance between dashes. Default is 0.
40
+ domain : tuple, optional
41
+ Sampling interval ``(x0, x1)`` for auto-scaled x when the plot window
42
+ does not fix x. Default is ``(-10, 10)``.
43
+ range : tuple, optional
44
+ Fixed output interval ``(y0, y1)`` for the y axis when auto-scaling.
33
45
  args : tuple, optional
34
46
  Additional positional arguments to be passed to the function f.
35
47
  kwargs : dict, optional
@@ -56,6 +68,8 @@ class Function2D:
56
68
  width:int=10,
57
69
  dotted:int=0,
58
70
  dashed:int=0,
71
+ domain:Optional[Sequence[float]]=None,
72
+ range:Optional[Sequence[float]]=None,
59
73
  *args,
60
74
  **kwargs
61
75
  ):
@@ -90,9 +104,75 @@ class Function2D:
90
104
  self.otherArgs = args
91
105
  self.otherKwargs = kwargs
92
106
 
107
+ self.domain = tuple(domain) if domain is not None else None
108
+ self.range = tuple(range) if range is not None else None
109
+
93
110
  self.supports = [identities.XYPLOT, identities.POLAR, identities.LOGPLOT]
94
111
 
95
112
 
113
+ def _call(self, x):
114
+ return self.function(x, *self.otherArgs, **self.otherKwargs)
115
+
116
+ def bounds(self, plot_window=None, plot=None):
117
+ """
118
+ Estimate data bounds for auto-scaling.
119
+
120
+ Returns up to six values ``[x0, x1, y0, y1, z0, z1]``. Entries are
121
+ ``None`` when that axis is fixed by the plot window or not applicable.
122
+ """
123
+ if plot_window is None and plot is not None:
124
+ plot_window = getattr(plot, 'windowAxis', None)
125
+
126
+ plot_identity = getattr(plot, 'identity', None) if plot is not None else None
127
+ first_axis_log = getattr(plot, 'firstAxisLog', False) if plot is not None else False
128
+ second_axis_log = getattr(plot, 'secondAxisLog', False) if plot is not None else False
129
+
130
+ if plot_identity == identities.POLAR:
131
+ wa = plot_window or [None, None]
132
+ if wa[0] is not None and wa[1] is not None:
133
+ return [wa[0], wa[1], None, None]
134
+ r0, r1 = sample_polar_1d(self._call)
135
+ if r0 is None:
136
+ return [None, None, None, None]
137
+ return [r0, r1, None, None]
138
+
139
+ wa = list(plot_window or [None, None, None, None])
140
+ while len(wa) < 4:
141
+ wa.append(None)
142
+
143
+ default_x = (0.01, 10.0) if first_axis_log else DEFAULT_DOMAIN_1D
144
+ x0, x1 = resolve_interval(self.domain, wa[0], wa[1], default_x)
145
+ if first_axis_log and x0 <= 0:
146
+ x0 = 0.01
147
+
148
+ auto_x = wa[0] is None or wa[1] is None
149
+ auto_y = wa[2] is None or wa[3] is None
150
+
151
+ if self.range is not None:
152
+ y0, y1 = float(self.range[0]), float(self.range[1])
153
+ elif auto_y:
154
+ _, _, y0, y1 = sample_1d(self._call, x0, x1)
155
+ if y0 is None:
156
+ return [None, None, None, None]
157
+ if second_axis_log:
158
+ if y0 <= 0:
159
+ y0 = 0.01
160
+ if y1 <= 0:
161
+ y1 = 0.01
162
+ y0, y1 = apply_margin(y0, y1)
163
+ else:
164
+ y0, y1 = None, None
165
+
166
+ if auto_x:
167
+ x0, x1 = apply_margin(x0, x1)
168
+ if first_axis_log and x0 <= 0:
169
+ x0 = 0.01
170
+ else:
171
+ x0, x1 = None, None
172
+
173
+ return [x0, x1, y0, y1]
174
+
175
+
96
176
  def __call__(self, x):
97
177
  return self.function(x, *self.otherArgs, **self.otherKwargs)
98
178
 
@@ -13,6 +13,14 @@ import numpy as np
13
13
  import math
14
14
  import numbers
15
15
  import time
16
+ from typing import Optional, Sequence
17
+
18
+ from ...core.bounds import (
19
+ DEFAULT_DOMAIN_1D,
20
+ apply_margin,
21
+ resolve_interval,
22
+ sample_2d,
23
+ )
16
24
 
17
25
 
18
26
 
@@ -75,6 +83,14 @@ class Function3D(Base3DObject):
75
83
  Whether to fill the plot. default is True
76
84
  drawDiagonalLines: bool
77
85
  Whether to draw diagonal lines in triangles when fill is False. default is False
86
+ domain : tuple, optional
87
+ Sampling interval for the two independent axes. For ``axis="xy"`` this is
88
+ ``(x0, x1, y0, y1)``; for ``axis="xz"`` it is ``(x0, x1, z0, z1)``; for
89
+ ``axis="yz"`` it is ``(y0, y1, z0, z1)``. Defaults to ``(-10, 10)`` on
90
+ each independent axis when the plot window does not fix them.
91
+ range : tuple, optional
92
+ Fixed interval ``(lo, hi)`` on the dependent axis (z for ``axis="xy"``,
93
+ y for ``axis="xz"``, x for ``axis="yz"``).
78
94
  excludeLight : bool, optional
79
95
  Whether to exclude lighting effects. Default is True.
80
96
 
@@ -93,6 +109,8 @@ class Function3D(Base3DObject):
93
109
  drawDiagonalLines:bool=False,
94
110
  axis="xy",
95
111
  excludeLight=True,
112
+ domain:Optional[Sequence[float]]=None,
113
+ range:Optional[Sequence[float]]=None,
96
114
  *args,
97
115
  **kwargs
98
116
  ):
@@ -106,6 +124,9 @@ class Function3D(Base3DObject):
106
124
  self.otherKwargs = kwargs
107
125
  self.excludeLight = excludeLight
108
126
 
127
+ self.domain = tuple(domain) if domain is not None else None
128
+ self.range = tuple(range) if range is not None else None
129
+
109
130
  self.fill = fill
110
131
  self.drawDiagonalLines = drawDiagonalLines
111
132
 
@@ -124,8 +145,80 @@ class Function3D(Base3DObject):
124
145
  self.numPoints = 25
125
146
 
126
147
 
127
-
148
+ _AXIS_IDX = {'x': (0, 1), 'y': (2, 3), 'z': (4, 5)}
149
+
150
+ def _call(self, a, b):
151
+ return self.f(a, b, *self.otherArgs, **self.otherKwargs)
152
+
153
+ def _resolve_axis_interval(self, axis_name, plot_window, domain_slice):
154
+ lo_i, hi_i = self._AXIS_IDX[axis_name]
155
+ plot_lo = plot_window[lo_i] if len(plot_window) > lo_i else None
156
+ plot_hi = plot_window[hi_i] if len(plot_window) > hi_i else None
157
+ user = domain_slice if domain_slice is not None else None
158
+ return resolve_interval(user, plot_lo, plot_hi, DEFAULT_DOMAIN_1D)
159
+
160
+ def _axis_auto(self, axis_name, plot_window):
161
+ lo_i, hi_i = self._AXIS_IDX[axis_name]
162
+ if len(plot_window) <= hi_i:
163
+ return True
164
+ return plot_window[lo_i] is None or plot_window[hi_i] is None
165
+
166
+ def bounds(self, plot_window=None, plot=None):
167
+ """
168
+ Estimate data bounds for auto-scaling 3D plots.
169
+
170
+ Returns ``[x0, x1, y0, y1, z0, z1]`` with ``None`` for fixed axes.
171
+ """
172
+ if plot_window is None and plot is not None:
173
+ plot_window = getattr(plot, 'windowAxis', None)
174
+
175
+ wa = list(plot_window or [None] * 6)
176
+ while len(wa) < 6:
177
+ wa.append(None)
178
+
179
+ ind0, ind1 = self.axis[0], self.axis[1]
180
+ dep = self.dependantVariable
128
181
 
182
+ domain = self.domain
183
+ d0 = domain[0:2] if domain is not None else None
184
+ d1 = domain[2:4] if domain is not None else None
185
+
186
+ if self.axis == 'xy':
187
+ u_axis, v_axis = 'x', 'y'
188
+ elif self.axis == 'xz':
189
+ u_axis, v_axis = 'x', 'z'
190
+ else:
191
+ u_axis, v_axis = 'y', 'z'
192
+
193
+ u0, u1 = self._resolve_axis_interval(u_axis, wa, d0)
194
+ v0, v1 = self._resolve_axis_interval(v_axis, wa, d1)
195
+
196
+ result = [None] * 6
197
+
198
+ for axis_name, lo, hi in ((u_axis, u0, u1), (v_axis, v0, v1)):
199
+ if not self._axis_auto(axis_name, wa):
200
+ continue
201
+ lo, hi = apply_margin(lo, hi)
202
+ lo_i, hi_i = self._AXIS_IDX[axis_name]
203
+ result[lo_i] = lo
204
+ result[hi_i] = hi
205
+
206
+ if self.range is not None:
207
+ dep_lo, dep_hi = float(self.range[0]), float(self.range[1])
208
+ elif self._axis_auto(dep, wa):
209
+ _, _, _, _, dep_lo, dep_hi = sample_2d(self._call, u0, u1, v0, v1)
210
+ if dep_lo is None:
211
+ return result
212
+ dep_lo, dep_hi = apply_margin(dep_lo, dep_hi)
213
+ else:
214
+ return result
215
+
216
+ dep_lo_i, dep_hi_i = self._AXIS_IDX[dep]
217
+ result[dep_lo_i] = dep_lo
218
+ result[dep_hi_i] = dep_hi
219
+ return result
220
+
221
+
129
222
  def __addTriangle__(self, render, p1, p2, p3, color, isRealpoint):
130
223
 
131
224
  # dont draw vertical vertices
@@ -19,6 +19,11 @@ class Function:
19
19
  The number of points to plot for 3D functions. Default is None.
20
20
  fill : bool, optional
21
21
  Whether to fill the area under the function plot for 3D functions. Default is True.
22
+ domain : tuple, optional
23
+ Sampling interval for auto-scaled axes. See :class:`kaxe.Function2D` and
24
+ :class:`kaxe.Function3D`.
25
+ range : tuple, optional
26
+ Fixed output interval on the dependent axis when auto-scaling.
22
27
  *args : tuple
23
28
  Additional positional arguments to pass to the function f.
24
29
  **kwargs : dict
@@ -53,5 +58,5 @@ class Function:
53
58
 
54
59
  if n == 2:
55
60
  from .d3.function import Function3D
56
- return Function3D(f, color=color, numPoints=numPoints, fill=fill)
61
+ return Function3D(f, color=color, numPoints=numPoints, fill=fill, *args, **kwargs)
57
62
 
@@ -61,8 +61,33 @@ class PolarPlot(Window):
61
61
 
62
62
  # creating plotting window
63
63
  def __calculateWindowBorders__(self):
64
- if self.windowAxis[0] is None: self.windowAxis[0] = 0
65
- if self.windowAxis[1] is None: self.windowAxis[1] = 10
64
+ if self.windowAxis[0] is None:
65
+ self.windowAxis[0] = 0
66
+
67
+ if self.windowAxis[1] is not None:
68
+ return
69
+
70
+ r_vals = []
71
+ for obj in self.objects:
72
+ bounds_fn = getattr(obj, 'bounds', None)
73
+ if callable(bounds_fn):
74
+ bounds = bounds_fn(plot_window=self.windowAxis, plot=self)
75
+ if bounds:
76
+ if bounds[0] is not None:
77
+ r_vals.append(bounds[0])
78
+ if bounds[1] is not None:
79
+ r_vals.append(bounds[1])
80
+ continue
81
+ try:
82
+ r_vals.append(obj.farLeft)
83
+ r_vals.append(obj.farRight)
84
+ except AttributeError:
85
+ continue
86
+
87
+ if r_vals:
88
+ self.windowAxis[1] = max(r_vals)
89
+ else:
90
+ self.windowAxis[1] = 10
66
91
 
67
92
 
68
93
  def __addRoundLines__(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kaxe
3
- Version: 1.4.6.dev0
3
+ Version: 1.4.8
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
@@ -15,6 +15,7 @@ src/kaxe/chart/pie.py
15
15
  src/kaxe/chart/qqplot.py
16
16
  src/kaxe/core/__init__.py
17
17
  src/kaxe/core/axis.py
18
+ src/kaxe/core/bounds.py
18
19
  src/kaxe/core/color.py
19
20
  src/kaxe/core/draw.py
20
21
  src/kaxe/core/fileloader.py
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