kaxe 1.5.6.dev0__tar.gz → 1.5.7.dev0__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 (148) hide show
  1. {kaxe-1.5.6.dev0/src/kaxe.egg-info → kaxe-1.5.7.dev0}/PKG-INFO +1 -1
  2. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/pyproject.toml +1 -1
  3. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/helper.py +34 -18
  4. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d2/contour.py +32 -14
  5. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0/src/kaxe.egg-info}/PKG-INFO +1 -1
  6. kaxe-1.5.7.dev0/tests/test_4.py +29 -0
  7. kaxe-1.5.6.dev0/tests/test_4.py +0 -11
  8. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/LICENSE +0 -0
  9. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/MANIFEST.in +0 -0
  10. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/README.md +0 -0
  11. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/setup.cfg +0 -0
  12. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/__init__.py +0 -0
  13. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/_require_3d.py +0 -0
  14. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/chart/__init__.py +0 -0
  15. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/chart/bar.py +0 -0
  16. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/chart/box.py +0 -0
  17. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/chart/pie.py +0 -0
  18. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/chart/qqplot.py +0 -0
  19. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/__init__.py +0 -0
  20. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/axis.py +0 -0
  21. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/bounds.py +0 -0
  22. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/color.py +0 -0
  23. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/d3/backend.py +0 -0
  24. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/d3/camera.py +0 -0
  25. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/d3/helper.py +0 -0
  26. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/d3/hud.py +0 -0
  27. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/d3/objects/__init__.py +0 -0
  28. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/d3/objects/color.py +0 -0
  29. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/d3/objects/line.py +0 -0
  30. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/d3/objects/point.py +0 -0
  31. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/d3/objects/pointer.py +0 -0
  32. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/d3/objects/triangle.py +0 -0
  33. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/d3/openglrender.py +0 -0
  34. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/d3/translator.py +0 -0
  35. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/draw.py +0 -0
  36. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/fileloader.py +0 -0
  37. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/ipython_display.py +0 -0
  38. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/legend.py +0 -0
  39. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/line.py +0 -0
  40. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/marker.py +0 -0
  41. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/profiler.py +0 -0
  42. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/progress.py +0 -0
  43. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/round.py +0 -0
  44. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/shapes.py +0 -0
  45. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/styles.py +0 -0
  46. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/svg.py +0 -0
  47. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/svg_pdf.py +0 -0
  48. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/symbol.py +0 -0
  49. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/text.py +0 -0
  50. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/core/window.py +0 -0
  51. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/data/__init__.py +0 -0
  52. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/data/excel.py +0 -0
  53. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/__init__.py +0 -0
  54. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/_lazy.py +0 -0
  55. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d2/__init__.py +0 -0
  56. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d2/arrow.py +0 -0
  57. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d2/bubble.py +0 -0
  58. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d2/equation.py +0 -0
  59. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d2/fill.py +0 -0
  60. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d2/function.py +0 -0
  61. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d2/inequality.py +0 -0
  62. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d2/map.py +0 -0
  63. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d2/parameter.py +0 -0
  64. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d2/pillar.py +0 -0
  65. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d2/point.py +0 -0
  66. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d3/__init__.py +0 -0
  67. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d3/base.py +0 -0
  68. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d3/function.py +0 -0
  69. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d3/mesh.py +0 -0
  70. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d3/point.py +0 -0
  71. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/d3/potato.py +0 -0
  72. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/function.py +0 -0
  73. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/legend.py +0 -0
  74. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/mapdata.py +0 -0
  75. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/point.py +0 -0
  76. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/objects/text.py +0 -0
  77. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/__init__.py +0 -0
  78. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/_lazy.py +0 -0
  79. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/box.py +0 -0
  80. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/constants.py +0 -0
  81. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/d3/__init__.py +0 -0
  82. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/d3/axes.py +0 -0
  83. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/d3/geometry.py +0 -0
  84. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/d3/plot3d.py +0 -0
  85. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/d3/variants.py +0 -0
  86. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/double.py +0 -0
  87. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/empty.py +0 -0
  88. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/grid.py +0 -0
  89. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/log.py +0 -0
  90. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/polar.py +0 -0
  91. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/standard.py +0 -0
  92. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/themes.py +0 -0
  93. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/zoom.py +0 -0
  94. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/plot/zoom_connector.py +0 -0
  95. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/project/__init__.py +0 -0
  96. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/project/codec.py +0 -0
  97. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/project/context.py +0 -0
  98. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/project/document.py +0 -0
  99. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/project/registry.py +0 -0
  100. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/project/sample.py +0 -0
  101. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/project/sampled_curve.py +0 -0
  102. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/project/serializers.py +0 -0
  103. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/project/window.py +0 -0
  104. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/__init__.py +0 -0
  105. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/__init__.py +0 -0
  106. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-oblique.ttf +0 -0
  107. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-roman.ttf +0 -0
  108. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-semibold.ttf +0 -0
  109. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-semiboldoblique.ttf +0 -0
  110. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.classical-serif-italic.ttf +0 -0
  111. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-bold.ttf +0 -0
  112. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-bolditalic.ttf +0 -0
  113. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-italic.ttf +0 -0
  114. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-roman.ttf +0 -0
  115. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-bold.ttf +0 -0
  116. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-boldoblique.ttf +0 -0
  117. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-demi-condensed-demicondensed.ttf +0 -0
  118. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-medium.ttf +0 -0
  119. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-oblique.ttf +0 -0
  120. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-bold.ttf +0 -0
  121. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-bolditalic.ttf +0 -0
  122. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-extra-boldslanted.ttf +0 -0
  123. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-extra-romanslanted.ttf +0 -0
  124. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-italic.ttf +0 -0
  125. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-roman.ttf +0 -0
  126. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-upright-italic-uprightitalic.ttf +0 -0
  127. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-bold.ttf +0 -0
  128. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-bolditalic.ttf +0 -0
  129. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-italic.ttf +0 -0
  130. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-light.ttf +0 -0
  131. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-lightoblique.ttf +0 -0
  132. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-regular.ttf +0 -0
  133. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-variable-width-italic.ttf +0 -0
  134. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-variable-width-medium.ttf +0 -0
  135. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/computer-modern-family/readme.txt +0 -0
  136. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/logo-small.png +0 -0
  137. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/symbolcross.png +0 -0
  138. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/symboldonut.png +0 -0
  139. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/symbollollipop.png +0 -0
  140. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe/resources/symboltriangle.png +0 -0
  141. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe.egg-info/SOURCES.txt +0 -0
  142. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe.egg-info/dependency_links.txt +0 -0
  143. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe.egg-info/requires.txt +0 -0
  144. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/src/kaxe.egg-info/top_level.txt +0 -0
  145. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/tests/test.py +0 -0
  146. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/tests/test2.py +0 -0
  147. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/tests/test3.py +0 -0
  148. {kaxe-1.5.6.dev0 → kaxe-1.5.7.dev0}/tests/test_5.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kaxe
3
- Version: 1.5.6.dev0
3
+ Version: 1.5.7.dev0
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.5.6.dev0"
3
+ version = "1.5.7.dev0"
4
4
  authors = [
5
5
  { name="Valter Yde Daugberg", email="valteryde@hotmail.com" },
6
6
  ]
@@ -45,30 +45,46 @@ def vlen(v):
45
45
  return math.sqrt(sum([i**2 for i in v]))
46
46
 
47
47
 
48
- def contour_label_angle(polyline, index):
49
- """Readable tangent angle in degrees for text placed on a contour polyline."""
50
- n = len(polyline)
51
- if n < 2:
48
+ def contour_label_angle(func, parent, px, py, polyline=None, tangent_window=40):
49
+ """Readable tangent angle in degrees for ``Text.rotate`` at pixel (px, py).
50
+
51
+ Uses the function gradient mapped into pixel space (matplotlib clabel style:
52
+ arctan2 of the tangent vector in kaxe y-up coordinates, then keep text
53
+ right-side up). The returned value is passed directly to ``Text.rotate`` /
54
+ ``PIL.Image.rotate`` (SVG export negates internally to match).
55
+ """
56
+ del polyline, tangent_window
57
+
58
+ x, y = parent.inversepixel(px, py)
59
+ if x is None or y is None:
52
60
  return 0
53
61
 
54
- if index <= 0:
55
- p0, p1 = polyline[0], polyline[1]
56
- elif index >= n - 1:
57
- p0, p1 = polyline[-2], polyline[-1]
58
- else:
59
- p0, p1 = polyline[index - 1], polyline[index + 1]
62
+ scale = max(abs(x), abs(y), 1.0)
63
+ h = 1e-4 * scale
64
+
65
+ try:
66
+ fx = (func(x + h, y) - func(x - h, y)) / (2 * h)
67
+ fy = (func(x, y + h) - func(x, y - h)) / (2 * h)
68
+ except (TypeError, ValueError, ZeroDivisionError):
69
+ return 0
70
+
71
+ tx, ty = -fy, fx
72
+ if tx == 0 and ty == 0:
73
+ return 0
74
+
75
+ px0, py0 = parent.pixel(x, y)
76
+ px1, py1 = parent.pixel(x + tx, y + ty)
77
+ if px0 is None or py0 is None or px1 is None or py1 is None:
78
+ return 0
60
79
 
61
- dx = p1[0] - p0[0]
62
- dy = p1[1] - p0[1]
80
+ dx = px1 - px0
81
+ dy = py1 - py0
63
82
  if dx == 0 and dy == 0:
64
83
  return 0
65
84
 
66
- angle = math.degrees(math.atan2(-dy, dx))
67
- if angle > 90:
68
- angle -= 180
69
- elif angle < -90:
70
- angle += 180
71
- return angle
85
+ rotation = math.degrees(math.atan2(dy, dx))
86
+ rotation = (rotation + 90) % 180 - 90
87
+ return rotation
72
88
 
73
89
 
74
90
  def bbox_overlaps(a, b, padding=0):
@@ -58,7 +58,7 @@ def _closest_polyline_index(polyline, point):
58
58
  return best_index
59
59
 
60
60
 
61
- def _label_candidates(polyline, spacing):
61
+ def _label_candidates(polyline, spacing, max_candidates=None):
62
62
  polyline = _simplify_polyline(polyline)
63
63
  if len(polyline) < 2:
64
64
  return []
@@ -76,6 +76,15 @@ def _label_candidates(polyline, spacing):
76
76
  mid_index = len(polyline) // 2
77
77
  candidates.append((polyline[mid_index], mid_index, arc))
78
78
 
79
+ if max_candidates is not None and len(candidates) > max_candidates:
80
+ if max_candidates <= 1:
81
+ return candidates[:1]
82
+ last = len(candidates) - 1
83
+ candidates = [
84
+ candidates[int(i * last / (max_candidates - 1))]
85
+ for i in range(max_candidates)
86
+ ]
87
+
79
88
  return candidates
80
89
 
81
90
 
@@ -110,7 +119,7 @@ class Contour:
110
119
  label : bool, optional
111
120
  Draw inline level labels on contour lines (default is True).
112
121
  labelSpacing : int, optional
113
- Minimum pixel spacing between label candidates along a contour (default is 100).
122
+ Minimum pixel spacing between label candidates along a contour (default is 80).
114
123
  labelCollisionPadding : int, optional
115
124
  Extra pixel gap required between placed label bounding boxes (default is 4).
116
125
  labelMinArc : int, optional
@@ -118,7 +127,7 @@ class Contour:
118
127
  labelMaxBranches : int, optional
119
128
  Maximum number of polylines per level to label (default is 1).
120
129
  labelMaxPerLevel : int, optional
121
- Hard cap on labels placed per level; unlimited when None (default is None).
130
+ Maximum labels per contour level (default is 8).
122
131
  labelColor : tuple, optional
123
132
  Color of inline contour labels (default is black).
124
133
 
@@ -141,11 +150,11 @@ class Contour:
141
150
  lineThickness: int = 2,
142
151
  computePadding: int = 50,
143
152
  label: bool = True,
144
- labelSpacing: int = 100,
153
+ labelSpacing: int = 80,
145
154
  labelCollisionPadding: int = 4,
146
155
  labelMinArc: Optional[int] = None,
147
156
  labelMaxBranches: int = 1,
148
- labelMaxPerLevel: Optional[int] = None,
157
+ labelMaxPerLevel: int = 8,
149
158
  labelColor=(0, 0, 0, 255),
150
159
  ):
151
160
  self.batch = shapes.Batch()
@@ -223,7 +232,11 @@ class Contour:
223
232
  simplified = _simplify_polyline(polyline)
224
233
  arc = _polyline_arc_length(simplified)
225
234
  for candidate_index, (point, index, _) in enumerate(
226
- _label_candidates(polyline, self.labelSpacing)
235
+ _label_candidates(
236
+ polyline,
237
+ self.labelSpacing,
238
+ max_candidates=self.labelMaxPerLevel,
239
+ )
227
240
  ):
228
241
  candidates.append({
229
242
  "z": z,
@@ -244,31 +257,36 @@ class Contour:
244
257
 
245
258
  def __finalizeLabels__(self, parent):
246
259
  fontSize = parent.getAttr('fontSize')
260
+ collision_padding = max(self.labelCollisionPadding, fontSize // 2)
247
261
  placed_bboxes = []
248
262
  label_bboxes = []
249
263
  placed_per_level = {}
250
264
 
251
265
  for candidate in self.__collectCandidates__(parent):
252
266
  level_index = candidate["level_index"]
253
- if self.labelMaxPerLevel is not None:
254
- if placed_per_level.get(level_index, 0) >= self.labelMaxPerLevel:
255
- continue
267
+ if placed_per_level.get(level_index, 0) >= self.labelMaxPerLevel:
268
+ continue
256
269
 
257
- angle = contour_label_angle(candidate["polyline"], candidate["index"])
270
+ px, py = candidate["point"]
271
+ angle = contour_label_angle(self.func, parent, px, py)
258
272
  text = Text(
259
273
  candidate["label_text"],
260
- int(candidate["point"][0]),
261
- int(candidate["point"][1]),
274
+ int(px),
275
+ int(py),
262
276
  fontSize=fontSize,
263
277
  color=self.labelColor,
264
- rotate=int(angle),
278
+ rotate=round(angle),
265
279
  anchor_x='center',
266
280
  anchor_y='center',
267
281
  )
268
282
  bbox = text.getBoundingBox()
283
+ label_padding = max(
284
+ collision_padding,
285
+ int(max(bbox[2], bbox[3]) * 0.15),
286
+ )
269
287
 
270
288
  if any(
271
- bbox_overlaps(bbox, placed_bbox, self.labelCollisionPadding)
289
+ bbox_overlaps(bbox, placed_bbox, label_padding)
272
290
  for placed_bbox in placed_bboxes
273
291
  ):
274
292
  continue
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kaxe
3
- Version: 1.5.6.dev0
3
+ Version: 1.5.7.dev0
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
@@ -0,0 +1,29 @@
1
+
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "src"))
6
+
7
+ from sympy import *
8
+ import kaxe
9
+ null = lambda *a, **b: 0
10
+
11
+ x_1, x_2 = symbols("x_1 x_2")
12
+
13
+ f = (x_1 + 1)**2 + (1 - x_2)**2
14
+
15
+ # min f(x) when
16
+
17
+ g_1 = x_1 + 0.5 * x_2 - 2 # <= 0
18
+ g_2 = -x_1 + 1 # <= 0
19
+
20
+
21
+ f_lambda = lambdify([x_1, x_2], f)
22
+ g_1_lambda = lambdify([x_1, x_2], g_1)
23
+ g_2_lambda = lambdify([x_1, x_2], g_2)
24
+
25
+ plt = kaxe.Plot()
26
+ plt.add(kaxe.Contour(f_lambda))
27
+ #plt.add(kaxe.Inequality(g_1_lambda, null))
28
+ # plt.add(kaxe.Inequality(g_2_lambda, null))
29
+ plt.show()
@@ -1,11 +0,0 @@
1
-
2
- import sys
3
-
4
- sys.path.append('./src')
5
-
6
- import kaxe
7
- import math
8
-
9
- plt = kaxe.Plot()
10
- plt.add(kaxe.HeatMap.fromFunction(lambda x,y: math.sin(x) * math.cos(y), numSamples=100, domain=(-10, 10, -10, 10)))
11
- plt.show()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes