Example #1
0
def test_hillas_failure():
    geom, image = create_sample_image(psi='0d')
    blank_image = zeros_like(image)

    with pytest.raises(HillasParameterizationError):
        hillas_parameters_1(geom, blank_image)

    with pytest.raises(HillasParameterizationError):
        hillas_parameters_2(geom, blank_image)

    with pytest.raises(HillasParameterizationError):
        hillas_parameters_3(geom, blank_image)

    with pytest.raises(HillasParameterizationError):
        hillas_parameters_4(geom, blank_image)
Example #2
0
def do_test_hillas(withunits=True):
    """
    test all Hillas-parameter routines on a sample image and see if they
    agree with eachother and with the toy model (assuming the toy model code
    is correct)
    """

    # try all quadrants
    for psi_angle in ['30d', '120d', '-30d', '-120d']:

        px, py, image = create_sample_image(psi_angle)
        results = {}

        if withunits:
            px = px * u.cm
            py = py * u.cm

        results['v1'] = hillas_parameters_1(px, py, image)
        results['v2'] = hillas_parameters_2(px, py, image)
        results['v3'] = hillas_parameters_3(px, py, image)
        results['v4'] = hillas_parameters_4(px, py, image)
        # compare each method's output
        for aa in results:
            for bb in results:
                if aa is not bb:
                    print("comparing {} to {}".format(aa, bb))
                    compare_result(results[aa].length, results[bb].length)
                    compare_result(results[aa].width, results[bb].width)
                    compare_result(results[aa].r, results[bb].r)
                    compare_result(results[aa].phi.deg, results[bb].phi.deg)
                    compare_result(results[aa].psi.deg, results[bb].psi.deg)
                    compare_result(results[aa].miss, results[bb].miss)
                    compare_result(results[aa].skewness, results[bb].skewness)
Example #3
0
def test_hillas():
    """
    test all Hillas-parameter routines on a sample image and see if they
    agree with eachother and with the toy model (assuming the toy model code
    is correct)
    """

    px, py, image = create_sample_image()
    results = {}

    results['v1'] = hillas_parameters_1(px, py, image)
    results['v2'] = hillas_parameters_2(px, py, image)
    results['v3'] = hillas_parameters_3(px, py, image)
    results['v4'] = hillas_parameters_4(px, py, image)

    # compare each method's output
    for aa in results:
        for bb in results:
            if aa is not bb:
                print("comparing {} to {}".format(aa, bb))
                assert isclose(results[aa].length, results[bb].length)
                assert isclose(results[aa].width, results[bb].width)
                assert isclose(results[aa].r, results[bb].r)
                assert isclose(results[aa].phi.deg, results[bb].phi.deg)
                assert isclose(results[aa].psi.deg, results[bb].psi.deg)
                assert isclose(results[aa].miss, results[bb].miss)
                assert isclose(results[aa].skewness, results[bb].skewness)
Example #4
0
def do_test_hillas(withunits=True):
    """
    test all Hillas-parameter routines on a sample image and see if they
    agree with eachother and with the toy model (assuming the toy model code
    is correct)
    """

    px, py, image = create_sample_image()
    results = {}

    if withunits:
        px = px * u.cm
        py = py * u.cm

    results['v1'] = hillas_parameters_1(px, py, image)
    results['v2'] = hillas_parameters_2(px, py, image)
    results['v3'] = hillas_parameters_3(px, py, image)
    results['v4'] = hillas_parameters_4(px, py, image)

    # compare each method's output
    for aa in results:
        for bb in results:
            if aa is not bb:
                print("comparing {} to {}".format(aa,bb))
                compare_result(results[aa].length, results[bb].length)
                compare_result(results[aa].width, results[bb].width)
                compare_result(results[aa].r, results[bb].r)
                compare_result(results[aa].phi.deg, results[bb].phi.deg)
                compare_result(results[aa].psi.deg, results[bb].psi.deg)
                compare_result(results[aa].miss, results[bb].miss)
                compare_result(results[aa].skewness, results[bb].skewness)
Example #5
0
def plot_ellipse_shower_on_image_meter(axis, image_array, pixels_position):

    xx, yy = pixels_position[0], pixels_position[1]

    hillas = hillas_parameters_1(xx.flatten(), # * u.meter,
                                 yy.flatten(), # * u.meter,
                                 image_array.flatten())

    centroid = (hillas.x.value, hillas.y.value)
    length = hillas.length.value
    width = hillas.width.value
    angle = hillas.psi.to(u.rad).value

    print("centroid:", centroid)
    print("length:",   length)
    print("width:",    width)
    print("angle:",    angle)

    #a, b, c = common.angle_and_point_to_equation(angle, centroid)
    #print("a:", a)
    #print("b:", b)
    #print("c:", c)
    #x = np.array([-0.2, 0.2])
    #f = lambda x: a/(-b) * x + c/(-b)
    #axis.plot(x, f(x), "--b")

    #print("DEBUG:", hillas[7].value, angle, np.degrees(angle))

    ellipse = Ellipse(xy=centroid, width=length, height=width, angle=np.degrees(angle), fill=False, color='red', lw=2)
    axis.axes.add_patch(ellipse)

    title = axis.axes.get_title()
    axis.axes.set_title("{} ({:.2f}°)".format(title, np.degrees(angle)))

    # Plot centroid

    axis.scatter(*centroid)

    # Plot shower axis

    #axis.arrow(0, 0,  0.1, 0, head_width=0.001, head_length=0.005, fc='k', ec='k')
    #axis.arrow(0, 0,  0, 0.1, head_width=0.001, head_length=0.005, fc='k', ec='k')

    p1_x = centroid[0]
    p1_y = centroid[1]

    p2_x = p1_x + math.cos(angle)
    p2_y = p1_y + math.sin(angle)
    #p2_x = p1_x + (length / 2.) * math.cos(angle)
    #p2_y = p1_y + (length / 2.) * math.sin(angle)


    #print(math.cos(math.pi/2.))
    #print(math.sin(math.pi/2.))
    #p2_x = p1_x + (length / 2.) * math.cos(math.pi/2.)
    #p2_y = p1_y + (length / 2.) * math.sin(math.pi/2.)
    #print(p1_x, p2_x)
    #print(p1_y, p2_x)


    axis.arrow(p1_x, p1_y,  p2_x, p2_y, head_width=0.001, head_length=0.005, fc='r', ec='r')

    p3_x = p1_x + math.cos(angle + math.pi/2.)
    p3_y = p1_y + math.sin(angle + math.pi/2.)
    #p3_x = p1_x + (width / 2.) * math.cos(angle + math.pi/2.)
    #p3_y = p1_y + (width / 2.) * math.sin(angle + math.pi/2.)

    axis.arrow(p1_x, p1_y, p3_x, p3_y, head_width=0.001, head_length=0.005, fc='g', ec='g')
    def update_plots(self, data=None, save=False):        # data is for event callers

        if self.current_file_path is not None:
            # Read the selected file #########

            fits_images_dict, fits_metadata_dict = images.load_benchmark_images(self.current_file_path)

            input_img = fits_images_dict["input_image"]
            reference_img = fits_images_dict["reference_image"]
            pixels_position = fits_images_dict["pixels_position"]

            if input_img.ndim != 2:
                raise Exception("Unexpected error: the input FITS file should contain a 2D array.")

            if reference_img.ndim != 2:
                raise Exception("Unexpected error: the input FITS file should contain a 2D array.")

            if self.kill_isolated_pixels_on_ref:
                reference_img = scipy_kill_isolated_pixels(reference_img)

            # Tailcut #####################

            #input_img_copy = copy.deepcopy(input_img)
            input_img_copy = input_img.astype('float64', copy=True)

            tailcut = tailcut_mod.Tailcut()
            
            initial_time = time.perf_counter()
            tailcut_cleaned_img = tailcut.clean_image(input_img_copy,
                                                      high_threshold=10,
                                                      low_threshold=5,
                                                      kill_isolated_pixels=self.kill_isolated_pixels)
            tailcut_execution_time = time.perf_counter() - initial_time

            # Wavelets ####################

            #input_img_copy = copy.deepcopy(input_img)
            input_img_copy = input_img.astype('float64', copy=True)

            wavelets = wavelets_mod.WaveletTransform()

            option_string = self.wavelets_options_entry.get_text()
            print(option_string)
            
            initial_time = time.perf_counter()
            wavelets_cleaned_img = wavelets.clean_image(input_img_copy,
                                                        kill_isolated_pixels=self.kill_isolated_pixels,
                                                        input_image_scale=self.input_image_scale,
                                                        offset_after_calibration=self.offset_after_calibration,
                                                        verbose=True,
                                                        raw_option_string=option_string)
            wavelets_execution_time = time.perf_counter() - initial_time

            # Execution time ##############

            print("Tailcut execution time: ", tailcut_execution_time) # TODO
            print("Wavelets execution time: ", wavelets_execution_time) # TODO

            # Tailcut scores ##############

            tailcut_title_suffix = ""
            try:
                tailcut_score_tuple, tailcut_score_name_tuple = assess_mod.assess_image_cleaning(input_img,
                                                                                                 tailcut_cleaned_img,
                                                                                                 reference_img,
                                                                                                 pixels_position,
                                                                                                 benchmark_method="all")

                if self.show_scores:
                    tailcut_title_suffix += " ("
                    for name, score in zip(tailcut_score_name_tuple, tailcut_score_tuple):
                        if name == "e_shape":
                            tailcut_title_suffix += " Es="
                            tailcut_title_suffix += "{:.2e}".format(score)
                        elif name == "e_energy":
                            tailcut_title_suffix += " Ee="
                            tailcut_title_suffix += "{:.2e}".format(score)
                        elif name == "hillas_theta":
                            tailcut_title_suffix += " Th="
                            tailcut_title_suffix += "{:.2f}".format(score)
                    tailcut_title_suffix += " )"

                print("Tailcut:")
                for name in tailcut_score_name_tuple:
                    print("{:>20}".format(name), end=" ")
                print()
                for score in tailcut_score_tuple:
                    print("{:20.12f}".format(score), end=" ")
                print()
            except assess_mod.AssessError:
                print("Tailcut: ", str(assess_mod.AssessError))

            # Wavelets scores #############

            wavelets_title_suffix = ""
            try:
                wavelets_score_tuple, wavelets_score_name_tuple = assess_mod.assess_image_cleaning(input_img,
                                                                                                   wavelets_cleaned_img,
                                                                                                   reference_img,
                                                                                                   pixels_position,
                                                                                                   benchmark_method="all")

                if self.show_scores:
                    wavelets_title_suffix += " ("
                    for name, score in zip(wavelets_score_name_tuple, wavelets_score_tuple):
                        if name == "e_shape":
                            wavelets_title_suffix += " Es="
                            wavelets_title_suffix += "{:.2e}".format(score)
                        elif name == "e_energy":
                            wavelets_title_suffix += " Ee="
                            wavelets_title_suffix += "{:.2e}".format(score)
                        elif name == "hillas_theta":
                            wavelets_title_suffix += " Th="
                            wavelets_title_suffix += "{:.2f}".format(score)
                    wavelets_title_suffix += " )"

                print("Wavelets:")
                for name in wavelets_score_name_tuple:
                    print("{:>20}".format(name), end=" ")
                print()
                for score in wavelets_score_tuple:
                    print("{:20.12f}".format(score), end=" ")
                print()
            except assess_mod.AssessError:
                print("Wavelets: ", str(assess_mod.AssessError))

            # Update the widget ###########

            self.clear_figure()

            ax1 = self.fig.add_subplot(221)
            ax2 = self.fig.add_subplot(222)
            ax3 = self.fig.add_subplot(223)
            ax4 = self.fig.add_subplot(224)

            if self.plot_histogram:
                self._draw_histogram(ax1, input_img, "Input")
                self._draw_histogram(ax2, reference_img, "Reference")
                self._draw_histogram(ax3, tailcut_cleaned_img, "Tailcut" + tailcut_title_suffix)
                self._draw_histogram(ax4, wavelets_cleaned_img, "Wavelets" + wavelets_title_suffix)
            else:
                # AX1 #######

                self._draw_image(ax1, input_img, "Input", pixels_position=pixels_position)

                # AX2 #######

                self._draw_image(ax2, reference_img, "Reference", pixels_position=pixels_position)

                if self.plot_ellipse_shower:
                    try:
                        common.plot_ellipse_shower_on_image_meter(ax2, reference_img, pixels_position)
                    except Exception as e:
                        print(e)

                # AX3 #######

                if self.plot_perpendicular_hit_distribution is not None:
                    if self.use_ref_angle_for_perpendicular_hit_distribution:
                        image_array = copy.deepcopy(reference_img)
                        xx, yy = pixels_position[0], pixels_position[1]
                        common_hillas_parameters = hillas_parameters_1(xx.flatten() * u.meter,
                                                                       yy.flatten() * u.meter,
                                                                       image_array.flatten())
                    else:
                        common_hillas_parameters = None

                    bins = np.linspace(-0.04, 0.04, 21)

                    if self.plot_perpendicular_hit_distribution == "Tailcut":
                        common.plot_perpendicular_hit_distribution(ax3,
                                                                   [reference_img, tailcut_cleaned_img],
                                                                   pixels_position,
                                                                   bins=bins,
                                                                   label_list=["Ref.", "Cleaned TC"],
                                                                   hist_type="step",
                                                                   common_hillas_parameters=common_hillas_parameters,
                                                                   plot_ratio=True)
                    elif self.plot_perpendicular_hit_distribution == "Wavelet":
                        common.plot_perpendicular_hit_distribution(ax3,
                                                                   [reference_img, wavelets_cleaned_img],
                                                                   pixels_position,
                                                                   bins=bins,
                                                                   label_list=["Ref.", "Cleaned WT"],
                                                                   hist_type="step",
                                                                   common_hillas_parameters=common_hillas_parameters,
                                                                   plot_ratio=True)

                    ax3.set_title("Perpendicular hit distribution")
                    ax3.set_xlabel("Distance to the shower axis (in meter)", fontsize=16)
                    ax3.set_ylabel("Photoelectrons", fontsize=16)
                else:
                    self._draw_image(ax3, tailcut_cleaned_img, "Tailcut" + tailcut_title_suffix, pixels_position=pixels_position)

                if self.plot_ellipse_shower:
                    if self.plot_perpendicular_hit_distribution is None:
                        try:
                            # Show ellipse only if "perpendicular hit distribution" is off
                            common.plot_ellipse_shower_on_image_meter(ax3, tailcut_cleaned_img, pixels_position)
                        except Exception as e:
                            print(e)

                # AX4 #######

                if self.plot_perpendicular_hit_distribution == "Tailcut":
                    self._draw_image(ax4, tailcut_cleaned_img, "Tailcut" + tailcut_title_suffix, pixels_position=pixels_position)

                    if self.plot_ellipse_shower:
                        if (self.plot_perpendicular_hit_distribution is not None) and self.use_ref_angle_for_perpendicular_hit_distribution:
                            try:
                                common.plot_ellipse_shower_on_image_meter(ax4, reference_img, pixels_position)
                            except Exception as e:
                                print(e)
                        else:
                            try:
                                common.plot_ellipse_shower_on_image_meter(ax4, tailcut_cleaned_img, pixels_position)
                            except Exception as e:
                                print(e)
                else:
                    self._draw_image(ax4, wavelets_cleaned_img, "Wavelets" + wavelets_title_suffix, pixels_position=pixels_position)

                    if self.plot_ellipse_shower:
                        if (self.plot_perpendicular_hit_distribution is not None) and self.use_ref_angle_for_perpendicular_hit_distribution:
                            try:
                                common.plot_ellipse_shower_on_image_meter(ax4, reference_img, pixels_position)
                            except Exception as e:
                                print(e)
                        else:
                            try:
                                common.plot_ellipse_shower_on_image_meter(ax4, wavelets_cleaned_img, pixels_position)
                            except Exception as e:
                                print(e)

            plt.suptitle("{:.3f} TeV ({} photoelectrons in reference image) - Event {} - Telescope {}".format(fits_metadata_dict["mc_energy"], int(fits_metadata_dict["npe"]), fits_metadata_dict["event_id"], fits_metadata_dict["tel_id"]), fontsize=18)

            if save:
                output_file_path_base = "ev{}_tel{}".format(fits_metadata_dict["event_id"], fits_metadata_dict["tel_id"]) # TODO: add WT options

                if self.plot_histogram:
                    output_file_path_base += "_hist"

                if self.plot_log_scale:
                    output_file_path_base += "_log"

                ## Save in PDF
                #output_file_path = output_file_path_base + ".pdf"
                #print("Save", output_file_path)
                #plt.savefig(output_file_path, bbox_inches='tight')

                ## Save in SVG
                #output_file_path = output_file_path_base + ".svg"
                #print("Save", output_file_path)
                #plt.savefig(output_file_path, bbox_inches='tight')

                # Save in PNG
                output_file_path = output_file_path_base + ".png"
                print("Save", output_file_path)
                plt.savefig(output_file_path, bbox_inches='tight')
            else:
                self.fig.canvas.draw()
Example #7
0
def get_hillas_parameters(geom: CameraGeometry, image, implementation=4):
    r"""Return Hillas parameters [hillas]_ of the given ``image``.

    Short description of Hillas parameters:
    * x:         x position of the ellipse's center (in meter)
    * y:         y position of the ellipse's center (in meter)
    * length:    measure of the RMS extent along the major axis (in meter) (length >= width)
    * width:     measure of the RMS extent along the minor axis (in meter) (length >= width)
    * intensity: the number of photoelectrons in the image (in PE)         (size = np.sum(image))
    * psi:       angle of the shower (in radian)
    * phi:       polar coordinate of centroid (in radian)
    * r:         radial coordinate of centroid (in meter)
    * kurtosis:  Kurtosis is a measure of whether the data are heavy-tailed or light-tailed
                 relative to a normal distribution.
                 That is, data sets with high kurtosis tend to have heavy tails, or outliers.
                 Data sets with low kurtosis tend to have light tails, or lack of outliers.
                 See http://www.itl.nist.gov/div898/handbook/eda/section3/eda35b.htm
    * skewness:  Skewness is a measure of symmetry, or more precisely, the lack of symmetry.
                 A distribution, or data set, is symmetric if it looks the same to the left
                 and right of the center point. See http://www.itl.nist.gov/div898/handbook/eda/section3/eda35b.htm

    See https://github.com/cta-observatory/ctapipe/blob/master/ctapipe/image/hillas.py#L83
    for more information.

    Parameters
    ----------
    geom : CameraGeomatry
        The geometry of the image to parametrize

    image : Numpy array
        The image to parametrize

    implementation : integer
        Tell which ctapipe's implementation to use (1 or 2).

    Returns
    -------
    namedtuple
        Hillas parameters for the given ``image``

    References
    ----------
    .. [hillas] Appendix of the Whipple Crab paper Weekes et al. (1998)
       http://adsabs.harvard.edu/abs/1989ApJ...342..379W
    """

    # Copy image to prevent tricky bugs
    image = image.copy()

    if implementation == 1:
        params = hillas_parameters_1(geom, image)
    elif implementation == 2:
        params = hillas_parameters_2(geom, image)
    elif implementation == 3:
        params = hillas_parameters_3(geom, image)
    elif implementation == 4:
        params = hillas_parameters_4(geom, image)
    else:
        raise ValueError("Wrong Hillas implementation ID.")

    return params
def plot_ellipse_shower_on_image_meter(axis, image_array, pixels_position):

    xx, yy = pixels_position[0], pixels_position[1]

    hillas = hillas_parameters_1(xx.flatten(), # * u.meter,
                                 yy.flatten(), # * u.meter,
                                 image_array.flatten())

    centroid = (hillas.cen_x.value, hillas.cen_y.value)
    length = hillas.length.value
    width = hillas.width.value
    angle = hillas.psi.to(u.rad).value

    print("centroid:", centroid)
    print("length:",   length)
    print("width:",    width)
    print("angle:",    angle)

    #a, b, c = common.angle_and_point_to_equation(angle, centroid)
    #print("a:", a)
    #print("b:", b)
    #print("c:", c)
    #x = np.array([-0.2, 0.2])
    #f = lambda x: a/(-b) * x + c/(-b)
    #axis.plot(x, f(x), "--b")

    #print("DEBUG:", hillas[7].value, angle, np.degrees(angle))

    ellipse = Ellipse(xy=centroid, width=length, height=width, angle=np.degrees(angle), fill=False, color='red', lw=2)
    axis.axes.add_patch(ellipse)

    title = axis.axes.get_title()
    axis.axes.set_title("{} ({:.2f}°)".format(title, np.degrees(angle)))

    # Plot centroid

    axis.scatter(*centroid)

    # Plot shower axis

    #axis.arrow(0, 0,  0.1, 0, head_width=0.001, head_length=0.005, fc='k', ec='k')
    #axis.arrow(0, 0,  0, 0.1, head_width=0.001, head_length=0.005, fc='k', ec='k')

    p1_x = centroid[0]
    p1_y = centroid[1]

    p2_x = p1_x + math.cos(angle)
    p2_y = p1_y + math.sin(angle)
    #p2_x = p1_x + (length / 2.) * math.cos(angle)
    #p2_y = p1_y + (length / 2.) * math.sin(angle)


    #print(math.cos(math.pi/2.))
    #print(math.sin(math.pi/2.))
    #p2_x = p1_x + (length / 2.) * math.cos(math.pi/2.)
    #p2_y = p1_y + (length / 2.) * math.sin(math.pi/2.)
    #print(p1_x, p2_x)
    #print(p1_y, p2_x)


    axis.arrow(p1_x, p1_y,  p2_x, p2_y, head_width=0.001, head_length=0.005, fc='r', ec='r')

    p3_x = p1_x + math.cos(angle + math.pi/2.)
    p3_y = p1_y + math.sin(angle + math.pi/2.)
    #p3_x = p1_x + (width / 2.) * math.cos(angle + math.pi/2.)
    #p3_y = p1_y + (width / 2.) * math.sin(angle + math.pi/2.)

    axis.arrow(p1_x, p1_y, p3_x, p3_y, head_width=0.001, head_length=0.005, fc='g', ec='g')
Example #9
0
    def update_plots(self, data=None, save=False):  # data is for event callers

        if self.current_file_path is not None:
            # Read the selected file #########

            fits_images_dict, fits_metadata_dict = images.load_benchmark_images(
                self.current_file_path)

            input_img = fits_images_dict["input_image"]
            reference_img = fits_images_dict["reference_image"]
            pixels_position = fits_images_dict["pixels_position"]

            if input_img.ndim != 2:
                raise Exception(
                    "Unexpected error: the input FITS file should contain a 2D array."
                )

            if reference_img.ndim != 2:
                raise Exception(
                    "Unexpected error: the input FITS file should contain a 2D array."
                )

            if self.kill_isolated_pixels_on_ref:
                reference_img = scipy_kill_isolated_pixels(reference_img)

            # Tailcut #####################

            #input_img_copy = copy.deepcopy(input_img)
            input_img_copy = input_img.astype('float64', copy=True)

            tailcut = tailcut_mod.Tailcut()

            initial_time = time.perf_counter()
            tailcut_cleaned_img = tailcut.clean_image(
                input_img_copy,
                high_threshold=10,
                low_threshold=5,
                kill_isolated_pixels=self.kill_isolated_pixels)
            tailcut_execution_time = time.perf_counter() - initial_time

            # Wavelets ####################

            #input_img_copy = copy.deepcopy(input_img)
            input_img_copy = input_img.astype('float64', copy=True)

            wavelets = wavelets_mod.WaveletTransform()

            option_string = self.wavelets_options_entry.get_text()
            print(option_string)

            initial_time = time.perf_counter()
            wavelets_cleaned_img = wavelets.clean_image(
                input_img_copy,
                kill_isolated_pixels=self.kill_isolated_pixels,
                input_image_scale=self.input_image_scale,
                offset_after_calibration=self.offset_after_calibration,
                verbose=True,
                raw_option_string=option_string)
            wavelets_execution_time = time.perf_counter() - initial_time

            # Execution time ##############

            print("Tailcut execution time: ", tailcut_execution_time)  # TODO
            print("Wavelets execution time: ", wavelets_execution_time)  # TODO

            # Tailcut scores ##############

            tailcut_title_suffix = ""
            try:
                tailcut_score_tuple, tailcut_score_name_tuple = assess_mod.assess_image_cleaning(
                    input_img,
                    tailcut_cleaned_img,
                    reference_img,
                    pixels_position,
                    benchmark_method="all")

                if self.show_scores:
                    tailcut_title_suffix += " ("
                    for name, score in zip(tailcut_score_name_tuple,
                                           tailcut_score_tuple):
                        if name == "e_shape":
                            tailcut_title_suffix += " Es="
                            tailcut_title_suffix += "{:.2e}".format(score)
                        elif name == "e_energy":
                            tailcut_title_suffix += " Ee="
                            tailcut_title_suffix += "{:.2e}".format(score)
                        elif name == "hillas_theta":
                            tailcut_title_suffix += " Th="
                            tailcut_title_suffix += "{:.2f}".format(score)
                    tailcut_title_suffix += " )"

                print("Tailcut:")
                for name in tailcut_score_name_tuple:
                    print("{:>20}".format(name), end=" ")
                print()
                for score in tailcut_score_tuple:
                    print("{:20.12f}".format(score), end=" ")
                print()
            except assess_mod.AssessError:
                print("Tailcut: ", str(assess_mod.AssessError))

            # Wavelets scores #############

            wavelets_title_suffix = ""
            try:
                wavelets_score_tuple, wavelets_score_name_tuple = assess_mod.assess_image_cleaning(
                    input_img,
                    wavelets_cleaned_img,
                    reference_img,
                    pixels_position,
                    benchmark_method="all")

                if self.show_scores:
                    wavelets_title_suffix += " ("
                    for name, score in zip(wavelets_score_name_tuple,
                                           wavelets_score_tuple):
                        if name == "e_shape":
                            wavelets_title_suffix += " Es="
                            wavelets_title_suffix += "{:.2e}".format(score)
                        elif name == "e_energy":
                            wavelets_title_suffix += " Ee="
                            wavelets_title_suffix += "{:.2e}".format(score)
                        elif name == "hillas_theta":
                            wavelets_title_suffix += " Th="
                            wavelets_title_suffix += "{:.2f}".format(score)
                    wavelets_title_suffix += " )"

                print("Wavelets:")
                for name in wavelets_score_name_tuple:
                    print("{:>20}".format(name), end=" ")
                print()
                for score in wavelets_score_tuple:
                    print("{:20.12f}".format(score), end=" ")
                print()
            except assess_mod.AssessError:
                print("Wavelets: ", str(assess_mod.AssessError))

            # Update the widget ###########

            self.clear_figure()

            ax1 = self.fig.add_subplot(221)
            ax2 = self.fig.add_subplot(222)
            ax3 = self.fig.add_subplot(223)
            ax4 = self.fig.add_subplot(224)

            if self.plot_histogram:
                self._draw_histogram(ax1, input_img, "Input")
                self._draw_histogram(ax2, reference_img, "Reference")
                self._draw_histogram(ax3, tailcut_cleaned_img,
                                     "Tailcut" + tailcut_title_suffix)
                self._draw_histogram(ax4, wavelets_cleaned_img,
                                     "Wavelets" + wavelets_title_suffix)
            else:
                # AX1 #######

                self._draw_image(ax1,
                                 input_img,
                                 "Input",
                                 pixels_position=pixels_position)

                # AX2 #######

                self._draw_image(ax2,
                                 reference_img,
                                 "Reference",
                                 pixels_position=pixels_position)

                if self.plot_ellipse_shower:
                    try:
                        common.plot_ellipse_shower_on_image_meter(
                            ax2, reference_img, pixels_position)
                    except Exception as e:
                        print(e)

                # AX3 #######

                if self.plot_perpendicular_hit_distribution is not None:
                    if self.use_ref_angle_for_perpendicular_hit_distribution:
                        image_array = copy.deepcopy(reference_img)
                        xx, yy = pixels_position[0], pixels_position[1]
                        common_hillas_parameters = hillas_parameters_1(
                            xx.flatten() * u.meter,
                            yy.flatten() * u.meter, image_array.flatten())
                    else:
                        common_hillas_parameters = None

                    bins = np.linspace(-0.04, 0.04, 21)

                    if self.plot_perpendicular_hit_distribution == "Tailcut":
                        common.plot_perpendicular_hit_distribution(
                            ax3, [reference_img, tailcut_cleaned_img],
                            pixels_position,
                            bins=bins,
                            label_list=["Ref.", "Cleaned TC"],
                            hist_type="step",
                            common_hillas_parameters=common_hillas_parameters,
                            plot_ratio=True)
                    elif self.plot_perpendicular_hit_distribution == "Wavelet":
                        common.plot_perpendicular_hit_distribution(
                            ax3, [reference_img, wavelets_cleaned_img],
                            pixels_position,
                            bins=bins,
                            label_list=["Ref.", "Cleaned WT"],
                            hist_type="step",
                            common_hillas_parameters=common_hillas_parameters,
                            plot_ratio=True)

                    ax3.set_title("Perpendicular hit distribution")
                    ax3.set_xlabel("Distance to the shower axis (in meter)",
                                   fontsize=16)
                    ax3.set_ylabel("Photoelectrons", fontsize=16)
                else:
                    self._draw_image(ax3,
                                     tailcut_cleaned_img,
                                     "Tailcut" + tailcut_title_suffix,
                                     pixels_position=pixels_position)

                if self.plot_ellipse_shower:
                    if self.plot_perpendicular_hit_distribution is None:
                        try:
                            # Show ellipse only if "perpendicular hit distribution" is off
                            common.plot_ellipse_shower_on_image_meter(
                                ax3, tailcut_cleaned_img, pixels_position)
                        except Exception as e:
                            print(e)

                # AX4 #######

                if self.plot_perpendicular_hit_distribution == "Tailcut":
                    self._draw_image(ax4,
                                     tailcut_cleaned_img,
                                     "Tailcut" + tailcut_title_suffix,
                                     pixels_position=pixels_position)

                    if self.plot_ellipse_shower:
                        if (
                                self.plot_perpendicular_hit_distribution
                                is not None
                        ) and self.use_ref_angle_for_perpendicular_hit_distribution:
                            try:
                                common.plot_ellipse_shower_on_image_meter(
                                    ax4, reference_img, pixels_position)
                            except Exception as e:
                                print(e)
                        else:
                            try:
                                common.plot_ellipse_shower_on_image_meter(
                                    ax4, tailcut_cleaned_img, pixels_position)
                            except Exception as e:
                                print(e)
                else:
                    self._draw_image(ax4,
                                     wavelets_cleaned_img,
                                     "Wavelets" + wavelets_title_suffix,
                                     pixels_position=pixels_position)

                    if self.plot_ellipse_shower:
                        if (
                                self.plot_perpendicular_hit_distribution
                                is not None
                        ) and self.use_ref_angle_for_perpendicular_hit_distribution:
                            try:
                                common.plot_ellipse_shower_on_image_meter(
                                    ax4, reference_img, pixels_position)
                            except Exception as e:
                                print(e)
                        else:
                            try:
                                common.plot_ellipse_shower_on_image_meter(
                                    ax4, wavelets_cleaned_img, pixels_position)
                            except Exception as e:
                                print(e)

            plt.suptitle(
                "{:.3f} TeV ({} photoelectrons in reference image) - Event {} - Telescope {}"
                .format(fits_metadata_dict["mc_energy"],
                        int(fits_metadata_dict["npe"]),
                        fits_metadata_dict["event_id"],
                        fits_metadata_dict["tel_id"]),
                fontsize=18)

            if save:
                output_file_path_base = "ev{}_tel{}".format(
                    fits_metadata_dict["event_id"],
                    fits_metadata_dict["tel_id"])  # TODO: add WT options

                if self.plot_histogram:
                    output_file_path_base += "_hist"

                if self.plot_log_scale:
                    output_file_path_base += "_log"

                ## Save in PDF
                #output_file_path = output_file_path_base + ".pdf"
                #print("Save", output_file_path)
                #plt.savefig(output_file_path, bbox_inches='tight')

                ## Save in SVG
                #output_file_path = output_file_path_base + ".svg"
                #print("Save", output_file_path)
                #plt.savefig(output_file_path, bbox_inches='tight')

                # Save in PNG
                output_file_path = output_file_path_base + ".png"
                print("Save", output_file_path)
                plt.savefig(output_file_path, bbox_inches='tight')
            else:
                self.fig.canvas.draw()
def plot_perpendicular_hit_distribution(histogram_axis, image_axis, image_array, pixels_position, title):

    image_array = copy.deepcopy(image_array)

    ###

    #size_m = 0.2  # Size of the "phase space" in meter
    size_m = 0.2  # Size of the "phase space" in meter

#     # TODO: clean these following hard coded values for Astri
#    num_pixels_x = 40
#    num_pixels_y = 40
#
#    x = np.linspace(-0.142555996776, 0.142555996776, num_pixels_x)
#    y = np.linspace(-0.142555996776, 0.142555996776, num_pixels_y)
#
#    #x = np.arange(0, np.shape(ref_image_array)[0], 1)          # TODO: wrong values -10 10 21
#    #y = np.arange(0, np.shape(ref_image_array)[1], 1)          # TODO: wrong values  (30, ...)
#
#    xx, yy = np.meshgrid(x, y)
#    print("delta x:", xx - pixels_position[0])
#    print("delta y:", yy - pixels_position[1])

    xx, yy = pixels_position[0], pixels_position[1]

    # Based on Tino's evaluate_cleaning.py (l. 277)
    hillas = hillas_parameters_1(xx.flatten() * u.meter,      # TODO: essayer avec hillas param 2 !!!
                                 yy.flatten() * u.meter,
                                 image_array.flatten())       # [0]

    centroid = (hillas.cen_x, hillas.cen_y)
    length = hillas.length
    width = hillas.width
    angle = np.radians(hillas.psi) # - np.pi/2.   # TODO

    print("centroid:", centroid)
    print("length:",   length)
    print("width:",    width)
    print("angle:",    angle)

    ###

    # p1 = center of the ellipse
    p1_x = hillas.cen_x
    p1_y = hillas.cen_y

    #image_axis.scatter(p1_x, p1_y)  # DEBUG plot

    # p2 = intersection between the ellipse and the shower track
    p2_x = p1_x + hillas.length * np.cos(angle)  # hillas.psi + np.pi/2)
    p2_y = p1_y + hillas.length * np.sin(angle)  # hillas.psi + np.pi/2)

    #image_axis.scatter(p2_x, p2_y)               # DEBUG plot
    #image_axis.plot([p1_x, p2_x], [p1_y, p2_y])  # DEBUG plot

    print(p1_x, p2_x, p1_y, p2_y)                # DEBUG plot

    d12_x = p1_x - p2_x
    d12_y = p1_y - p2_y

    print(d12_x, d12_y)                # DEBUG plot

    # Slope of the shower track
    T = linalg.normalise(np.array([d12_x.value, d12_y.value]))  # why a dedicated function ? if it's what I understand, it can easily be done on the fly

    #print("[p1_x-p2_x, p1_y-p2_y]:", [p1_x-p2_x, p1_y-p2_y])
    #print("T:", T)
    #image_axis.plot([p1_x, p1_x*T[0]], [p1_y, p1_y*T[1]], "-g", linewidth=3)  # DEBUG plot

    x = xx.flatten()
    y = yy.flatten()

    # Manhattan distance of pixels to the center of the ellipse
    # Translate (center) on P1 ?
    D = [p1_x.value-x, p1_y.value-y]

    # Pixels in the new base
    dl = D[0]*T[0] + D[1]*T[1]
    dp = D[0]*T[1] - D[1]*T[0]

    # nparray.ravel(): Return a flattened array.
    values, bins, patches = histogram_axis.hist(dp.ravel(),
                                                histtype='step',
                                                bins=np.linspace(-size_m, size_m, 31))          # -10 10 21

    # TODO: scatter seulement  les points qui sont dans le linspace de bins defini juste au dessus, faire apparaitre chaque bin d'une couleure différente
    
    ##image_axis.scatter(dl, dp, s=10, alpha=0.5)               # DEBUG plot
    #image_axis.scatter(dl, dp, s=10, alpha=0.5)               # DEBUG plot
    #image_axis.plot(dl.reshape(40, 40).T, dp.reshape(40, 40).T)               # DEBUG plot
    #print(dl)
    #print(dp.shape)

    ###

    histogram_axis.set_xlim([-size_m, size_m])

    histogram_axis.set_xlabel('Distance to the shower axis (m)', fontsize=14)
    histogram_axis.set_ylabel('Hits', fontsize=14)

    histogram_axis.set_title(title)
def plot_perpendicular_hit_distribution(histogram_axis, image_axis,
                                        image_array, pixels_position, title):

    image_array = copy.deepcopy(image_array)

    ###

    #size_m = 0.2  # Size of the "phase space" in meter
    size_m = 0.2  # Size of the "phase space" in meter

    #     # TODO: clean these following hard coded values for Astri
    #    num_pixels_x = 40
    #    num_pixels_y = 40
    #
    #    x = np.linspace(-0.142555996776, 0.142555996776, num_pixels_x)
    #    y = np.linspace(-0.142555996776, 0.142555996776, num_pixels_y)
    #
    #    #x = np.arange(0, np.shape(ref_image_array)[0], 1)          # TODO: wrong values -10 10 21
    #    #y = np.arange(0, np.shape(ref_image_array)[1], 1)          # TODO: wrong values  (30, ...)
    #
    #    xx, yy = np.meshgrid(x, y)
    #    print("delta x:", xx - pixels_position[0])
    #    print("delta y:", yy - pixels_position[1])

    xx, yy = pixels_position[0], pixels_position[1]

    # Based on Tino's evaluate_cleaning.py (l. 277)
    hillas = hillas_parameters_1(
        xx.flatten() * u.meter,  # TODO: essayer avec hillas param 2 !!!
        yy.flatten() * u.meter,
        image_array.flatten())  # [0]

    centroid = (hillas.x, hillas.y)
    length = hillas.length
    width = hillas.width
    angle = np.radians(hillas.psi)  # - np.pi/2.   # TODO

    print("centroid:", centroid)
    print("length:", length)
    print("width:", width)
    print("angle:", angle)

    ###

    # p1 = center of the ellipse
    p1_x = hillas.x
    p1_y = hillas.y

    #image_axis.scatter(p1_x, p1_y)  # DEBUG plot

    # p2 = intersection between the ellipse and the shower track
    p2_x = p1_x + hillas.length * np.cos(angle)  # hillas.psi + np.pi/2)
    p2_y = p1_y + hillas.length * np.sin(angle)  # hillas.psi + np.pi/2)

    #image_axis.scatter(p2_x, p2_y)               # DEBUG plot
    #image_axis.plot([p1_x, p2_x], [p1_y, p2_y])  # DEBUG plot

    print(p1_x, p2_x, p1_y, p2_y)  # DEBUG plot

    d12_x = p1_x - p2_x
    d12_y = p1_y - p2_y

    print(d12_x, d12_y)  # DEBUG plot

    # Slope of the shower track
    T = linalg.normalise(
        np.array([d12_x.value, d12_y.value])
    )  # why a dedicated function ? if it's what I understand, it can easily be done on the fly

    #print("[p1_x-p2_x, p1_y-p2_y]:", [p1_x-p2_x, p1_y-p2_y])
    #print("T:", T)
    #image_axis.plot([p1_x, p1_x*T[0]], [p1_y, p1_y*T[1]], "-g", linewidth=3)  # DEBUG plot

    x = xx.flatten()
    y = yy.flatten()

    # Manhattan distance of pixels to the center of the ellipse
    # Translate (center) on P1 ?
    D = [p1_x.value - x, p1_y.value - y]

    # Pixels in the new base
    dl = D[0] * T[0] + D[1] * T[1]
    dp = D[0] * T[1] - D[1] * T[0]

    # nparray.ravel(): Return a flattened array.
    values, bins, patches = histogram_axis.hist(dp.ravel(),
                                                histtype='step',
                                                bins=np.linspace(
                                                    -size_m, size_m,
                                                    31))  # -10 10 21

    # TODO: scatter seulement  les points qui sont dans le linspace de bins defini juste au dessus, faire apparaitre chaque bin d'une couleure différente

    ##image_axis.scatter(dl, dp, s=10, alpha=0.5)               # DEBUG plot
    #image_axis.scatter(dl, dp, s=10, alpha=0.5)               # DEBUG plot
    #image_axis.plot(dl.reshape(40, 40).T, dp.reshape(40, 40).T)               # DEBUG plot
    #print(dl)
    #print(dp.shape)

    ###

    histogram_axis.set_xlim([-size_m, size_m])

    histogram_axis.set_xlabel('Distance to the shower axis (m)', fontsize=14)
    histogram_axis.set_ylabel('Hits', fontsize=14)

    histogram_axis.set_title(title)