fastplotpy 0.3.0a1__py3-none-win_amd64.whl

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 (78) hide show
  1. fastplotpy/README.md +70 -0
  2. fastplotpy/__init__.py +33 -0
  3. fastplotpy/assets/dist/assets/scene.worker-CcnexaKr.js +1 -0
  4. fastplotpy/assets/dist/index.js +15071 -0
  5. fastplotpy/assets/native/NotoSans-OFL.txt +96 -0
  6. fastplotpy/assets/native/THIRD_PARTY_NOTICES.md +24 -0
  7. fastplotpy/assets/native/fastplot_python_abi.dll +0 -0
  8. fastplotpy/assets/package.json +1 -0
  9. fastplotpy/axes_validation.py +102 -0
  10. fastplotpy/camera3d.py +104 -0
  11. fastplotpy/color_scale.py +88 -0
  12. fastplotpy/defaults/area-fill.json +5 -0
  13. fastplotpy/defaults/bar.json +22 -0
  14. fastplotpy/defaults/camera3d.json +22 -0
  15. fastplotpy/defaults/cartesian-references.json +10 -0
  16. fastplotpy/defaults/control.json +3 -0
  17. fastplotpy/defaults/crosshair.json +19 -0
  18. fastplotpy/defaults/error-bars.json +7 -0
  19. fastplotpy/defaults/heatmap.json +70 -0
  20. fastplotpy/defaults/interaction.json +3 -0
  21. fastplotpy/defaults/layout.json +32 -0
  22. fastplotpy/defaults/legend.json +24 -0
  23. fastplotpy/defaults/line-axes.json +28 -0
  24. fastplotpy/defaults/line3d.json +13 -0
  25. fastplotpy/defaults/markers.json +6 -0
  26. fastplotpy/defaults/mesh3d.json +13 -0
  27. fastplotpy/defaults/pan.json +7 -0
  28. fastplotpy/defaults/pie.json +27 -0
  29. fastplotpy/defaults/pie3d.json +7 -0
  30. fastplotpy/defaults/point-labels.json +13 -0
  31. fastplotpy/defaults/pointClick.json +6 -0
  32. fastplotpy/defaults/pointSelection.json +13 -0
  33. fastplotpy/defaults/polar.json +71 -0
  34. fastplotpy/defaults/polarRotate.json +5 -0
  35. fastplotpy/defaults/scatter3d.json +39 -0
  36. fastplotpy/defaults/scene3d.json +61 -0
  37. fastplotpy/defaults/surface.json +35 -0
  38. fastplotpy/defaults/tooltip.json +18 -0
  39. fastplotpy/defaults/trace-colors.json +10 -0
  40. fastplotpy/defaults/trace-options.json +24 -0
  41. fastplotpy/defaults/wonderplot.json +58 -0
  42. fastplotpy/defaults/zoom.json +12 -0
  43. fastplotpy/defaults.py +15 -0
  44. fastplotpy/error_bars.py +118 -0
  45. fastplotpy/exports.py +153 -0
  46. fastplotpy/families2d.py +896 -0
  47. fastplotpy/heatmap_labels.py +146 -0
  48. fastplotpy/interactions.py +243 -0
  49. fastplotpy/interactive.py +1922 -0
  50. fastplotpy/js_serialize.py +47 -0
  51. fastplotpy/lighting3d.py +113 -0
  52. fastplotpy/line3d_lod.py +138 -0
  53. fastplotpy/lod3d.py +105 -0
  54. fastplotpy/mesh3d_lod.py +107 -0
  55. fastplotpy/native.py +163 -0
  56. fastplotpy/overlays.py +561 -0
  57. fastplotpy/point_labels.py +86 -0
  58. fastplotpy/polar.py +445 -0
  59. fastplotpy/polygon_clip3d.py +148 -0
  60. fastplotpy/references.py +72 -0
  61. fastplotpy/rendering.py +65 -0
  62. fastplotpy/rust_scenes.py +314 -0
  63. fastplotpy/scene.py +1185 -0
  64. fastplotpy/scene3d.py +1215 -0
  65. fastplotpy/scene3d_accessibility.py +183 -0
  66. fastplotpy/scene3d_collection.py +158 -0
  67. fastplotpy/subplots.py +115 -0
  68. fastplotpy/surface_contours.py +122 -0
  69. fastplotpy/surface_lod.py +109 -0
  70. fastplotpy/svg3d.py +235 -0
  71. fastplotpy/trendline.py +236 -0
  72. fastplotpy/triangle_wireframe.py +51 -0
  73. fastplotpy/types.py +3027 -0
  74. fastplotpy-0.3.0a1.dist-info/METADATA +86 -0
  75. fastplotpy-0.3.0a1.dist-info/RECORD +78 -0
  76. fastplotpy-0.3.0a1.dist-info/WHEEL +5 -0
  77. fastplotpy-0.3.0a1.dist-info/licenses/LICENSE +21 -0
  78. fastplotpy-0.3.0a1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,28 @@
1
+ {
2
+ "defaultTicks": 5,
3
+ "maxDecimals": 10,
4
+ "plotBounds": { "left": 48, "top": 16, "right": 16, "bottom": 36 },
5
+ "axisColor": "#64748b",
6
+ "gridColor": "#cbd5e1",
7
+ "axisLineWidth": 1,
8
+ "gridLineWidth": 0.5,
9
+ "minorGridAlpha": 0.45,
10
+ "minorTickAlpha": 0.6,
11
+ "minorLabelAlpha": 0.65,
12
+ "majorTickLength": 5,
13
+ "majorTickDirection": "outside",
14
+ "majorTickLabelOffset": 8,
15
+ "majorTickLabelGap": 3,
16
+ "minorLabelMinDistanceX": 18,
17
+ "minorLabelMinDistanceY": 14,
18
+ "minorDefault": { "show": true, "ticks": "outside", "ticklen": 3, "grid": false },
19
+ "labelColor": "#475569",
20
+ "labelFont": "11px system-ui, sans-serif",
21
+ "labelRotationDegrees": 0,
22
+ "labelCollision": "allow",
23
+ "labelFormatter": null,
24
+ "titleColor": "#334155",
25
+ "titleFont": "600 12px system-ui, sans-serif",
26
+ "titleLineHeight": 16,
27
+ "titleGap": 8
28
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "lineWidth": 2,
3
+ "lineOpacity": 1,
4
+ "minimumHitRadius": 1,
5
+ "interpolation": "linear",
6
+ "smoothSamplesPerSegment": 12,
7
+ "lod": {
8
+ "enabled": false,
9
+ "strategy": "largest-triangle-3d",
10
+ "maxSourceSegments": 250
11
+ },
12
+ "maxSegments": 1000000
13
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "show": false,
3
+ "size": 3,
4
+ "shape": "circle",
5
+ "minSize": 1
6
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "opacity": 0.82,
3
+ "maxFaces": 500000,
4
+ "lod": {
5
+ "strategy": "largest-area-stratified",
6
+ "maxFaces": 1000
7
+ },
8
+ "backfaceCulling": false,
9
+ "wireframeShow": false,
10
+ "wireframeColor": "#0f172a",
11
+ "wireframeWidth": 1,
12
+ "wireframeOpacity": 0.65
13
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "mode": "xy",
3
+ "mouseButton": 0,
4
+ "modifierKey": "shift",
5
+ "preventDefault": true,
6
+ "minDragDistance": 2
7
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "startAngleDegrees": -90,
3
+ "clockwise": true,
4
+ "sectorGapDegrees": 0,
5
+ "sectorOpacity": 1,
6
+ "borderColor": "rgba(15, 23, 42, 0.28)",
7
+ "borderWidth": 1,
8
+ "innerRadiusRatio": 0,
9
+ "outerRadiusRatio": 1,
10
+ "colors": [],
11
+ "labels": {
12
+ "show": false,
13
+ "position": "inside",
14
+ "content": "label",
15
+ "color": "#ffffff",
16
+ "font": "12px system-ui, sans-serif",
17
+ "lineHeight": 15,
18
+ "decimals": 1,
19
+ "prefix": "",
20
+ "suffix": "",
21
+ "minSectorAngleDegrees": 12,
22
+ "radiusRatio": 0.66,
23
+ "offset": 14,
24
+ "collisionPadding": 2,
25
+ "formatter": null
26
+ }
27
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extrusionDepth": 0.15,
3
+ "curveTolerance": 1,
4
+ "seamStrokeWidth": 1,
5
+ "seamLineJoin": "round",
6
+ "maxCurveStepDegrees": 90
7
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "show": false,
3
+ "color": "#0f172a",
4
+ "font": "11px Inter, system-ui, sans-serif",
5
+ "lineHeight": 14,
6
+ "position": "auto",
7
+ "offset": 6,
8
+ "decimals": 0,
9
+ "prefix": "",
10
+ "suffix": "",
11
+ "collisionPadding": 2,
12
+ "formatter": null
13
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "enabled": false,
3
+ "mouseButton": 0,
4
+ "maxMovement": 4,
5
+ "radius": 8
6
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "enabled": false,
3
+ "mode": "single",
4
+ "keyboard": false,
5
+ "mouseButton": 0,
6
+ "maxMovement": 4,
7
+ "radius": 8,
8
+ "strokeColor": "#2563eb",
9
+ "fillColor": "rgba(37, 99, 235, 0.16)",
10
+ "lineWidth": 2,
11
+ "padding": 3,
12
+ "markerlessRadius": 3
13
+ }
@@ -0,0 +1,71 @@
1
+ {
2
+ "mode": "windrose",
3
+ "radialScale": "linear",
4
+ "sectorMode": "grouped",
5
+ "angleCategories": [],
6
+ "sectorWidthDegrees": 24,
7
+ "sectorGapDegrees": 0,
8
+ "sectorOpacity": 1,
9
+ "startAngleDegrees": -90,
10
+ "clockwise": true,
11
+ "innerRadiusRatio": 0,
12
+ "outerRadiusRatio": 0.92,
13
+ "minRadius": 0,
14
+ "maxRadius": null,
15
+ "borderWidth": 1,
16
+ "borderColor": "rgba(15, 23, 42, 0.28)",
17
+ "sectorLabels": {
18
+ "show": false,
19
+ "color": "#ffffff",
20
+ "font": "11px Inter, system-ui, sans-serif",
21
+ "lineHeight": 14,
22
+ "decimals": 0,
23
+ "prefix": "",
24
+ "suffix": "",
25
+ "minSectorRadius": 14,
26
+ "minSectorAngleDegrees": 6,
27
+ "radiusRatio": 0.62,
28
+ "collisionPadding": 2,
29
+ "formatter": null
30
+ },
31
+ "grid": {
32
+ "show": false,
33
+ "rings": 4,
34
+ "ringValues": [],
35
+ "spokes": 12,
36
+ "ringColor": "rgba(100, 116, 139, 0.34)",
37
+ "spokeColor": "rgba(100, 116, 139, 0.28)",
38
+ "ringLineWidth": 1,
39
+ "spokeLineWidth": 1,
40
+ "labels": {
41
+ "show": false,
42
+ "color": "#475569",
43
+ "font": "11px system-ui, sans-serif",
44
+ "decimals": 0,
45
+ "angleDegrees": 90,
46
+ "offset": 6,
47
+ "prefix": "",
48
+ "suffix": "",
49
+ "formatter": null
50
+ },
51
+ "angleLabels": {
52
+ "show": false,
53
+ "color": "#475569",
54
+ "font": "11px system-ui, sans-serif",
55
+ "decimals": 0,
56
+ "offset": 14,
57
+ "labels": [],
58
+ "prefix": "",
59
+ "suffix": "\u00b0",
60
+ "formatter": null
61
+ }
62
+ },
63
+ "vectors": {
64
+ "show": false,
65
+ "directions": [],
66
+ "color": "",
67
+ "lineWidth": 2,
68
+ "headSize": 8,
69
+ "headAngleDegrees": 28
70
+ }
71
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "mouseButton": 0,
3
+ "preventDefault": true,
4
+ "minDragDistance": 2
5
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "markerSize": 6,
3
+ "markerOpacity": 0.9,
4
+ "markerShape": "circle",
5
+ "lod": {
6
+ "enabled": false,
7
+ "strategy": "spatial-grid",
8
+ "maxPoints": 5000
9
+ },
10
+ "valueScale": "linear",
11
+ "lowColor": "#e0f2fe",
12
+ "highColor": "#7c3aed",
13
+ "colorStops": [],
14
+ "sizeScale": {
15
+ "enabled": false,
16
+ "minSize": 3,
17
+ "maxSize": 14,
18
+ "minValue": null,
19
+ "maxValue": null
20
+ },
21
+ "opacityScale": {
22
+ "enabled": false,
23
+ "minOpacity": 0.2,
24
+ "maxOpacity": 1,
25
+ "minValue": null,
26
+ "maxValue": null
27
+ },
28
+ "colorScaleLegend": true,
29
+ "legendWidth": 12,
30
+ "legendHeight": 120,
31
+ "legendOffset": 12,
32
+ "legendTitle": "value",
33
+ "legendTickCount": 3,
34
+ "legendFont": "11px system-ui, sans-serif",
35
+ "legendColor": "#475569",
36
+ "legendLabelGap": 4,
37
+ "legendGlyphWidth": 7,
38
+ "legendMinimumLabelHeight": 32
39
+ }
@@ -0,0 +1,61 @@
1
+ {
2
+ "renderer": "canvas",
3
+ "webgl2BatchVertexCount": 65532,
4
+ "webgl2MaxBufferBytes": 8388608,
5
+ "nodePngMaxPixels": 16777216,
6
+ "projection": "perspective",
7
+ "eye": [1.8, 1.4, 1.8],
8
+ "target": [0, 0, 0],
9
+ "up": [0, 1, 0],
10
+ "fieldOfViewDegrees": 45,
11
+ "orthographicScale": 2.5,
12
+ "near": 0.1,
13
+ "far": 100,
14
+ "lightingShow": false,
15
+ "lightingDirection": [1, 1, 1],
16
+ "lightingAmbient": 0.35,
17
+ "lightingDiffuse": 0.65,
18
+ "lightingSpecular": 0,
19
+ "lightingShininess": 32,
20
+ "lightingTwoSided": true,
21
+ "axisPadding": 0.08,
22
+ "showAxes": true,
23
+ "showGrid": true,
24
+ "gridSteps": 4,
25
+ "axisColor": "#52606d",
26
+ "gridColor": "#d9e2ec",
27
+ "axisLineWidth": 1.5,
28
+ "gridLineWidth": 1,
29
+ "axisLabelFont": "600 12px system-ui, sans-serif",
30
+ "axisLabelOffset": 8,
31
+ "axisTickCount": 5,
32
+ "axisTickMinCount": 2,
33
+ "axisTickMaxCount": 12,
34
+ "axisTickWorldLength": 0.03,
35
+ "axisTickLabelFont": "11px system-ui, sans-serif",
36
+ "axisTickLabelOffset": 7,
37
+ "axisTickLabelMinGap": 4,
38
+ "axisTickLabelGlyphWidth": 6.5,
39
+ "axisTickLabelMinWidth": 7,
40
+ "axisTickLabelLineHeight": 12,
41
+ "axisTickLabelBoundsInset": 1,
42
+ "axisTickMaxDecimals": 12,
43
+ "axisTickAutoMaxDecimals": 10,
44
+ "axisTickScientificLowerMagnitude": 0.0001,
45
+ "axisTickScientificUpperMagnitude": 10000000,
46
+ "axisTickScientificDecimals": 3,
47
+ "axisTickZeroToleranceFloor": 1e-15,
48
+ "axisTickStepFloor": 1e-12,
49
+ "axisTickLineWidthScale": 0.75,
50
+ "axisTickMinLineWidth": 1,
51
+ "maxPoints": 100000,
52
+ "accessibilityMaxRows": 50,
53
+ "accessibilityIncludeTable": true,
54
+ "accessibilityScatter3dLabel": "Scatter3D chart",
55
+ "accessibilityLine3dLabel": "Line3D chart",
56
+ "accessibilitySurfaceLabel": "Surface chart",
57
+ "accessibilityMesh3dLabel": "Mesh3D chart",
58
+ "accessibilityCollectionLabel": "3D chart data summary",
59
+ "staticFallbackDescription": "Static three-dimensional chart fallback generated from the renderer-neutral scene.",
60
+ "staticFallbackDecimals": 6
61
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "lowColor": "#0ea5e9",
3
+ "highColor": "#f97316",
4
+ "colorStops": [],
5
+ "opacity": 1,
6
+ "wireframeShow": false,
7
+ "wireframeColor": "#0f172a",
8
+ "wireframeWidth": 1,
9
+ "wireframeOpacity": 0.65,
10
+ "contourShow": false,
11
+ "contourCount": 5,
12
+ "contourColor": "#0f172a",
13
+ "contourWidth": 1.25,
14
+ "contourOpacity": 0.8,
15
+ "maxContourLevels": 32,
16
+ "lod": {
17
+ "enabled": false,
18
+ "strategy": "grid-stride",
19
+ "maxCells": 10000
20
+ },
21
+ "missingCells": "gap",
22
+ "maxTriangles": 200000,
23
+ "maxContourSegments": 500000,
24
+ "colorScaleLegend": true,
25
+ "legendWidth": 12,
26
+ "legendHeight": 120,
27
+ "legendOffset": 12,
28
+ "legendTitle": "z",
29
+ "legendTickCount": 3,
30
+ "legendFont": "11px system-ui, sans-serif",
31
+ "legendColor": "#475569",
32
+ "legendLabelGap": 4,
33
+ "legendGlyphWidth": 7,
34
+ "legendMinimumLabelHeight": 32
35
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "enabled": false,
3
+ "mode": "default",
4
+ "lineMode": "points",
5
+ "shared": false,
6
+ "sharedXMode": "exact",
7
+ "radius": 8,
8
+ "font": "12px system-ui, sans-serif",
9
+ "textLineHeight": 16,
10
+ "textColor": "#f8fafc",
11
+ "fallbackDarkTextColor": "#0f172a",
12
+ "backgroundColor": "#0f172a",
13
+ "borderColor": "#1e293b",
14
+ "borderWidth": 1,
15
+ "borderRadius": 4,
16
+ "padding": 8,
17
+ "minimumContrastRatio": 4.5
18
+ }
@@ -0,0 +1,10 @@
1
+ [
2
+ "#2563eb",
3
+ "#dc2626",
4
+ "#16a34a",
5
+ "#d97706",
6
+ "#7c3aed",
7
+ "#0891b2",
8
+ "#db2777",
9
+ "#4b5563"
10
+ ]
@@ -0,0 +1,24 @@
1
+ {
2
+ "connectGaps": false,
3
+ "lineWidth": 1.5,
4
+ "opacity": 1,
5
+ "interpolation": "linear",
6
+ "smoothInterpolationSamplesPerSegment": 12,
7
+ "pattern": "solid",
8
+ "patternSegments": {
9
+ "solid": [],
10
+ "dashed": [8, 4],
11
+ "dotted": [1, 4],
12
+ "dash-dot": [8, 4, 1, 4]
13
+ },
14
+ "trendline": {
15
+ "show": false,
16
+ "method": "linear",
17
+ "degree": 2,
18
+ "samples": 120,
19
+ "minDegree": 1,
20
+ "maxDegree": 6,
21
+ "minSamples": 2,
22
+ "maxSamples": 512
23
+ }
24
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "valueScale": "linear",
3
+ "markerSize": 5,
4
+ "markerOpacity": 1,
5
+ "markerShape": "circle",
6
+ "lowColor": "#e0f2fe",
7
+ "highColor": "#7c3aed",
8
+ "colorStops": [],
9
+ "sizeScale": {
10
+ "enabled": false,
11
+ "minSize": 3,
12
+ "maxSize": 14,
13
+ "minValue": null,
14
+ "maxValue": null
15
+ },
16
+ "opacityScale": {
17
+ "enabled": false,
18
+ "minOpacity": 0.2,
19
+ "maxOpacity": 1,
20
+ "minValue": null,
21
+ "maxValue": null
22
+ },
23
+ "borderWidth": 0,
24
+ "borderColor": "rgba(15, 23, 42, 0.28)",
25
+ "markerLabels": {
26
+ "show": false,
27
+ "color": "#0f172a",
28
+ "font": "11px system-ui, sans-serif",
29
+ "lineHeight": 14,
30
+ "decimals": 0,
31
+ "prefix": "",
32
+ "suffix": "",
33
+ "offsetY": 6,
34
+ "collisionPadding": 2,
35
+ "formatter": null
36
+ },
37
+ "colorScaleLegend": {
38
+ "show": false,
39
+ "position": "right",
40
+ "title": "",
41
+ "width": 12,
42
+ "height": 128,
43
+ "offset": 16,
44
+ "tickCount": 3,
45
+ "tickValues": [],
46
+ "tickSize": 6,
47
+ "labelGap": 6,
48
+ "labelPrefix": "",
49
+ "labelSuffix": "",
50
+ "decimals": 0,
51
+ "font": "11px system-ui, sans-serif",
52
+ "color": "#475569",
53
+ "lineHeight": 14,
54
+ "titleGap": 4,
55
+ "borderColor": "rgba(15, 23, 42, 0.28)",
56
+ "borderWidth": 1
57
+ }
58
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "wheel": false,
3
+ "drag": false,
4
+ "pinch": false,
5
+ "mode": "xy",
6
+ "factor": 1.2,
7
+ "preventDefault": true,
8
+ "minDragDistance": 6,
9
+ "selectionFillStyle": "rgba(37, 99, 235, 0.12)",
10
+ "selectionStrokeStyle": "rgba(37, 99, 235, 0.8)",
11
+ "selectionLineWidth": 1
12
+ }
fastplotpy/defaults.py ADDED
@@ -0,0 +1,15 @@
1
+ """Source-pinned configurable defaults shared by the Python chart builders."""
2
+
3
+ from importlib import resources
4
+ import json
5
+
6
+
7
+ def get_defaults(name: str):
8
+ """Return a fresh copy of a fastPlotJs default JSON document."""
9
+ if "/" in name or "\\" in name or not name.removesuffix(".json").replace("-", "").isalnum():
10
+ raise ValueError("Invalid defaults name")
11
+ filename = name if name.endswith(".json") else f"{name}.json"
12
+ return json.loads(resources.files("fastplotpy").joinpath("defaults", filename).read_text(encoding="utf-8"))
13
+
14
+
15
+ DEFAULT_TRACE_COLORS = tuple(get_defaults("trace-colors"))
@@ -0,0 +1,118 @@
1
+ """Cartesian error-bar resolution and geometry from the source contract."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from math import isfinite
6
+ from typing import Mapping
7
+
8
+ from .defaults import get_defaults
9
+
10
+
11
+ def _option(value, inherited, name):
12
+ if value is None:
13
+ return inherited
14
+ if isinstance(value, bool) or not isinstance(value, (int, float)) or not isfinite(value) or value < 0:
15
+ raise ValueError(f"{name} must be a finite number >= 0")
16
+ return value
17
+
18
+
19
+ def resolve_error_bars(plot_value, trace_value, color):
20
+ defaults = get_defaults("error-bars")
21
+ plot_options = plot_value if isinstance(plot_value, Mapping) else {}
22
+ trace_options = trace_value if isinstance(trace_value, Mapping) else {}
23
+ plot_show = plot_value if isinstance(plot_value, bool) else plot_options.get("show", defaults["show"]) if isinstance(plot_value, Mapping) else False
24
+ show = trace_value if isinstance(trace_value, bool) else trace_options.get("show", defaults["show"]) if isinstance(trace_value, Mapping) else plot_show
25
+ plot_width = _option(plot_options.get("lineWidth"), defaults["lineWidth"], "errorBars.lineWidth")
26
+ plot_cap = _option(plot_options.get("capSize"), defaults["capSize"], "errorBars.capSize")
27
+ style = {
28
+ "color": trace_options.get("color") if isinstance(trace_options.get("color"), str) and trace_options["color"].strip()
29
+ else plot_options.get("color") if isinstance(plot_options.get("color"), str) and plot_options["color"].strip() else color,
30
+ "lineWidth": _option(trace_options.get("lineWidth"), plot_width, "trace.errorBars.lineWidth"),
31
+ "capSize": _option(trace_options.get("capSize"), plot_cap, "trace.errorBars.capSize"),
32
+ }
33
+ return {"show": show, "x": trace_options.get("x", plot_options.get("x", defaults["x"])),
34
+ "y": trace_options.get("y", plot_options.get("y", defaults["y"])), "style": style}
35
+
36
+
37
+ def endpoints(point: Mapping, dimension: str, axis: Mapping, source_index: int):
38
+ error = point.get(dimension + "Error")
39
+ if error is None:
40
+ return None
41
+ name = f"data[{source_index}].{dimension}Error"
42
+ if isinstance(error, bool):
43
+ raise ValueError(f"{name} must be a finite number >= 0")
44
+ if isinstance(error, (int, float)):
45
+ if not isfinite(error) or error < 0:
46
+ raise ValueError(f"{name} must be a finite number >= 0")
47
+ minus = plus = error
48
+ elif isinstance(error, Mapping):
49
+ minus, plus = error.get("minus"), error.get("plus")
50
+ if any(isinstance(value, bool) or not isinstance(value, (int, float)) or not isfinite(value) or value < 0 for value in (minus, plus)):
51
+ raise ValueError(f"{name} must contain finite minus/plus values >= 0")
52
+ else:
53
+ raise ValueError(f"{name} must contain finite minus/plus values >= 0")
54
+ if axis.get("categories"):
55
+ raise ValueError(f"{dimension}Error is not supported on categorical axes")
56
+ from .scene import _number, _scaled
57
+ value = _number(point[dimension], axis)
58
+ low, high = value - minus, value + plus
59
+ _scaled(low, axis)
60
+ _scaled(high, axis)
61
+ return low, high
62
+
63
+
64
+ def error_domain_values(trace: Mapping, resolved: Mapping, x_axis: Mapping, y_axis: Mapping):
65
+ x_values, y_values = [], []
66
+ if not resolved["show"]:
67
+ return x_values, y_values
68
+ for index, point in enumerate(trace.get("data") or []):
69
+ if point.get("x") is None or point.get("y") is None:
70
+ continue
71
+ for dimension, axis, output in (("x", x_axis, x_values), ("y", y_axis, y_values)):
72
+ if resolved[dimension]:
73
+ value = endpoints(point, dimension, axis, index)
74
+ if value:
75
+ output.extend(value)
76
+ return x_values, y_values
77
+
78
+
79
+ def error_geometry(trace: Mapping, resolved: Mapping, x_axis: Mapping, y_axis: Mapping,
80
+ x_domain: tuple[float, float], y_domain: tuple[float, float],
81
+ width: float, height: float, anchors: Mapping[int, Mapping] | None = None):
82
+ if not resolved["show"] or not (resolved["x"] or resolved["y"]) or resolved["style"]["lineWidth"] == 0:
83
+ return None
84
+ from .scene import _number, _scaled
85
+ def screen(value, domain, axis, size, invert=False):
86
+ position = (_scaled(value, axis) - domain[0]) / max(domain[1] - domain[0], 2.220446049250313e-16) * size
87
+ return size - position if invert else position
88
+ output = []
89
+ for index, point in enumerate(trace.get("data") or []):
90
+ if point.get("x") is None or point.get("y") is None:
91
+ continue
92
+ if anchors is not None and index not in anchors:
93
+ continue
94
+ anchor = anchors[index] if anchors is not None else None
95
+ center_x = anchor["x"] if anchor else screen(_number(point["x"], x_axis), x_domain, x_axis, width)
96
+ center_y = anchor["y"] if anchor else screen(_number(point["y"], y_axis), y_domain, y_axis, height, True)
97
+ if not 0 <= center_x <= width or not 0 <= center_y <= height:
98
+ continue
99
+ for dimension, axis, domain, size in (("x", x_axis, x_domain, width), ("y", y_axis, y_domain, height)):
100
+ if not resolved[dimension]:
101
+ continue
102
+ value = endpoints(point, dimension, axis, index)
103
+ if not value:
104
+ continue
105
+ raw = [screen(endpoint, domain, axis, size, dimension == "y") for endpoint in value]
106
+ start, end = sorted(raw)
107
+ if end < 0 or start > size:
108
+ continue
109
+ if dimension == "x":
110
+ bar = {"axis": "x", "sourceIndex": index, "x1": max(0, start), "y1": center_y,
111
+ "x2": min(width, end), "y2": center_y}
112
+ else:
113
+ bar = {"axis": "y", "sourceIndex": index, "x1": center_x, "y1": max(0, start),
114
+ "x2": center_x, "y2": min(height, end)}
115
+ bar["startCap"] = 0 <= start <= size
116
+ bar["endCap"] = 0 <= end <= size
117
+ output.append(bar)
118
+ return output or None