ctapipe is not stable yet, so expect large and rapid changes to structure and functionality as we explore various design choices before the 1.0 release.

Array Displays#

Like CameraDisplays, ctapipe provides a way to display information related to the array on the ground: ArrayDisplay

10 import matplotlib.pyplot as plt
11 import numpy as np
12 from astropy import units as u
13 from astropy.coordinates import SkyCoord
14
15 from ctapipe.calib import CameraCalibrator
16 from ctapipe.coordinates import EastingNorthingFrame
17 from ctapipe.image import ImageProcessor
18 from ctapipe.instrument import SubarrayDescription
19 from ctapipe.io import EventSource
20 from ctapipe.reco import ShowerProcessor
21 from ctapipe.visualization import ArrayDisplay
22
23 plt.rcParams["figure.figsize"] = (8, 6)
26 tel_ids = list(range(1, 5)) + list(range(5, 20))  # just LSTs  + one set of MSTs
27
28 subarray = SubarrayDescription.read(
29     "dataset://gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst"
30 ).select_subarray(tel_ids)
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:   0%|          | 0.00/18.9M [00:00<?, ?B/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:   0%|          | 51.2k/18.9M [00:00<01:13, 256kB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:   1%|          | 102k/18.9M [00:00<00:52, 361kB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:   1%|          | 174k/18.9M [00:00<00:38, 493kB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:   2%|▏         | 358k/18.9M [00:00<00:19, 959kB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:   4%|▍         | 717k/18.9M [00:00<00:09, 1.82MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:   7%|▋         | 1.24M/18.9M [00:00<00:06, 2.90MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:   9%|▉         | 1.76M/18.9M [00:00<00:04, 3.61MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  12%|█▏        | 2.22M/18.9M [00:00<00:04, 3.91MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  14%|█▍        | 2.63M/18.9M [00:01<00:04, 3.96MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  17%|█▋        | 3.14M/18.9M [00:01<00:03, 4.30MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  19%|█▉        | 3.59M/18.9M [00:01<00:03, 4.35MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  22%|██▏       | 4.13M/18.9M [00:01<00:03, 4.63MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  24%|██▍       | 4.60M/18.9M [00:01<00:03, 4.64MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  27%|██▋       | 5.11M/18.9M [00:01<00:02, 4.77MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  30%|██▉       | 5.63M/18.9M [00:01<00:02, 4.88MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  33%|███▎      | 6.15M/18.9M [00:01<00:02, 4.97MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  35%|███▌      | 6.68M/18.9M [00:01<00:02, 5.02MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  38%|███▊      | 7.20M/18.9M [00:01<00:02, 5.06MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  41%|████      | 7.73M/18.9M [00:02<00:02, 5.12MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  44%|████▎     | 8.25M/18.9M [00:02<00:02, 5.13MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  46%|████▋     | 8.78M/18.9M [00:02<00:01, 5.14MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  49%|████▉     | 9.30M/18.9M [00:02<00:01, 5.14MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  52%|█████▏    | 9.82M/18.9M [00:02<00:01, 5.15MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  55%|█████▍    | 10.4M/18.9M [00:02<00:01, 5.18MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  58%|█████▊    | 10.9M/18.9M [00:02<00:01, 5.17MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  60%|██████    | 11.4M/18.9M [00:02<00:01, 5.17MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  63%|██████▎   | 11.9M/18.9M [00:02<00:01, 5.16MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  66%|██████▌   | 12.4M/18.9M [00:02<00:01, 5.16MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  69%|██████▊   | 13.0M/18.9M [00:03<00:01, 5.19MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  71%|███████▏  | 13.5M/18.9M [00:03<00:01, 5.18MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  74%|███████▍  | 14.0M/18.9M [00:03<00:00, 5.17MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  77%|███████▋  | 14.5M/18.9M [00:03<00:00, 5.17MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  80%|███████▉  | 15.1M/18.9M [00:03<00:00, 5.16MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  82%|████████▏ | 15.6M/18.9M [00:03<00:00, 5.19MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  85%|████████▌ | 16.1M/18.9M [00:03<00:00, 5.18MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  88%|████████▊ | 16.6M/18.9M [00:03<00:00, 5.17MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  91%|█████████ | 17.2M/18.9M [00:03<00:00, 5.17MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  94%|█████████▎| 17.7M/18.9M [00:03<00:00, 5.16MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  96%|█████████▋| 18.2M/18.9M [00:04<00:00, 5.19MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst:  99%|█████████▉| 18.7M/18.9M [00:04<00:00, 5.18MB/s]
Downloading gamma_20deg_0deg_run1___cta-prod5-lapalma_desert-2158m-LaPalma-dark_100evts.simtel.zst: 100%|██████████| 18.9M/18.9M [00:04<00:00, 4.56MB/s]

An array display is created for example in subarray.peek():

37 subarray.peek()
MonteCarloArray_1-19
<ctapipe.visualization.mpl_array.ArrayDisplay object at 0x7f746aaa4a60>

However, you can make one manually with a bit more flexibility:

Constructing an ArrayDisplay#

50 disp = ArrayDisplay(subarray)
MonteCarloArray_1-19

You can specify the Frame you want as long as it is compatible with GroundFrame. EastingNorthingFrame is probably the most useful. You can also add telescope labels

59 disp = ArrayDisplay(subarray, frame=EastingNorthingFrame())
60 disp.add_labels()
MonteCarloArray_1-19

Using color to show information#

By default the color of the telescope circles correlates to telescope type. However, you can use color to convey other information by setting the values attribute, like a trigger pattern

72 plt.set_cmap("rainbow")  # the array display will use the current colormap for values
73
74 ad = ArrayDisplay(subarray)
75 ad.telescopes.set_linewidth(0)  # to turn off the telescope borders
76
77 trigger_pattern = np.zeros(subarray.n_tels)
78 trigger_pattern[
79     [
80         1,
81         4,
82         5,
83         6,
84     ]
85 ] = 1
86 ad.values = trigger_pattern  # display certain telescopes in a color
87 ad.add_labels()
MonteCarloArray_1-19

or for example, you could use color to represent the telescope distance to the impact point

 95 shower_impact = SkyCoord(200 * u.m, -200 * u.m, 0 * u.m, frame=EastingNorthingFrame())
 96
 97 plt.set_cmap("rainbow")  # the array display will use the current colormap for values
 98 ad = ArrayDisplay(subarray)
 99 ad.telescopes.set_linewidth(0)  # to turn off the telescope borders
100 plt.scatter(shower_impact.easting, shower_impact.northing, marker="+", s=200)
101
102 distances = np.hypot(
103     subarray.tel_coords.cartesian.x - shower_impact.cartesian.x,
104     subarray.tel_coords.cartesian.y - shower_impact.cartesian.y,
105 )
106 ad.values = distances
107 plt.colorbar(ad.telescopes, label="Distance (m)")
MonteCarloArray_1-19
<matplotlib.colorbar.Colorbar object at 0x7f7469aeb730>

Overlaying vectors#

For plotting reconstruction quantities, it’s useful to overlay vectors on the telescope positions. ArrayDisplay provides functions: * set_vector_uv to set by cartesian coordinates from the center of each telescope * set_vector_rho_phi to set by polar coordinates from the center of each telescope * set_vector_hillas to set vectors from a dict[int,HillasParameters] mapping tel_id (not index!) to a set of parameters.

123 np.random.seed(0)
124 phis = np.random.uniform(0, 180.0, size=subarray.n_tels) * u.deg
125 rhos = np.ones(subarray.n_tels) * 200 * u.m
126
127
128 ad = ArrayDisplay(subarray, frame=EastingNorthingFrame(), tel_scale=2)
129 ad.set_vector_rho_phi(rho=rhos, phi=phis)
MonteCarloArray_1-19

Overlaying Image Axes#

For the common use case of plotting image axis on an ArrayDisplay, the set_line_hillas() method is provided for convenience. The following example shows its use:

142 input_url = "dataset://gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz"

First, we define a function to plot the array with overlaid lines for the image axes

151 def plot_event(event, subarray, ax):
152     """
153     Draw an ArrayDisplay with image axes and the
154     true and reconstructed impact position overlaid
155     """
156
157     event.pointing.array_azimuth
158     disp = ArrayDisplay(subarray, axes=ax)
159
160     hillas_dict = {tid: tel.parameters.hillas for tid, tel in event.dl1.tel.items()}
161     core_dict = {tid: tel.parameters.core.psi for tid, tel in event.dl1.tel.items()}
162
163     disp.set_line_hillas(
164         hillas_dict,
165         core_dict,
166         500,
167     )
168
169     reco_shower = event.dl2.stereo.geometry["HillasReconstructor"]
170
171     ax.scatter(
172         event.simulation.shower.core_x,
173         event.simulation.shower.core_y,
174         s=200,
175         c="k",
176         marker="x",
177         label="True Impact",
178     )
179     ax.scatter(
180         reco_shower.core_x,
181         reco_shower.core_y,
182         s=200,
183         c="r",
184         marker="x",
185         label="Estimated Impact",
186     )
187
188     ax.legend()

Now, we can loop through some events and plot them. Here we apply default calibration, image processing, and reconstruction, however it is better to use ctapipe-process with a well-defined configuration to do this in reality. Note that some events will not have images bright enough to do parameterization or reconstruction, so they will have no image axis lines or no estimated impact position.

200 fig, ax = plt.subplots(5, 3, figsize=(20, 40), constrained_layout=True)
201 ax = ax.ravel()
202
203 with EventSource(input_url, max_events=15, focal_length_choice="EQUIVALENT") as source:
204     calib = CameraCalibrator(subarray=source.subarray)
205     process_images = ImageProcessor(subarray=source.subarray)
206     process_shower = ShowerProcessor(subarray=source.subarray)
207
208     for i, event in enumerate(source):
209         calib(event)
210         process_images(event)
211         process_shower(event)
212         plot_event(event, source.subarray, ax=ax[i])
MonteCarloArray, MonteCarloArray, MonteCarloArray, MonteCarloArray, MonteCarloArray, MonteCarloArray, MonteCarloArray, MonteCarloArray, MonteCarloArray, MonteCarloArray, MonteCarloArray, MonteCarloArray, MonteCarloArray, MonteCarloArray, MonteCarloArray
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:   0%|          | 0.00/9.23M [00:00<?, ?B/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:   1%|          | 51.2k/9.23M [00:00<00:35, 255kB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:   1%|          | 102k/9.23M [00:00<00:25, 362kB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:   2%|▏         | 215k/9.23M [00:00<00:14, 644kB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:   3%|▎         | 317k/9.23M [00:00<00:11, 774kB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:   7%|▋         | 655k/9.23M [00:00<00:05, 1.63MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  11%|█▏        | 1.04M/9.23M [00:00<00:03, 2.35MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  16%|█▋        | 1.51M/9.23M [00:00<00:02, 3.05MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  21%|██        | 1.89M/9.23M [00:00<00:02, 3.30MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  26%|██▋       | 2.43M/9.23M [00:01<00:01, 3.91MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  31%|███       | 2.88M/9.23M [00:01<00:01, 4.08MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  36%|███▌      | 3.30M/9.23M [00:01<00:01, 4.11MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  40%|████      | 3.72M/9.23M [00:01<00:01, 4.13MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  45%|████▍     | 4.14M/9.23M [00:01<00:01, 4.13MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  49%|████▉     | 4.56M/9.23M [00:01<00:01, 4.14MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  54%|█████▍    | 4.99M/9.23M [00:01<00:01, 4.19MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  60%|█████▉    | 5.50M/9.23M [00:01<00:00, 4.46MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  65%|██████▌   | 6.03M/9.23M [00:01<00:00, 4.70MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  71%|███████   | 6.55M/9.23M [00:01<00:00, 4.85MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  76%|███████▋  | 7.05M/9.23M [00:02<00:00, 4.85MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  82%|████████▏ | 7.54M/9.23M [00:02<00:00, 4.86MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  87%|████████▋ | 8.06M/9.23M [00:02<00:00, 4.96MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  93%|█████████▎| 8.58M/9.23M [00:02<00:00, 5.02MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz:  99%|█████████▊| 9.10M/9.23M [00:02<00:00, 5.07MB/s]
Downloading gamma_LaPalma_baseline_20Zd_180Az_prod3b_test.simtel.gz: 100%|██████████| 9.23M/9.23M [00:02<00:00, 3.82MB/s]

Total running time of the script: (0 minutes 14.157 seconds)

Gallery generated by Sphinx-Gallery