code-loader 1.0.209__tar.gz → 1.0.211__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 (37) hide show
  1. {code_loader-1.0.209 → code_loader-1.0.211}/PKG-INFO +3 -4
  2. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/contract/datasetclasses.py +2 -2
  3. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/contract/enums.py +1 -0
  4. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/contract/responsedataclasses.py +29 -0
  5. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/contract/visualizer_classes.py +58 -2
  6. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/inner_leap_binder/leapbinder_decorators.py +4 -3
  7. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/plot_functions/plot_functions.py +22 -1
  8. {code_loader-1.0.209 → code_loader-1.0.211}/pyproject.toml +1 -1
  9. {code_loader-1.0.209 → code_loader-1.0.211}/LICENSE +0 -0
  10. {code_loader-1.0.209 → code_loader-1.0.211}/README.md +0 -0
  11. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/__init__.py +0 -0
  12. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/contract/__init__.py +0 -0
  13. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/contract/exceptions.py +0 -0
  14. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/contract/mapping.py +0 -0
  15. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/contract/sim_config.py +0 -0
  16. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/default_losses.py +0 -0
  17. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/default_metrics.py +0 -0
  18. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/experiment_api/__init__.py +0 -0
  19. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/experiment_api/api.py +0 -0
  20. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/experiment_api/cli_config_utils.py +0 -0
  21. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/experiment_api/client.py +0 -0
  22. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/experiment_api/epoch.py +0 -0
  23. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/experiment_api/experiment.py +0 -0
  24. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/experiment_api/experiment_context.py +0 -0
  25. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/experiment_api/types.py +0 -0
  26. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/experiment_api/utils.py +0 -0
  27. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/experiment_api/workingspace_config_utils.py +0 -0
  28. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/inner_leap_binder/__init__.py +0 -0
  29. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/inner_leap_binder/leapbinder.py +0 -0
  30. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/leaploader.py +0 -0
  31. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/leaploaderbase.py +0 -0
  32. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/mixpanel_tracker.py +0 -0
  33. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/plot_functions/__init__.py +0 -0
  34. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/plot_functions/visualize.py +0 -0
  35. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/utils.py +0 -0
  36. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/visualizers/__init__.py +0 -0
  37. {code_loader-1.0.209 → code_loader-1.0.211}/code_loader/visualizers/default_visualizers.py +0 -0
@@ -1,9 +1,9 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.1
2
2
  Name: code-loader
3
- Version: 1.0.209
3
+ Version: 1.0.211
4
4
  Summary:
5
+ Home-page: https://github.com/tensorleap/code-loader
5
6
  License: MIT
6
- License-File: LICENSE
7
7
  Author: dorhar
8
8
  Author-email: doron.harnoy@tensorleap.ai
9
9
  Requires-Python: >=3.8,<3.13
@@ -20,7 +20,6 @@ Requires-Dist: numpy (>=2.3.2,<3.0.0) ; python_version >= "3.11" and python_vers
20
20
  Requires-Dist: psutil (>=5.9.5,<6.0.0)
21
21
  Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
22
22
  Requires-Dist: requests (>=2.32.3,<3.0.0)
23
- Project-URL: Homepage, https://github.com/tensorleap/code-loader
24
23
  Project-URL: Repository, https://github.com/tensorleap/code-loader
25
24
  Description-Content-Type: text/markdown
26
25
 
@@ -8,7 +8,7 @@ import numpy.typing as npt
8
8
  from code_loader.contract.enums import DataStateType, DataStateEnum, LeapDataType, ConfusionMatrixValue, \
9
9
  MetricDirection, DatasetMetadataType, LatentSpaceReduction, CustomLatentSpaceComputedAt
10
10
  from code_loader.contract.visualizer_classes import LeapImage, LeapText, LeapGraph, LeapHorizontalBar, \
11
- LeapTextMask, LeapImageMask, LeapImageWithBBox, LeapImageWithHeatmap, LeapVideo, LeapAudio
11
+ LeapTextMask, LeapImageMask, LeapImageWithBBox, LeapImageWithHeatmap, LeapVideo, LeapAudio, LeapPointCloud
12
12
  from code_loader.contract.sim_config import SimConfig
13
13
 
14
14
  custom_latent_space_attribute = "custom_latent_space"
@@ -213,7 +213,7 @@ VisualizerCallableInterface = Union[
213
213
  ]
214
214
 
215
215
  LeapData = Union[LeapImage, LeapText, LeapGraph, LeapHorizontalBar, LeapImageMask, LeapTextMask, LeapImageWithBBox,
216
- LeapImageWithHeatmap, LeapVideo, LeapAudio]
216
+ LeapImageWithHeatmap, LeapVideo, LeapAudio, LeapPointCloud]
217
217
 
218
218
  CustomCallableInterface = Callable[..., Any]
219
219
 
@@ -29,6 +29,7 @@ class LeapDataType(Enum):
29
29
  ImageWithHeatmap = 'ImageWithHeatmap'
30
30
  Video = 'Video'
31
31
  Audio = 'Audio'
32
+ PointCloud = 'PointCloud'
32
33
 
33
34
 
34
35
  class MetricDirection(Enum):
@@ -131,6 +131,35 @@ class BoundingBox:
131
131
  metadata: Optional[Dict[str, Union[str, int, float]]] = None
132
132
 
133
133
 
134
+ @dataclass
135
+ class BoundingBox3D:
136
+ """
137
+ Represents an oriented 3D bounding box in a point cloud's coordinate frame.
138
+
139
+ Attributes:
140
+ x, y, z (float): The center of the box.
141
+ width (float): Extent along the box's local y axis.
142
+ length (float): Extent along the box's local x axis (the heading axis).
143
+ height (float): Extent along the box's local z axis.
144
+ yaw (float): Rotation about +z in radians, counter-clockwise from +x. The +length/2 face is the front.
145
+ label (str): The class name of the box.
146
+ confidence (float): Prediction score, typically in [0, 1]; 1.0 for ground truth.
147
+ metadata (Optional[Dict[str, Union[str, int, float]]]): Optional extra fields shown with the box.
148
+
149
+ Corners are the local points (±length/2, ±width/2, ±height/2) rotated by yaw about z, then translated to (x, y, z).
150
+ """
151
+ x: float
152
+ y: float
153
+ z: float
154
+ width: float
155
+ length: float
156
+ height: float
157
+ yaw: float
158
+ label: str
159
+ confidence: float = 1.0
160
+ metadata: Optional[Dict[str, Union[str, int, float]]] = None
161
+
162
+
134
163
 
135
164
  @dataclass
136
165
  class LeapAnalysisConfiguration:
@@ -5,7 +5,7 @@ import numpy.typing as npt
5
5
  from dataclasses import dataclass
6
6
 
7
7
  from code_loader.contract.enums import LeapDataType
8
- from code_loader.contract.responsedataclasses import BoundingBox
8
+ from code_loader.contract.responsedataclasses import BoundingBox, BoundingBox3D
9
9
 
10
10
 
11
11
  class LeapValidationError(Exception):
@@ -377,6 +377,61 @@ class LeapAudio:
377
377
  raise LeapValidationError(f'sample_rate must be a positive int, got {self.sample_rate}')
378
378
 
379
379
 
380
+ @dataclass
381
+ class LeapPointCloud:
382
+ """
383
+ Visualizer representing a set of 3D points for Tensorleap: a LiDAR sweep, a depth-camera frame, a mesh's
384
+ vertices, or any (N, 3) point set. The UI renders it with an orbit camera; the engine stores the points as a
385
+ raw float32 blob.
386
+
387
+ Attributes:
388
+ points (npt.NDArray[np.float32]): The points, shaped [N, 3] as x, y, z in any consistent frame and unit.
389
+ intensity (Optional[npt.NDArray[np.float32]]): Optional per-point scalar shaped [N]: the LiDAR return
390
+ intensity in most formats, but any per-point value (reflectance, depth, an error) fits. The UI offers it as a
391
+ color mode.
392
+ bounding_boxes (Optional[List[BoundingBox3D]]): Optional oriented 3D boxes in the same frame as `points`.
393
+ An empty list is valid.
394
+ type (LeapDataType): The data type, default is LeapDataType.PointCloud.
395
+
396
+ Example:
397
+ points = (np.random.rand(1000, 3) * 50).astype(np.float32)
398
+ box = BoundingBox3D(x=10, y=0, z=1, width=2, length=4.5, height=1.8, yaw=0.3, label="car", confidence=0.9)
399
+ leap_point_cloud = LeapPointCloud(points=points, intensity=points[:, 2].copy(), bounding_boxes=[box])
400
+ """
401
+ points: npt.NDArray[np.float32]
402
+ intensity: Optional[npt.NDArray[np.float32]] = None
403
+ bounding_boxes: Optional[List[BoundingBox3D]] = None
404
+ type: LeapDataType = LeapDataType.PointCloud
405
+
406
+ def __post_init__(self) -> None:
407
+ validate_type(self.type, LeapDataType.PointCloud)
408
+ validate_type(type(self.points), np.ndarray)
409
+ validate_type(self.points.dtype, np.float32)
410
+ validate_type(len(self.points.shape), 2, 'Point cloud points must be of shape 2 [N, 3]')
411
+ if self.points.shape[1] != 3 or self.points.shape[0] < 1:
412
+ raise LeapValidationError(
413
+ f'Point cloud points must be of shape [N, 3] with N >= 1, got {self.points.shape}')
414
+ if not np.isfinite(self.points).all():
415
+ raise LeapValidationError('Point cloud points must be finite (no NaN/Inf)')
416
+ if self.intensity is not None:
417
+ validate_type(type(self.intensity), np.ndarray)
418
+ validate_type(self.intensity.dtype, np.float32)
419
+ if self.intensity.shape != (self.points.shape[0],):
420
+ raise LeapValidationError(
421
+ f'Point cloud intensity shape {self.intensity.shape} must be ({self.points.shape[0]},)')
422
+ if not np.isfinite(self.intensity).all():
423
+ raise LeapValidationError('Point cloud intensity must be finite (no NaN/Inf)')
424
+ if self.bounding_boxes is not None:
425
+ validate_type(type(self.bounding_boxes), list)
426
+ for box in self.bounding_boxes:
427
+ validate_type(type(box), BoundingBox3D)
428
+ numbers = (box.x, box.y, box.z, box.width, box.length, box.height, box.yaw, box.confidence)
429
+ if not all(np.isfinite(float(v)) for v in numbers):
430
+ raise LeapValidationError(f'BoundingBox3D "{box.label}" has a non-finite field')
431
+ if min(box.width, box.length, box.height) <= 0:
432
+ raise LeapValidationError(f'BoundingBox3D "{box.label}" extents must be positive')
433
+
434
+
380
435
  map_leap_data_type_to_visualizer_class = {
381
436
  LeapDataType.Image.value: LeapImage,
382
437
  LeapDataType.Graph.value: LeapGraph,
@@ -387,5 +442,6 @@ map_leap_data_type_to_visualizer_class = {
387
442
  LeapDataType.TextMask.value: LeapTextMask,
388
443
  LeapDataType.ImageWithBBox.value: LeapImageWithBBox,
389
444
  LeapDataType.ImageWithHeatmap.value: LeapImageWithHeatmap,
390
- LeapDataType.Audio.value: LeapAudio
445
+ LeapDataType.Audio.value: LeapAudio,
446
+ LeapDataType.PointCloud.value: LeapPointCloud,
391
447
  }
@@ -34,8 +34,8 @@ from code_loader.contract.enums import MetricDirection, LeapDataType, DatasetMet
34
34
  from code_loader import leap_binder, LeapLoader
35
35
  from code_loader.contract.mapping import NodeMapping, NodeMappingType, NodeConnection
36
36
  from code_loader.contract.visualizer_classes import LeapImage, LeapImageMask, LeapTextMask, LeapText, LeapGraph, \
37
- LeapHorizontalBar, LeapImageWithBBox, LeapImageWithHeatmap, LeapVideo, LeapAudio, LeapValidationError, \
38
- map_leap_data_type_to_visualizer_class
37
+ LeapHorizontalBar, LeapImageWithBBox, LeapImageWithHeatmap, LeapVideo, LeapAudio, LeapPointCloud, \
38
+ LeapValidationError, map_leap_data_type_to_visualizer_class
39
39
  from code_loader.inner_leap_binder.leapbinder import mapping_runtime_mode_env_var_mame, \
40
40
  _reject_stringized_sample_preprocess_response
41
41
  from code_loader.mixpanel_tracker import clear_integration_events, AnalyticsEvent, emit_integration_event_once
@@ -1593,7 +1593,8 @@ def tensorleap_custom_visualizer(name: str, visualizer_type: LeapDataType,
1593
1593
  LeapDataType.ImageWithBBox: LeapImageWithBBox,
1594
1594
  LeapDataType.ImageWithHeatmap: LeapImageWithHeatmap,
1595
1595
  LeapDataType.Video: LeapVideo,
1596
- LeapDataType.Audio: LeapAudio
1596
+ LeapDataType.Audio: LeapAudio,
1597
+ LeapDataType.PointCloud: LeapPointCloud
1597
1598
  }
1598
1599
  validate_output_structure(result, func_name=user_function.__name__,
1599
1600
  expected_type_name=result_type_map[visualizer_type])
@@ -20,7 +20,7 @@ from textwrap import wrap
20
20
  import math
21
21
 
22
22
  from code_loader.contract.visualizer_classes import LeapImage, LeapImageWithBBox, LeapGraph, LeapText, \
23
- LeapHorizontalBar, LeapImageMask, LeapTextMask, LeapImageWithHeatmap, LeapVideo
23
+ LeapHorizontalBar, LeapImageMask, LeapTextMask, LeapImageWithHeatmap, LeapVideo, LeapPointCloud
24
24
  from code_loader.utils import rescale_min_max
25
25
 
26
26
 
@@ -464,6 +464,26 @@ def plot_image_with_heatmap(leap_data: LeapImageWithHeatmap, title: str) -> None
464
464
 
465
465
 
466
466
 
467
+ @run_only_on_non_mapping_mode()
468
+ def plot_point_cloud(leap_data: LeapPointCloud, title: str) -> None:
469
+ """Bird's-eye view (x right, y up, equal aspect): points colored by height, box footprints as polylines."""
470
+ points = leap_data.points
471
+ fig, ax = plt.subplots(figsize=(7, 7))
472
+ fig.patch.set_facecolor('black')
473
+ ax.set_facecolor('black')
474
+ ax.scatter(points[:, 0], points[:, 1], s=1, c=points[:, 2], cmap='viridis')
475
+ for box in leap_data.bounding_boxes or []:
476
+ c, s = np.cos(box.yaw), np.sin(box.yaw)
477
+ local = np.array([[1, 1], [1, -1], [-1, -1], [-1, 1], [1, 1]], dtype=np.float64) * [box.length / 2, box.width / 2]
478
+ corners = local @ np.array([[c, -s], [s, c]]).T + [box.x, box.y]
479
+ ax.plot(corners[:, 0], corners[:, 1], linewidth=1.5, color='orange')
480
+ ax.text(box.x, box.y, f'{box.label} {box.confidence:.2f}', color='orange', fontsize=6)
481
+ ax.set_aspect('equal')
482
+ ax.set_title(f'{title} ({points.shape[0]} points)', color='white')
483
+ ax.tick_params(colors='white')
484
+ plt.show()
485
+
486
+
467
487
  plot_switch = {
468
488
  LeapDataType.Image: plot_image,
469
489
  LeapDataType.Text: plot_text_with_heatmap,
@@ -474,4 +494,5 @@ plot_switch = {
474
494
  LeapDataType.ImageWithHeatmap: plot_image_with_heatmap,
475
495
  LeapDataType.ImageWithBBox: plot_image_with_b_box,
476
496
  LeapDataType.Video: plot_video,
497
+ LeapDataType.PointCloud: plot_point_cloud,
477
498
  }
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "code-loader"
3
- version = "1.0.209"
3
+ version = "1.0.211"
4
4
  description = ""
5
5
  authors = ["dorhar <doron.harnoy@tensorleap.ai>"]
6
6
  license = "MIT"
File without changes
File without changes