OTAnalytics 0.5.3__py3-none-any.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 (217) hide show
  1. OTAnalytics/__init__.py +0 -0
  2. OTAnalytics/__main__.py +13 -0
  3. OTAnalytics/adapter_intersect/__init__.py +0 -0
  4. OTAnalytics/adapter_ui/__init__.py +0 -0
  5. OTAnalytics/adapter_ui/abstract_button_quick_save_config.py +12 -0
  6. OTAnalytics/adapter_ui/abstract_canvas.py +25 -0
  7. OTAnalytics/adapter_ui/abstract_frame.py +19 -0
  8. OTAnalytics/adapter_ui/abstract_frame_canvas.py +17 -0
  9. OTAnalytics/adapter_ui/abstract_frame_filter.py +50 -0
  10. OTAnalytics/adapter_ui/abstract_frame_project.py +27 -0
  11. OTAnalytics/adapter_ui/abstract_frame_remark.py +7 -0
  12. OTAnalytics/adapter_ui/abstract_frame_track_plotting.py +11 -0
  13. OTAnalytics/adapter_ui/abstract_frame_track_statistics.py +13 -0
  14. OTAnalytics/adapter_ui/abstract_frame_tracks.py +29 -0
  15. OTAnalytics/adapter_ui/abstract_main_window.py +9 -0
  16. OTAnalytics/adapter_ui/abstract_progressbar_popup.py +38 -0
  17. OTAnalytics/adapter_ui/abstract_treeview_interface.py +31 -0
  18. OTAnalytics/adapter_ui/default_values.py +12 -0
  19. OTAnalytics/adapter_ui/dto.py +6 -0
  20. OTAnalytics/adapter_ui/flow_adapter.py +54 -0
  21. OTAnalytics/adapter_ui/helpers.py +41 -0
  22. OTAnalytics/adapter_ui/text_resources.py +51 -0
  23. OTAnalytics/adapter_ui/ui_texts.py +29 -0
  24. OTAnalytics/adapter_ui/view_model.py +447 -0
  25. OTAnalytics/adapter_visualization/__init__.py +0 -0
  26. OTAnalytics/adapter_visualization/color_provider.py +87 -0
  27. OTAnalytics/application/__init__.py +0 -0
  28. OTAnalytics/application/analysis/__init__.py +0 -0
  29. OTAnalytics/application/analysis/intersect.py +40 -0
  30. OTAnalytics/application/analysis/traffic_counting.py +945 -0
  31. OTAnalytics/application/analysis/traffic_counting_specification.py +60 -0
  32. OTAnalytics/application/application.py +713 -0
  33. OTAnalytics/application/config.py +57 -0
  34. OTAnalytics/application/config_specification.py +54 -0
  35. OTAnalytics/application/datastore.py +456 -0
  36. OTAnalytics/application/eventlist.py +162 -0
  37. OTAnalytics/application/exception.py +31 -0
  38. OTAnalytics/application/export_formats/__init__.py +0 -0
  39. OTAnalytics/application/export_formats/event_list.py +23 -0
  40. OTAnalytics/application/export_formats/export_mode.py +41 -0
  41. OTAnalytics/application/export_formats/road_user_assignments.py +46 -0
  42. OTAnalytics/application/export_formats/track_statistics.py +17 -0
  43. OTAnalytics/application/geometry.py +24 -0
  44. OTAnalytics/application/logger.py +51 -0
  45. OTAnalytics/application/parser/__init__.py +0 -0
  46. OTAnalytics/application/parser/cli_parser.py +128 -0
  47. OTAnalytics/application/parser/config_parser.py +128 -0
  48. OTAnalytics/application/parser/deserializer.py +4 -0
  49. OTAnalytics/application/parser/flow_parser.py +41 -0
  50. OTAnalytics/application/playback.py +7 -0
  51. OTAnalytics/application/plotting.py +326 -0
  52. OTAnalytics/application/progress.py +95 -0
  53. OTAnalytics/application/project.py +161 -0
  54. OTAnalytics/application/run_configuration.py +225 -0
  55. OTAnalytics/application/state.py +711 -0
  56. OTAnalytics/application/track_filter.py +149 -0
  57. OTAnalytics/application/ui/__init__.py +0 -0
  58. OTAnalytics/application/ui/frame_control.py +152 -0
  59. OTAnalytics/application/use_cases/__init__.py +0 -0
  60. OTAnalytics/application/use_cases/add_new_remark.py +9 -0
  61. OTAnalytics/application/use_cases/apply_cli_cuts.py +47 -0
  62. OTAnalytics/application/use_cases/clear_repositories.py +53 -0
  63. OTAnalytics/application/use_cases/config.py +52 -0
  64. OTAnalytics/application/use_cases/config_has_changed.py +121 -0
  65. OTAnalytics/application/use_cases/create_events.py +171 -0
  66. OTAnalytics/application/use_cases/create_intersection_events.py +282 -0
  67. OTAnalytics/application/use_cases/cut_tracks_with_sections.py +78 -0
  68. OTAnalytics/application/use_cases/editor/__init__.py +0 -0
  69. OTAnalytics/application/use_cases/editor/section_editor.py +138 -0
  70. OTAnalytics/application/use_cases/event_repository.py +65 -0
  71. OTAnalytics/application/use_cases/export_events.py +50 -0
  72. OTAnalytics/application/use_cases/filter_visualization.py +76 -0
  73. OTAnalytics/application/use_cases/flow_repository.py +101 -0
  74. OTAnalytics/application/use_cases/flow_statistics.py +27 -0
  75. OTAnalytics/application/use_cases/generate_flows.py +170 -0
  76. OTAnalytics/application/use_cases/get_current_project.py +10 -0
  77. OTAnalytics/application/use_cases/get_current_remark.py +9 -0
  78. OTAnalytics/application/use_cases/get_road_user_assignments.py +23 -0
  79. OTAnalytics/application/use_cases/highlight_intersections.py +388 -0
  80. OTAnalytics/application/use_cases/inside_cutting_section.py +88 -0
  81. OTAnalytics/application/use_cases/intersection_repository.py +37 -0
  82. OTAnalytics/application/use_cases/load_otconfig.py +76 -0
  83. OTAnalytics/application/use_cases/load_otflow.py +94 -0
  84. OTAnalytics/application/use_cases/load_track_files.py +84 -0
  85. OTAnalytics/application/use_cases/number_of_tracks_to_be_validated.py +7 -0
  86. OTAnalytics/application/use_cases/preload_input_files.py +34 -0
  87. OTAnalytics/application/use_cases/quick_save_configuration.py +37 -0
  88. OTAnalytics/application/use_cases/reset_project_config.py +16 -0
  89. OTAnalytics/application/use_cases/road_user_assignment_export.py +259 -0
  90. OTAnalytics/application/use_cases/save_otflow.py +46 -0
  91. OTAnalytics/application/use_cases/section_repository.py +198 -0
  92. OTAnalytics/application/use_cases/start_new_project.py +39 -0
  93. OTAnalytics/application/use_cases/suggest_save_path.py +113 -0
  94. OTAnalytics/application/use_cases/track_export.py +57 -0
  95. OTAnalytics/application/use_cases/track_repository.py +205 -0
  96. OTAnalytics/application/use_cases/track_statistics.py +167 -0
  97. OTAnalytics/application/use_cases/track_statistics_export.py +140 -0
  98. OTAnalytics/application/use_cases/track_to_video_repository.py +16 -0
  99. OTAnalytics/application/use_cases/update_project.py +42 -0
  100. OTAnalytics/application/use_cases/video_repository.py +136 -0
  101. OTAnalytics/assets/OpenTrafficCam_800.png +0 -0
  102. OTAnalytics/domain/__init__.py +0 -0
  103. OTAnalytics/domain/common.py +27 -0
  104. OTAnalytics/domain/date.py +85 -0
  105. OTAnalytics/domain/event.py +588 -0
  106. OTAnalytics/domain/files.py +18 -0
  107. OTAnalytics/domain/filter.py +256 -0
  108. OTAnalytics/domain/flow.py +236 -0
  109. OTAnalytics/domain/geometry.py +194 -0
  110. OTAnalytics/domain/intersect.py +155 -0
  111. OTAnalytics/domain/observer.py +35 -0
  112. OTAnalytics/domain/progress.py +68 -0
  113. OTAnalytics/domain/remark.py +9 -0
  114. OTAnalytics/domain/section.py +483 -0
  115. OTAnalytics/domain/track.py +348 -0
  116. OTAnalytics/domain/track_dataset.py +431 -0
  117. OTAnalytics/domain/track_repository.py +269 -0
  118. OTAnalytics/domain/types.py +33 -0
  119. OTAnalytics/domain/video.py +339 -0
  120. OTAnalytics/helpers/__init__.py +0 -0
  121. OTAnalytics/helpers/time_profiling.py +20 -0
  122. OTAnalytics/plugin_datastore/__init__.py +0 -0
  123. OTAnalytics/plugin_datastore/python_track_store.py +837 -0
  124. OTAnalytics/plugin_datastore/track_geometry_store/__init__.py +0 -0
  125. OTAnalytics/plugin_datastore/track_geometry_store/pygeos_store.py +402 -0
  126. OTAnalytics/plugin_datastore/track_store.py +803 -0
  127. OTAnalytics/plugin_filter/__init__.py +0 -0
  128. OTAnalytics/plugin_filter/dataframe_filter.py +324 -0
  129. OTAnalytics/plugin_filter/pandas_track_id.py +23 -0
  130. OTAnalytics/plugin_intersect/__init__.py +0 -0
  131. OTAnalytics/plugin_intersect/shapely/__init__.py +0 -0
  132. OTAnalytics/plugin_intersect/shapely/mapping.py +57 -0
  133. OTAnalytics/plugin_intersect/simple/__init__.py +0 -0
  134. OTAnalytics/plugin_intersect/simple/cut_tracks_with_sections.py +82 -0
  135. OTAnalytics/plugin_intersect/simple_intersect.py +33 -0
  136. OTAnalytics/plugin_intersect_parallelization/__init__.py +0 -0
  137. OTAnalytics/plugin_intersect_parallelization/multiprocessing.py +50 -0
  138. OTAnalytics/plugin_intersect_parallelization/sequential.py +28 -0
  139. OTAnalytics/plugin_number_of_tracks_to_be_validated/__init__.py +0 -0
  140. OTAnalytics/plugin_number_of_tracks_to_be_validated/calculation_strategy.py +115 -0
  141. OTAnalytics/plugin_number_of_tracks_to_be_validated/metric_rates_builder.py +36 -0
  142. OTAnalytics/plugin_number_of_tracks_to_be_validated/otc_classes.py +22 -0
  143. OTAnalytics/plugin_number_of_tracks_to_be_validated/svz/__init__.py +0 -0
  144. OTAnalytics/plugin_number_of_tracks_to_be_validated/svz/metric_rates.py +23 -0
  145. OTAnalytics/plugin_number_of_tracks_to_be_validated/svz/number_of_tracks_to_be_validated.py +69 -0
  146. OTAnalytics/plugin_number_of_tracks_to_be_validated/tracks_as_dataframe_provider.py +38 -0
  147. OTAnalytics/plugin_parser/__init__.py +0 -0
  148. OTAnalytics/plugin_parser/argparse_cli_parser.py +189 -0
  149. OTAnalytics/plugin_parser/dataformat_versions.py +22 -0
  150. OTAnalytics/plugin_parser/export.py +290 -0
  151. OTAnalytics/plugin_parser/json_parser.py +70 -0
  152. OTAnalytics/plugin_parser/otconfig_parser.py +352 -0
  153. OTAnalytics/plugin_parser/ottrk_dataformat.py +63 -0
  154. OTAnalytics/plugin_parser/otvision_parser.py +1101 -0
  155. OTAnalytics/plugin_parser/pandas_parser.py +125 -0
  156. OTAnalytics/plugin_parser/road_user_assignment_export.py +78 -0
  157. OTAnalytics/plugin_parser/streaming_parser.py +349 -0
  158. OTAnalytics/plugin_parser/track_export.py +102 -0
  159. OTAnalytics/plugin_parser/track_statistics_export.py +137 -0
  160. OTAnalytics/plugin_progress/__init__.py +0 -0
  161. OTAnalytics/plugin_progress/multiprocessing_progress.py +48 -0
  162. OTAnalytics/plugin_progress/tqdm_progressbar.py +35 -0
  163. OTAnalytics/plugin_prototypes/__init__.py +0 -0
  164. OTAnalytics/plugin_prototypes/event_visualization.py +79 -0
  165. OTAnalytics/plugin_prototypes/eventlist_exporter/__init__.py +0 -0
  166. OTAnalytics/plugin_prototypes/eventlist_exporter/eventlist_exporter.py +354 -0
  167. OTAnalytics/plugin_prototypes/track_visualization/__init__.py +0 -0
  168. OTAnalytics/plugin_prototypes/track_visualization/track_viz.py +846 -0
  169. OTAnalytics/plugin_ui/__init__.py +0 -0
  170. OTAnalytics/plugin_ui/cli.py +489 -0
  171. OTAnalytics/plugin_ui/customtkinter_gui/__init__.py +0 -0
  172. OTAnalytics/plugin_ui/customtkinter_gui/abstract_ctk_frame.py +51 -0
  173. OTAnalytics/plugin_ui/customtkinter_gui/button_quick_save_config.py +22 -0
  174. OTAnalytics/plugin_ui/customtkinter_gui/canvas_observer.py +26 -0
  175. OTAnalytics/plugin_ui/customtkinter_gui/constants.py +70 -0
  176. OTAnalytics/plugin_ui/customtkinter_gui/custom_containers.py +164 -0
  177. OTAnalytics/plugin_ui/customtkinter_gui/dummy_viewmodel.py +1833 -0
  178. OTAnalytics/plugin_ui/customtkinter_gui/frame_analysis.py +87 -0
  179. OTAnalytics/plugin_ui/customtkinter_gui/frame_bbox_offset.py +90 -0
  180. OTAnalytics/plugin_ui/customtkinter_gui/frame_canvas.py +223 -0
  181. OTAnalytics/plugin_ui/customtkinter_gui/frame_configuration.py +36 -0
  182. OTAnalytics/plugin_ui/customtkinter_gui/frame_date_filter_control.py +147 -0
  183. OTAnalytics/plugin_ui/customtkinter_gui/frame_files.py +124 -0
  184. OTAnalytics/plugin_ui/customtkinter_gui/frame_filter.py +860 -0
  185. OTAnalytics/plugin_ui/customtkinter_gui/frame_flows.py +149 -0
  186. OTAnalytics/plugin_ui/customtkinter_gui/frame_project.py +466 -0
  187. OTAnalytics/plugin_ui/customtkinter_gui/frame_remarks.py +30 -0
  188. OTAnalytics/plugin_ui/customtkinter_gui/frame_sections.py +171 -0
  189. OTAnalytics/plugin_ui/customtkinter_gui/frame_track_plotting.py +155 -0
  190. OTAnalytics/plugin_ui/customtkinter_gui/frame_track_statistics.py +159 -0
  191. OTAnalytics/plugin_ui/customtkinter_gui/frame_tracks.py +94 -0
  192. OTAnalytics/plugin_ui/customtkinter_gui/frame_videos.py +107 -0
  193. OTAnalytics/plugin_ui/customtkinter_gui/gui.py +345 -0
  194. OTAnalytics/plugin_ui/customtkinter_gui/helpers.py +160 -0
  195. OTAnalytics/plugin_ui/customtkinter_gui/line_section.py +700 -0
  196. OTAnalytics/plugin_ui/customtkinter_gui/messagebox.py +136 -0
  197. OTAnalytics/plugin_ui/customtkinter_gui/scrollable_xy_frame.py +200 -0
  198. OTAnalytics/plugin_ui/customtkinter_gui/state.py +25 -0
  199. OTAnalytics/plugin_ui/customtkinter_gui/style.py +110 -0
  200. OTAnalytics/plugin_ui/customtkinter_gui/toplevel_export_counts.py +162 -0
  201. OTAnalytics/plugin_ui/customtkinter_gui/toplevel_export_events.py +121 -0
  202. OTAnalytics/plugin_ui/customtkinter_gui/toplevel_flows.py +228 -0
  203. OTAnalytics/plugin_ui/customtkinter_gui/toplevel_progress.py +168 -0
  204. OTAnalytics/plugin_ui/customtkinter_gui/toplevel_sections.py +127 -0
  205. OTAnalytics/plugin_ui/customtkinter_gui/toplevel_template.py +81 -0
  206. OTAnalytics/plugin_ui/customtkinter_gui/treeview_template.py +93 -0
  207. OTAnalytics/plugin_ui/customtkinter_gui/utility_widgets.py +38 -0
  208. OTAnalytics/plugin_ui/intersection_repository.py +34 -0
  209. OTAnalytics/plugin_ui/main_application.py +1373 -0
  210. OTAnalytics/plugin_ui/visualization/__init__.py +0 -0
  211. OTAnalytics/plugin_ui/visualization/visualization.py +981 -0
  212. OTAnalytics/plugin_video_processing/video_reader.py +165 -0
  213. OTAnalytics/version.py +1 -0
  214. otanalytics-0.5.3.dist-info/METADATA +45 -0
  215. otanalytics-0.5.3.dist-info/RECORD +217 -0
  216. otanalytics-0.5.3.dist-info/WHEEL +4 -0
  217. otanalytics-0.5.3.dist-info/licenses/LICENSE +674 -0
File without changes
@@ -0,0 +1,13 @@
1
+ import warnings
2
+
3
+ from OTAnalytics.plugin_ui.main_application import ApplicationStarter
4
+
5
+ warnings.simplefilter(action="ignore", category=FutureWarning)
6
+
7
+
8
+ def main() -> None:
9
+ ApplicationStarter().start()
10
+
11
+
12
+ if __name__ == "__main__":
13
+ main()
File without changes
File without changes
@@ -0,0 +1,12 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class AbstractButtonQuickSaveConfig(ABC):
5
+
6
+ @abstractmethod
7
+ def set_state_changed_color(self) -> None:
8
+ raise NotImplementedError
9
+
10
+ @abstractmethod
11
+ def set_default_color(self) -> None:
12
+ raise NotImplementedError
@@ -0,0 +1,25 @@
1
+ from abc import abstractmethod
2
+
3
+ from customtkinter import CTkCanvas
4
+
5
+ from OTAnalytics.adapter_ui.helpers import WidgetPositionProvider
6
+
7
+ # from OTAnalytics.plugin_ui.canvas_observer import EventHandler
8
+
9
+
10
+ class AbstractCanvas(CTkCanvas, WidgetPositionProvider):
11
+ # TODO: Properly define abstract property here and in derived class(es)
12
+ # @property
13
+ # @abstractmethod
14
+ # def event_handler(self) -> EventHandler:
15
+ # pass
16
+
17
+ # TODO: Define whole interface (all properties and methods) required by viewmodel
18
+
19
+ @abstractmethod
20
+ def introduce_to_viewmodel(self) -> None:
21
+ raise NotImplementedError
22
+
23
+ @abstractmethod
24
+ def add_preview_image(self) -> None:
25
+ raise NotImplementedError
@@ -0,0 +1,19 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class AbstractFrame(ABC):
5
+ @abstractmethod
6
+ def set_enabled_general_buttons(self, enabled: bool) -> None:
7
+ raise NotImplementedError
8
+
9
+ @abstractmethod
10
+ def set_enabled_add_buttons(self, enabled: bool) -> None:
11
+ raise NotImplementedError
12
+
13
+ @abstractmethod
14
+ def set_enabled_change_single_item_buttons(self, enabled: bool) -> None:
15
+ raise NotImplementedError
16
+
17
+ @abstractmethod
18
+ def set_enabled_change_multiple_items_buttons(self, enabled: bool) -> None:
19
+ raise NotImplementedError
@@ -0,0 +1,17 @@
1
+ from abc import abstractmethod
2
+
3
+ from OTAnalytics.domain.track import TrackImage
4
+
5
+
6
+ class AbstractFrameCanvas:
7
+ @abstractmethod
8
+ def introduce_to_viewmodel(self) -> None:
9
+ pass
10
+
11
+ @abstractmethod
12
+ def update_background(self, image: TrackImage) -> None:
13
+ pass
14
+
15
+ @abstractmethod
16
+ def clear_image(self) -> None:
17
+ pass
@@ -0,0 +1,50 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from OTAnalytics.adapter_ui.dto import DateRangeDto
4
+
5
+
6
+ class AbstractFrameFilter(ABC):
7
+ @abstractmethod
8
+ def _introduce_to_viewmodel(self) -> None:
9
+ pass
10
+
11
+ @abstractmethod
12
+ def set_active_color_on_filter_by_date_button(self) -> None:
13
+ pass
14
+
15
+ @abstractmethod
16
+ def set_inactive_color_on_filter_by_date_button(self) -> None:
17
+ pass
18
+
19
+ @abstractmethod
20
+ def set_active_color_on_filter_by_class_button(self) -> None:
21
+ pass
22
+
23
+ @abstractmethod
24
+ def set_inactive_color_on_filter_by_class_button(self) -> None:
25
+ pass
26
+
27
+ @abstractmethod
28
+ def enable_filter_by_date_button(self) -> None:
29
+ pass
30
+
31
+ @abstractmethod
32
+ def disable_filter_by_date_button(self) -> None:
33
+ pass
34
+
35
+ @abstractmethod
36
+ def enable_filter_by_class_button(self) -> None:
37
+ pass
38
+
39
+ @abstractmethod
40
+ def disable_filter_by_class_button(self) -> None:
41
+ pass
42
+
43
+ @abstractmethod
44
+ def update_date_range(self, date_range: DateRangeDto) -> None:
45
+ pass
46
+
47
+ @abstractmethod
48
+ def reset(self) -> None:
49
+ """Reset all filters."""
50
+ raise NotImplementedError
@@ -0,0 +1,27 @@
1
+ from abc import abstractmethod
2
+ from datetime import datetime
3
+ from typing import Optional
4
+
5
+
6
+ class AbstractFrameProject:
7
+ @abstractmethod
8
+ def introduce_to_viewmodel(self) -> None:
9
+ pass
10
+
11
+ @abstractmethod
12
+ def update(self, name: str, start_date: Optional[datetime]) -> None:
13
+ pass
14
+
15
+ @abstractmethod
16
+ def set_enabled_general_buttons(self, enabled: bool) -> None:
17
+ raise NotImplementedError
18
+
19
+
20
+ class AbstractFrameSvzMetadata:
21
+ @abstractmethod
22
+ def introduce_to_viewmodel(self) -> None:
23
+ pass
24
+
25
+ @abstractmethod
26
+ def update(self, metadata: dict) -> None:
27
+ pass
@@ -0,0 +1,7 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class AbstractFrameRemark(ABC):
5
+ @abstractmethod
6
+ def load_remark(self) -> None:
7
+ pass
@@ -0,0 +1,11 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class AbstractFrameTrackPlotting(ABC):
5
+ @abstractmethod
6
+ def introduce_to_viewmodel(self) -> None:
7
+ raise NotImplementedError
8
+
9
+ @abstractmethod
10
+ def reset_layers(self) -> None:
11
+ raise NotImplementedError
@@ -0,0 +1,13 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from OTAnalytics.application.use_cases.track_statistics import TrackStatistics
4
+
5
+
6
+ class AbstractFrameTrackStatistics(ABC):
7
+ @abstractmethod
8
+ def introduce_to_viewmodel(self) -> None:
9
+ raise NotImplementedError
10
+
11
+ @abstractmethod
12
+ def update_track_statistics(self, track_statistics: TrackStatistics) -> None:
13
+ raise NotImplementedError
@@ -0,0 +1,29 @@
1
+ from abc import abstractmethod
2
+
3
+ from OTAnalytics.plugin_ui.customtkinter_gui.abstract_ctk_frame import AbstractCTkFrame
4
+
5
+
6
+ class AbstractFrameTracks(AbstractCTkFrame):
7
+ @abstractmethod
8
+ def introduce_to_viewmodel(self) -> None:
9
+ raise NotImplementedError
10
+
11
+ @abstractmethod
12
+ def update_offset(self, new_offset_x: float, new_offset_y: float) -> None:
13
+ raise NotImplementedError
14
+
15
+ @abstractmethod
16
+ def configure_offset_button(self, color: str, enabled: bool) -> None:
17
+ raise NotImplementedError
18
+
19
+ @abstractmethod
20
+ def enable_update_offset_button(self, enabled: bool) -> None:
21
+ raise NotImplementedError
22
+
23
+ @abstractmethod
24
+ def set_offset_button_color(self, color: str) -> None:
25
+ raise NotImplementedError
26
+
27
+ @abstractmethod
28
+ def get_default_offset_button_color(self) -> str:
29
+ raise NotImplementedError
@@ -0,0 +1,9 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from OTAnalytics.adapter_ui.helpers import WidgetPositionProvider
4
+
5
+
6
+ class AbstractMainWindow(WidgetPositionProvider, ABC):
7
+ @abstractmethod
8
+ def introduce_to_viewmodel(self) -> None:
9
+ raise NotImplementedError
@@ -0,0 +1,38 @@
1
+ from abc import ABC, abstractmethod
2
+ from tkinter import Widget
3
+ from typing import Optional
4
+
5
+ from OTAnalytics.domain.progress import Counter
6
+
7
+
8
+ class AbstractPopupProgressbar(ABC):
9
+ def update_progress(self) -> None:
10
+ raise NotImplementedError
11
+
12
+
13
+ class ProgressbarPopupBuilder(ABC):
14
+ def __init__(self) -> None:
15
+ self._master: Optional[Widget] = None
16
+ self._counter: Optional[Counter] = None
17
+ self._total: Optional[int] = None
18
+ self._description = ""
19
+ self._unit = ""
20
+
21
+ def add_widget(self, widget: Widget) -> None:
22
+ self._master = widget
23
+
24
+ def add_counter(self, counter: Counter) -> None:
25
+ self._counter = counter
26
+
27
+ def add_description(self, description: str) -> None:
28
+ self._description = description
29
+
30
+ def add_unit(self, unit: str) -> None:
31
+ self._unit = unit
32
+
33
+ def add_total(self, value: int) -> None:
34
+ self._total = value
35
+
36
+ @abstractmethod
37
+ def build(self) -> AbstractPopupProgressbar:
38
+ raise NotImplementedError
@@ -0,0 +1,31 @@
1
+ from abc import abstractmethod
2
+
3
+ from OTAnalytics.adapter_ui.helpers import WidgetPositionProvider
4
+
5
+
6
+ class AbstractTreeviewInterface(WidgetPositionProvider):
7
+ # TODO: add property viewmodel
8
+
9
+ @abstractmethod
10
+ def _introduce_to_viewmodel(self) -> None:
11
+ raise NotImplementedError
12
+
13
+ @abstractmethod
14
+ def _notify_viewmodel_about_selected_item_ids(self, ids: list[str]) -> None:
15
+ raise NotImplementedError
16
+
17
+ @abstractmethod
18
+ def update_items(self) -> None:
19
+ raise NotImplementedError
20
+
21
+ @abstractmethod
22
+ def update_selected_items(self, item_ids: list[str]) -> None:
23
+ raise NotImplementedError
24
+
25
+ @abstractmethod
26
+ def enable(self) -> None:
27
+ raise NotImplementedError
28
+
29
+ @abstractmethod
30
+ def disable(self) -> None:
31
+ raise NotImplementedError
@@ -0,0 +1,12 @@
1
+ from OTAnalytics.domain.section import RelativeOffsetCoordinate
2
+
3
+ RELATIVE_SECTION_OFFSET: RelativeOffsetCoordinate = RelativeOffsetCoordinate(0.5, 0.5)
4
+ DATE_FORMAT: str = r"%Y-%m-%d"
5
+ DATETIME_FORMAT: str = r"%Y-%m-%d %H:%M:%S"
6
+ DATE_FORMAT_PLACEHOLDER = "yyyy-mm-dd"
7
+
8
+ DATE_FORMAT_GERMAN: str = r"%d.%m.%Y"
9
+ DATETIME_FORMAT_GERMAN: str = r"%d.%m.%Y %H:%M:%S"
10
+ DATE_FORMAT_PLACEHOLDER_GERMAN = "dd.mm.yyyy"
11
+
12
+ SUPPORTED_FORMATS: list[str] = [DATE_FORMAT, DATE_FORMAT_GERMAN]
@@ -0,0 +1,6 @@
1
+ from typing import TypedDict
2
+
3
+
4
+ class DateRangeDto(TypedDict):
5
+ start_date: str
6
+ end_date: str
@@ -0,0 +1,54 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from OTAnalytics.domain.section import COORDINATES, Section
4
+
5
+
6
+ class SectionRefPointCalculator(ABC):
7
+ def coordinates_from_section(self, section: Section) -> list[tuple[int, int]]:
8
+ coordinates_dicts = section.to_dict()[COORDINATES]
9
+ return [(d["x"], d["y"]) for d in coordinates_dicts]
10
+
11
+ @abstractmethod
12
+ def get_reference_point(self, section: Section) -> tuple[float, float]:
13
+ """
14
+ Calculates a reference point on a section.
15
+ Raises:
16
+ NotImplementedError: If derived classes have not implemented this method
17
+ Returns:
18
+ tuple[float, float]: Reference point
19
+ """
20
+ raise NotImplementedError
21
+
22
+
23
+ class InnerSegmentsCenterCalculator(SectionRefPointCalculator):
24
+ def get_reference_point(self, section: Section) -> tuple[float, float]:
25
+ coordinates = self.coordinates_from_section(section)
26
+ num_coordinates = len(coordinates)
27
+ if num_coordinates == 0:
28
+ raise ValueError("LineSection has no coordinates")
29
+ if num_coordinates % 2 == 0:
30
+ # Calculate center between innermost two points
31
+ innermost_coordinates = coordinates[
32
+ num_coordinates // 2 - 1 : num_coordinates // 2 + 1
33
+ ]
34
+ center_x = (innermost_coordinates[0][0] + innermost_coordinates[1][0]) / 2
35
+ center_y = (innermost_coordinates[0][1] + innermost_coordinates[1][1]) / 2
36
+ else:
37
+ # Calculate innermost point
38
+ innermost_coordinate_index = len(coordinates) // 2
39
+ center_x, center_y = coordinates[innermost_coordinate_index]
40
+ return center_x, center_y
41
+
42
+
43
+ class GeometricCenterCalculator(SectionRefPointCalculator):
44
+ def get_reference_point(self, section: Section) -> tuple[float, float]:
45
+ coordinates = self.coordinates_from_section(section)
46
+ total_x = 0
47
+ total_y = 0
48
+ num_points = len(coordinates)
49
+ for x, y in coordinates:
50
+ total_x += x
51
+ total_y += y
52
+ center_x = total_x / num_points
53
+ center_y = total_y / num_points
54
+ return center_x, center_y
@@ -0,0 +1,41 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class WidgetPositionProvider(ABC):
5
+ @abstractmethod
6
+ def get_position(self, offset: tuple[float, float] = (0.5, 0.5)) -> tuple[int, int]:
7
+ raise NotImplementedError
8
+
9
+
10
+ def remove_wildcard_from(file_extension: str) -> str:
11
+ return file_extension[1:] if file_extension.startswith("*") else file_extension
12
+
13
+
14
+ def ensure_file_extension_is_present(
15
+ file: str, allowed_extensions: list[str], defaultextension: str
16
+ ) -> str:
17
+ """
18
+ Ensure that the file contains a file extension. If no extension is appended, the
19
+ defaultextension will be used.
20
+
21
+ Args:
22
+ file (str): file to ensure it has a file extension
23
+ allowed_extensions (list[str]): extensions that are allowed
24
+ defaultextension (str): default extension to be added if extension is missing
25
+
26
+ Returns:
27
+ Path: path object with file extension
28
+ """
29
+ if not file:
30
+ return ""
31
+ file_extension = remove_wildcard_from(defaultextension)
32
+ allowed_file_extensions = set(
33
+ [remove_wildcard_from(ext) for ext in allowed_extensions]
34
+ )
35
+ allowed_file_extensions.add(file_extension)
36
+ for allowed_extension in allowed_file_extensions:
37
+ if file.endswith(allowed_extension):
38
+ return file
39
+ if file_extension.startswith("."):
40
+ return file + file_extension
41
+ return f"{file}.{file_extension}"
@@ -0,0 +1,51 @@
1
+ from dataclasses import dataclass
2
+ from typing import Iterator
3
+
4
+ COLUMN_NAME = "column_name"
5
+
6
+
7
+ @dataclass(frozen=True, order=True)
8
+ class ColumnResource:
9
+ """
10
+ Represents a row in a treeview with an id and a dict of values to be shown.
11
+ The dicts keys represent the columns and the values represent the cell values.
12
+ """
13
+
14
+ id: str
15
+ values: dict[str, str]
16
+
17
+
18
+ class ColumnResources:
19
+ def __init__(
20
+ self, resources: list[ColumnResource], lookup_column: str = COLUMN_NAME
21
+ ) -> None:
22
+ self._resources = resources
23
+ self._lookup_column = lookup_column
24
+ self._to_id = self._create_to_id(resources)
25
+ self._to_name = self._create_to_name(resources)
26
+
27
+ def _create_to_id(self, resources: list[ColumnResource]) -> dict[str, str]:
28
+ return {
29
+ resource.values[self._lookup_column]: resource.id for resource in resources
30
+ }
31
+
32
+ def _create_to_name(self, resources: list[ColumnResource]) -> dict[str, str]:
33
+ return {
34
+ resource.id: resource.values[self._lookup_column] for resource in resources
35
+ }
36
+
37
+ @property
38
+ def names(self) -> list[str]:
39
+ return [resource.values[self._lookup_column] for resource in self._resources]
40
+
41
+ def get_name_for(self, resource_id: str) -> str:
42
+ return self._to_name.get(resource_id, "")
43
+
44
+ def get_id_for(self, name: str) -> str:
45
+ return self._to_id.get(name, "")
46
+
47
+ def has(self, resource_id: str) -> bool:
48
+ return resource_id in [resource.id for resource in self._resources]
49
+
50
+ def __iter__(self) -> Iterator[ColumnResource]:
51
+ return self._resources.__iter__()
@@ -0,0 +1,29 @@
1
+ from OTAnalytics.application.project import (
2
+ CountingDayType,
3
+ DirectionOfStationing,
4
+ WeatherType,
5
+ )
6
+
7
+ DIRECTIONS_OF_STATIONING = {
8
+ DirectionOfStationing.IN_DIRECTION: "In Stationierungsrichtung",
9
+ DirectionOfStationing.OPPOSITE_DIRECTION: "Gegen Stationierungsrichtung",
10
+ }
11
+
12
+ COUNTING_DAY_TYPES = {
13
+ CountingDayType.NOW_1: "1. NoW",
14
+ CountingDayType.NOW_2: "2. NoW",
15
+ CountingDayType.FR_1: "1. Fr",
16
+ CountingDayType.FR_2: "2. Fr",
17
+ CountingDayType.SO_1: "1. So",
18
+ CountingDayType.SO_2: "2. So",
19
+ CountingDayType.FEW_1: "1. FeW",
20
+ CountingDayType.FEW_2: "2. FeW",
21
+ }
22
+
23
+ WEATHER_TYPES = {
24
+ WeatherType.SUN: "sonnig",
25
+ WeatherType.CLOUD: "bewölkt",
26
+ WeatherType.RAIN: "Regen",
27
+ WeatherType.SNOW: "Schnee",
28
+ WeatherType.FOG: "Nebel",
29
+ }