gammasimtools 0.22.0__py3-none-any.whl → 0.23.0__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 (114) hide show
  1. {gammasimtools-0.22.0.dist-info → gammasimtools-0.23.0.dist-info}/METADATA +2 -1
  2. {gammasimtools-0.22.0.dist-info → gammasimtools-0.23.0.dist-info}/RECORD +114 -112
  3. simtools/_version.py +2 -2
  4. simtools/application_control.py +118 -0
  5. simtools/applications/calculate_incident_angles.py +17 -22
  6. simtools/applications/convert_all_model_parameters_from_simtel.py +28 -43
  7. simtools/applications/convert_geo_coordinates_of_array_elements.py +26 -45
  8. simtools/applications/convert_model_parameter_from_simtel.py +21 -41
  9. simtools/applications/db_add_file_to_db.py +12 -13
  10. simtools/applications/db_add_simulation_model_from_repository_to_db.py +20 -33
  11. simtools/applications/db_add_value_from_json_to_db.py +28 -23
  12. simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +19 -34
  13. simtools/applications/db_generate_compound_indexes.py +11 -13
  14. simtools/applications/db_get_array_layouts_from_db.py +19 -39
  15. simtools/applications/db_get_file_from_db.py +15 -17
  16. simtools/applications/db_get_parameter_from_db.py +33 -35
  17. simtools/applications/db_inspect_databases.py +10 -11
  18. simtools/applications/db_upload_model_repository.py +13 -31
  19. simtools/applications/derive_ctao_array_layouts.py +16 -21
  20. simtools/applications/derive_mirror_rnda.py +9 -14
  21. simtools/applications/derive_photon_electron_spectrum.py +7 -10
  22. simtools/applications/derive_psf_parameters.py +13 -20
  23. simtools/applications/derive_trigger_rates.py +6 -9
  24. simtools/applications/docs_produce_array_element_report.py +22 -23
  25. simtools/applications/docs_produce_calibration_reports.py +26 -24
  26. simtools/applications/docs_produce_model_parameter_reports.py +15 -22
  27. simtools/applications/docs_produce_simulation_configuration_report.py +21 -22
  28. simtools/applications/generate_array_config.py +14 -33
  29. simtools/applications/generate_corsika_histograms.py +22 -43
  30. simtools/applications/generate_default_metadata.py +15 -36
  31. simtools/applications/generate_regular_arrays.py +11 -15
  32. simtools/applications/generate_simtel_event_data.py +23 -33
  33. simtools/applications/maintain_simulation_model_add_production.py +12 -19
  34. simtools/applications/maintain_simulation_model_compare_productions.py +10 -12
  35. simtools/applications/maintain_simulation_model_verify_production_tables.py +8 -11
  36. simtools/applications/merge_tables.py +14 -23
  37. simtools/applications/plot_array_layout.py +77 -54
  38. simtools/applications/plot_simtel_events.py +11 -13
  39. simtools/applications/plot_tabular_data.py +17 -38
  40. simtools/applications/plot_tabular_data_for_model_parameter.py +16 -23
  41. simtools/applications/print_version.py +14 -42
  42. simtools/applications/production_derive_corsika_limits.py +5 -9
  43. simtools/applications/production_derive_statistics.py +12 -25
  44. simtools/applications/production_generate_grid.py +20 -48
  45. simtools/applications/production_merge_corsika_limits.py +17 -21
  46. simtools/applications/run_application.py +12 -32
  47. simtools/applications/simulate_flasher.py +21 -25
  48. simtools/applications/simulate_illuminator.py +7 -14
  49. simtools/applications/simulate_pedestals.py +13 -13
  50. simtools/applications/simulate_prod.py +21 -33
  51. simtools/applications/simulate_prod_htcondor_generator.py +11 -25
  52. simtools/applications/submit_array_layouts.py +15 -18
  53. simtools/applications/submit_data_from_external.py +18 -34
  54. simtools/applications/submit_model_parameter_from_external.py +27 -40
  55. simtools/applications/validate_camera_efficiency.py +23 -21
  56. simtools/applications/validate_camera_fov.py +21 -26
  57. simtools/applications/validate_cumulative_psf.py +27 -35
  58. simtools/applications/validate_file_using_schema.py +15 -33
  59. simtools/applications/validate_optics.py +26 -32
  60. simtools/camera/camera_efficiency.py +0 -2
  61. simtools/configuration/commandline_parser.py +32 -4
  62. simtools/configuration/configurator.py +0 -5
  63. simtools/corsika/corsika_config.py +0 -5
  64. simtools/data_model/data_reader.py +0 -2
  65. simtools/data_model/metadata_collector.py +0 -2
  66. simtools/data_model/model_data_writer.py +0 -2
  67. simtools/data_model/validate_data.py +0 -2
  68. simtools/db/db_handler.py +0 -2
  69. simtools/io/hdf5_handler.py +0 -5
  70. simtools/io/legacy_data_handler.py +0 -5
  71. simtools/job_execution/job_manager.py +0 -3
  72. simtools/layout/array_layout.py +0 -2
  73. simtools/layout/telescope_position.py +0 -2
  74. simtools/model/array_model.py +2 -4
  75. simtools/model/calibration_model.py +0 -2
  76. simtools/model/camera.py +0 -2
  77. simtools/model/mirrors.py +0 -2
  78. simtools/model/model_parameter.py +30 -7
  79. simtools/model/model_utils.py +0 -5
  80. simtools/model/site_model.py +0 -2
  81. simtools/model/telescope_model.py +0 -2
  82. simtools/production_configuration/calculate_statistical_uncertainties_grid_point.py +0 -2
  83. simtools/production_configuration/derive_production_statistics.py +0 -2
  84. simtools/production_configuration/interpolation_handler.py +0 -2
  85. simtools/ray_tracing/psf_analysis.py +0 -2
  86. simtools/ray_tracing/ray_tracing.py +0 -2
  87. simtools/reporting/docs_auto_report_generator.py +108 -0
  88. simtools/reporting/docs_read_parameters.py +1 -7
  89. simtools/runners/corsika_runner.py +0 -2
  90. simtools/runners/corsika_simtel_runner.py +0 -2
  91. simtools/runners/simtel_runner.py +0 -2
  92. simtools/schemas/model_parameters/transit_time_random.schema.yml +29 -0
  93. simtools/simtel/simtel_config_reader.py +0 -2
  94. simtools/simtel/simtel_config_writer.py +31 -13
  95. simtools/simtel/simtel_io_metadata.py +3 -3
  96. simtools/simtel/simulator_array.py +9 -21
  97. simtools/simtel/simulator_camera_efficiency.py +0 -2
  98. simtools/simtel/simulator_light_emission.py +1 -3
  99. simtools/simtel/simulator_ray_tracing.py +0 -2
  100. simtools/simulator.py +0 -5
  101. simtools/testing/assertions.py +2 -2
  102. simtools/testing/configuration.py +17 -4
  103. simtools/utils/general.py +5 -13
  104. simtools/utils/geometry.py +0 -5
  105. simtools/utils/names.py +1 -13
  106. simtools/version.py +61 -0
  107. simtools/visualization/plot_array_layout.py +129 -23
  108. simtools/visualization/plot_incident_angles.py +0 -2
  109. simtools/visualization/plot_simtel_events.py +0 -11
  110. simtools/visualization/visualize.py +0 -12
  111. {gammasimtools-0.22.0.dist-info → gammasimtools-0.23.0.dist-info}/WHEEL +0 -0
  112. {gammasimtools-0.22.0.dist-info → gammasimtools-0.23.0.dist-info}/entry_points.txt +0 -0
  113. {gammasimtools-0.22.0.dist-info → gammasimtools-0.23.0.dist-info}/licenses/LICENSE +0 -0
  114. {gammasimtools-0.22.0.dist-info → gammasimtools-0.23.0.dist-info}/top_level.txt +0 -0
@@ -5,6 +5,7 @@ import os
5
5
  from pathlib import Path
6
6
 
7
7
  import simtools.utils.general as gen
8
+ import simtools.version as simtools_version
8
9
  from simtools.io import ascii_handler
9
10
 
10
11
  _logger = logging.getLogger(__name__)
@@ -130,11 +131,23 @@ def configure(config, tmp_test_directory, request):
130
131
 
131
132
 
132
133
  def _skip_test_for_model_version(config, model_version_requested):
133
- """Skip test if model version requested is not supported."""
134
- if config.get("model_version_use_current") is None or model_version_requested is None:
134
+ """
135
+ Skip test if model version requested is not supported.
136
+
137
+ Compares full and major.minor version strings.
138
+ """
139
+ if not (config.get("model_version_use_current") and model_version_requested):
135
140
  return
136
- model_version_config = config["configuration"]["model_version"]
137
- if model_version_requested != model_version_config:
141
+ model_version_config = str(config["configuration"]["model_version"])
142
+
143
+ if (
144
+ simtools_version.compare_versions(
145
+ model_version_requested,
146
+ model_version_config,
147
+ level=simtools_version.version_kind(model_version_requested),
148
+ )
149
+ != 0
150
+ ):
138
151
  raise VersionError(
139
152
  f"Model version requested {model_version_requested} not supported for this test"
140
153
  )
simtools/utils/general.py CHANGED
@@ -13,17 +13,6 @@ from urllib.parse import urlparse
13
13
 
14
14
  import numpy as np
15
15
 
16
- __all__ = [
17
- "change_dict_keys_case",
18
- "clear_default_sim_telarray_cfg_directories",
19
- "collect_final_lines",
20
- "collect_kwargs",
21
- "get_log_excerpt",
22
- "get_log_level_from_user",
23
- "remove_substring_recursively_from_dict",
24
- "set_default_kwargs",
25
- ]
26
-
27
16
  _logger = logging.getLogger(__name__)
28
17
 
29
18
 
@@ -345,7 +334,7 @@ def resolve_file_patterns(file_names):
345
334
  return _files
346
335
 
347
336
 
348
- def pack_tar_file(tar_file_name, file_list):
337
+ def pack_tar_file(tar_file_name, file_list, sub_dir=None):
349
338
  """
350
339
  Pack files into a tar.gz archive.
351
340
 
@@ -355,6 +344,8 @@ def pack_tar_file(tar_file_name, file_list):
355
344
  Name of the output tar.gz file.
356
345
  file_list: list
357
346
  List of files to include in the archive.
347
+ sub_dir: str, optional
348
+ Subdirectory within the archive to place the files.
358
349
  """
359
350
  file_list = [Path(f) for f in file_list]
360
351
  base = Path(os.path.commonpath([f.resolve() for f in file_list]))
@@ -365,7 +356,8 @@ def pack_tar_file(tar_file_name, file_list):
365
356
 
366
357
  with tarfile.open(tar_file_name, "w:gz") as tar:
367
358
  for file in file_list:
368
- tar.add(file, arcname=file.name)
359
+ arc_name = Path(sub_dir) / file.name if sub_dir else file.name
360
+ tar.add(file, arcname=str(arc_name))
369
361
 
370
362
 
371
363
  def get_log_excerpt(log_file, n_last_lines=30):
@@ -7,11 +7,6 @@ import astropy.units as u
7
7
  import numpy as np
8
8
  from astropy.units import UnitsError
9
9
 
10
- __all__ = [
11
- "convert_2d_to_radial_distr",
12
- "rotate",
13
- ]
14
-
15
10
  _logger = logging.getLogger(__name__)
16
11
 
17
12
 
simtools/utils/names.py CHANGED
@@ -28,18 +28,6 @@ from simtools.constants import (
28
28
 
29
29
  _logger = logging.getLogger(__name__)
30
30
 
31
- __all__ = [
32
- "generate_file_name",
33
- "get_array_element_type_from_name",
34
- "get_site_from_array_element_name",
35
- "sanitize_name",
36
- "simtel_config_file_name",
37
- "simtel_single_mirror_list_file_name",
38
- "validate_array_element_id_name",
39
- "validate_array_element_name",
40
- "validate_site_name",
41
- ]
42
-
43
31
  # Mapping of db collection names to class keys
44
32
  db_collections_to_class_keys = {
45
33
  "sites": ["Site"],
@@ -122,7 +110,7 @@ def site_names():
122
110
  @cache
123
111
  def array_element_design_types(array_element_type):
124
112
  """
125
- Get array element site types (e.g., 'design' or 'flashcam').
113
+ Get array element design type (e.g., 'design' or 'flashcam').
126
114
 
127
115
  Default values are ['design', 'test'].
128
116
 
simtools/version.py CHANGED
@@ -6,6 +6,9 @@
6
6
 
7
7
  from packaging.version import InvalidVersion, Version
8
8
 
9
+ MAJOR_MINOR_PATCH = "major.minor.patch"
10
+ MAJOR_MINOR = "major.minor"
11
+
9
12
  try:
10
13
  try:
11
14
  from ._dev_version import version
@@ -128,3 +131,61 @@ def sort_versions(version_list, reverse=False):
128
131
  return [str(v) for v in sorted(map(Version, version_list), reverse=reverse)]
129
132
  except InvalidVersion as exc:
130
133
  raise ValueError(f"Invalid version in list: {version_list}") from exc
134
+
135
+
136
+ def version_kind(version_string):
137
+ """
138
+ Determine the kind of version string.
139
+
140
+ Parameters
141
+ ----------
142
+ version_string : str
143
+ The version string to analyze.
144
+
145
+ Returns
146
+ -------
147
+ str
148
+ The kind of version string ("major.minor", "major.minor.patch", or "major").
149
+ """
150
+ try:
151
+ ver = Version(version_string)
152
+ except InvalidVersion as exc:
153
+ raise ValueError(f"Invalid version string: {version_string}") from exc
154
+ if ver.release and len(ver.release) >= 3:
155
+ return MAJOR_MINOR_PATCH
156
+ if len(ver.release) == 2:
157
+ return MAJOR_MINOR
158
+ return "major"
159
+
160
+
161
+ def compare_versions(version_string_1, version_string_2, level=MAJOR_MINOR_PATCH):
162
+ """
163
+ Compare two versions at the given level: "major", "major.minor", "major.minor.patch".
164
+
165
+ Parameters
166
+ ----------
167
+ version_string_1 : str
168
+ First version string to compare.
169
+ version_string_2 : str
170
+ Second version string to compare.
171
+ level : str, optional
172
+ Level of comparison: "major", "major.minor", or "major.minor.patch"
173
+
174
+ Returns
175
+ -------
176
+ int
177
+ -1 if version_string_1 < version_string_2
178
+ 0 if version_string_1 == version_string_2
179
+ 1 if version_string_1 > version_string_2
180
+ """
181
+ ver1 = Version(version_string_1).release
182
+ ver2 = Version(version_string_2).release
183
+
184
+ if level == "major":
185
+ ver1, ver2 = ver1[:1], ver2[:1]
186
+ elif level == MAJOR_MINOR:
187
+ ver1, ver2 = ver1[:2], ver2[:2]
188
+ elif level != MAJOR_MINOR_PATCH:
189
+ raise ValueError(f"Unknown level: {level}")
190
+
191
+ return (ver1 > ver2) - (ver1 < ver2)
@@ -13,8 +13,6 @@ from simtools.utils import geometry as transf
13
13
  from simtools.utils import names
14
14
  from simtools.visualization import legend_handlers as leg_h
15
15
 
16
- __all__ = ["get_telescope_patch", "plot_array_layout"]
17
-
18
16
 
19
17
  def plot_array_layout(
20
18
  telescopes,
@@ -22,6 +20,9 @@ def plot_array_layout(
22
20
  axes_range=None,
23
21
  marker_scaling=1.0,
24
22
  background_telescopes=None,
23
+ grayed_out_elements=None,
24
+ highlighted_elements=None,
25
+ legend_location="best",
25
26
  ):
26
27
  """
27
28
  Plot telescope array layout.
@@ -38,6 +39,12 @@ def plot_array_layout(
38
39
  Marker size scale factor.
39
40
  background_telescopes : Table or None
40
41
  Optional background telescope table.
42
+ grayed_out_elements : list or None
43
+ List of telescope names to plot as gray circles.
44
+ highlighted_elements : list or None
45
+ List of telescope names to plot with red circles around them.
46
+ legend_location : str
47
+ Location of the legend (default "best").
41
48
 
42
49
  Returns
43
50
  -------
@@ -46,55 +53,105 @@ def plot_array_layout(
46
53
  """
47
54
  fig, ax = plt.subplots(1)
48
55
 
49
- patches, plot_range = get_patches(ax, telescopes, show_tel_label, axes_range, marker_scaling)
56
+ patches, plot_range, highlighted_patches = get_patches(
57
+ ax,
58
+ telescopes,
59
+ show_tel_label,
60
+ axes_range,
61
+ marker_scaling,
62
+ grayed_out_elements,
63
+ highlighted_elements,
64
+ )
50
65
 
51
66
  if background_telescopes is not None:
52
- bg_patches, bg_range = get_patches(
67
+ bg_patches, bg_range, _ = get_patches(
53
68
  ax, background_telescopes, False, axes_range, marker_scaling
54
69
  )
55
70
  ax.add_collection(PatchCollection(bg_patches, match_original=True, alpha=0.1))
56
71
  if axes_range is None:
57
72
  plot_range = max(plot_range, bg_range)
58
73
 
59
- update_legend(ax, telescopes)
60
- finalize_plot(ax, patches, "Easting [m]", "Northing [m]", plot_range)
74
+ update_legend(ax, telescopes, grayed_out_elements, legend_location)
75
+ finalize_plot(ax, patches, "Easting [m]", "Northing [m]", plot_range, highlighted_patches)
61
76
 
62
77
  return fig
63
78
 
64
79
 
65
- def get_patches(ax, telescopes, show_tel_label, axes_range, marker_scaling):
80
+ def get_patches(
81
+ ax,
82
+ telescopes,
83
+ show_tel_label,
84
+ axes_range,
85
+ marker_scaling,
86
+ grayed_out_elements=None,
87
+ highlighted_elements=None,
88
+ ):
66
89
  """
67
90
  Get plot patches and axis range.
68
91
 
92
+ Parameters
93
+ ----------
94
+ ax : Axes
95
+ Matplotlib axes object.
96
+ telescopes : Table
97
+ Telescope data table.
98
+ show_tel_label : bool
99
+ Show telescope labels.
100
+ axes_range : float or None
101
+ Axis range, auto if None.
102
+ marker_scaling : float
103
+ Marker size scale factor.
104
+ grayed_out_elements : list or None
105
+ List of telescope names to plot as gray circles.
106
+ highlighted_elements : list or None
107
+ List of telescope names to plot with red circles around them.
108
+
69
109
  Returns
70
110
  -------
71
111
  patches : list
72
112
  List of telescope patches.
73
113
  axes_range : float
74
114
  Calculated or input axis range.
115
+ highlighted_patches : list
116
+ List of highlighted telescope patches.
75
117
  """
76
118
  pos_x, pos_y = get_positions(telescopes)
77
119
  telescopes["pos_x_rotated"] = Column(pos_x)
78
120
  telescopes["pos_y_rotated"] = Column(pos_y)
79
121
 
80
- patches, radii = create_patches(telescopes, marker_scaling, show_tel_label, ax)
122
+ patches, radii, highlighted_patches = create_patches(
123
+ telescopes, marker_scaling, show_tel_label, ax, grayed_out_elements, highlighted_elements
124
+ )
81
125
 
82
126
  if axes_range:
83
- return patches, axes_range
127
+ return patches, axes_range, highlighted_patches
84
128
 
85
129
  r = max(radii).value
86
130
  max_x = max(abs(pos_x.min().value), abs(pos_x.max().value)) + r
87
131
  max_y = max(abs(pos_y.min().value), abs(pos_y.max().value)) + r
88
132
  updated_axes_range = max(max_x, max_y) * 1.1
89
133
 
90
- return patches, updated_axes_range
134
+ return patches, updated_axes_range, highlighted_patches
91
135
 
92
136
 
93
137
  @u.quantity_input(x=u.m, y=u.m, radius=u.m)
94
- def get_telescope_patch(name, x, y, radius):
138
+ def get_telescope_patch(name, x, y, radius, is_grayed_out=False):
95
139
  """
96
140
  Create patch for a telescope.
97
141
 
142
+ Parameters
143
+ ----------
144
+ name : str
145
+ Telescope name.
146
+ x : Quantity
147
+ X position.
148
+ y : Quantity
149
+ Y position.
150
+ radius : Quantity
151
+ Telescope radius.
152
+ is_grayed_out : bool
153
+ Whether to plot telescope in gray.
154
+
98
155
  Returns
99
156
  -------
100
157
  patch : Patch
@@ -103,20 +160,23 @@ def get_telescope_patch(name, x, y, radius):
103
160
  tel_type = names.get_array_element_type_from_name(name)
104
161
  x, y, r = x.to(u.m), y.to(u.m), radius.to(u.m)
105
162
 
163
+ color = "gray" if is_grayed_out else leg_h.get_telescope_config(tel_type)["color"]
164
+
106
165
  if tel_type == "SCTS":
107
166
  return mpatches.Rectangle(
108
167
  ((x - r / 2).value, (y - r / 2).value),
109
168
  width=r.value,
110
169
  height=r.value,
111
- fill=False,
112
- color=leg_h.get_telescope_config(tel_type)["color"],
170
+ fill=is_grayed_out,
171
+ color=color,
113
172
  )
114
173
 
115
174
  return mpatches.Circle(
116
175
  (x.value, y.value),
117
176
  radius=r.value,
118
- fill=tel_type.startswith("MST"),
119
- color=leg_h.get_telescope_config(tel_type)["color"],
177
+ fill=is_grayed_out or tel_type.startswith("MST"),
178
+ alpha=0.5 if is_grayed_out else 1.0,
179
+ color=color,
120
180
  )
121
181
 
122
182
 
@@ -143,35 +203,71 @@ def get_positions(telescopes):
143
203
  return transf.rotate(x, y, locale_rotate_angle) if locale_rotate_angle != 0 else (x, y)
144
204
 
145
205
 
146
- def create_patches(telescopes, scale, show_label, ax):
206
+ def create_patches(
207
+ telescopes, scale, show_label, ax, grayed_out_elements=None, highlighted_elements=None
208
+ ):
147
209
  """
148
210
  Create telescope patches and labels.
149
211
 
212
+ Parameters
213
+ ----------
214
+ telescopes : Table
215
+ Telescope data table.
216
+ scale : float
217
+ Marker size scale factor.
218
+ show_label : bool
219
+ Show telescope labels.
220
+ ax : Axes
221
+ Matplotlib axes object.
222
+ grayed_out_elements : list or None
223
+ List of telescope names to plot as gray circles.
224
+ highlighted_elements : list or None
225
+ List of telescope names to plot with red circles around them.
226
+
150
227
  Returns
151
228
  -------
152
229
  patches : list
153
230
  Shape patches.
154
231
  radii : list
155
232
  Telescope radii.
233
+ highlighted_patches : list
234
+ List of highlighted telescope patches.
156
235
  """
157
- patches, radii = [], []
236
+ patches, radii, highlighted_patches = [], [], []
158
237
  fontsize, scale_factor = (4, 2) if len(telescopes) > 30 else (8, 1)
159
238
 
239
+ grayed_out_set = set(grayed_out_elements) if grayed_out_elements else set()
240
+ highlighted_set = set(highlighted_elements) if highlighted_elements else set()
241
+
160
242
  for tel in telescopes:
161
243
  name = get_telescope_name(tel)
162
244
  radius = get_sphere_radius(tel)
163
245
  radii.append(radius)
164
246
  tel_type = names.get_array_element_type_from_name(name)
165
247
 
248
+ is_grayed_out = name in grayed_out_set
249
+ is_highlighted = name in highlighted_set
250
+
166
251
  patches.append(
167
252
  get_telescope_patch(
168
253
  tel_type,
169
254
  tel["pos_x_rotated"],
170
255
  tel["pos_y_rotated"],
171
256
  scale_factor * radius * scale,
257
+ is_grayed_out=is_grayed_out,
172
258
  )
173
259
  )
174
260
 
261
+ if is_highlighted:
262
+ highlight_patch = mpatches.Circle(
263
+ (tel["pos_x_rotated"].value, tel["pos_y_rotated"].value),
264
+ radius=(scale_factor * radius * scale * 4).value,
265
+ fill=False,
266
+ color="red",
267
+ linewidth=1,
268
+ )
269
+ highlighted_patches.append(highlight_patch)
270
+
175
271
  if show_label:
176
272
  ax.text(
177
273
  tel["pos_x_rotated"].value,
@@ -182,7 +278,7 @@ def create_patches(telescopes, scale, show_label, ax):
182
278
  fontsize=fontsize,
183
279
  )
184
280
 
185
- return patches, radii
281
+ return patches, radii, highlighted_patches
186
282
 
187
283
 
188
284
  def get_telescope_name(tel):
@@ -213,10 +309,16 @@ def get_sphere_radius(tel):
213
309
  return tel["sphere_radius"] if "sphere_radius" in tel.colnames else 10.0 * u.m
214
310
 
215
311
 
216
- def update_legend(ax, telescopes):
312
+ def update_legend(ax, telescopes, grayed_out_elements=None, legend_location="best"):
217
313
  """Add legend for telescope types and counts."""
218
- names_list = [get_telescope_name(tel) for tel in telescopes]
219
- types = [names.get_array_element_type_from_name(n) for n in names_list]
314
+ grayed_out_set = set(grayed_out_elements) if grayed_out_elements else set()
315
+
316
+ types = []
317
+ for tel in telescopes:
318
+ tel_name = get_telescope_name(tel)
319
+ if tel_name not in grayed_out_set:
320
+ types.append(names.get_array_element_type_from_name(tel_name))
321
+
220
322
  counts = Counter(types)
221
323
 
222
324
  objs, labels = [], []
@@ -239,12 +341,16 @@ def update_legend(ax, telescopes):
239
341
 
240
342
  handler_map[telescope_type] = BaseLegendHandlerWrapper(telescope_type)
241
343
 
242
- ax.legend(objs, labels, handler_map=handler_map, prop={"size": 11}, loc="best")
344
+ ax.legend(objs, labels, handler_map=handler_map, prop={"size": 11}, loc=legend_location)
243
345
 
244
346
 
245
- def finalize_plot(ax, patches, x_title, y_title, axes_range):
347
+ def finalize_plot(ax, patches, x_title, y_title, axes_range, highlighted_patches=None):
246
348
  """Finalize plot appearance and limits."""
247
349
  ax.add_collection(PatchCollection(patches, match_original=True))
350
+
351
+ if highlighted_patches:
352
+ ax.add_collection(PatchCollection(highlighted_patches, match_original=True))
353
+
248
354
  ax.set(xlabel=x_title, ylabel=y_title)
249
355
  ax.tick_params(labelsize=8)
250
356
  ax.axis("square")
@@ -11,8 +11,6 @@ import astropy.units as u
11
11
  import matplotlib.pyplot as plt
12
12
  import numpy as np
13
13
 
14
- __all__ = ["plot_incident_angles"]
15
-
16
14
  Y_AXIS_BIN_COUNT_LABEL = "Density"
17
15
 
18
16
 
@@ -16,17 +16,6 @@ from simtools.data_model.metadata_collector import MetadataCollector
16
16
  from simtools.visualization.plot_corsika_histograms import save_figs_to_pdf
17
17
  from simtools.visualization.visualize import save_figure
18
18
 
19
- __all__ = [
20
- "generate_and_save_plots",
21
- "plot_simtel_event_image",
22
- "plot_simtel_integrated_pedestal_image",
23
- "plot_simtel_integrated_signal_image",
24
- "plot_simtel_peak_timing",
25
- "plot_simtel_step_traces",
26
- "plot_simtel_time_traces",
27
- "plot_simtel_waveform_matrix",
28
- ]
29
-
30
19
  _logger = logging.getLogger(__name__)
31
20
 
32
21
  # Reusable literal constants (duplicated from visualize to avoid circular deps)
@@ -12,18 +12,6 @@ from astropy.table import QTable
12
12
  from cycler import cycler
13
13
  from matplotlib import gridspec
14
14
 
15
- __all__ = [
16
- "get_colors",
17
- "get_lines",
18
- "get_markers",
19
- "plot_1d",
20
- "plot_hist_2d",
21
- "plot_table",
22
- "save_figure",
23
- "set_style",
24
- ]
25
-
26
-
27
15
  COLORS = {}
28
16
  COLORS["classic"] = [
29
17
  "#ba2c54",