def __sortt(self, key):
     cut_file = key.split('.')
     element_object = Element(cut_file[0].strip())
     element, isotope = element_object.get_element_and_isotope()
     mass = str(isotope)
     if not mass:
         mass = self.__masses.get_standard_isotope(element)
     else:
         mass = float(mass)
     return mass
 def __sortt(self, key):
     if key == "total":
         return -1
     element_object = Element(key)
     element, isotope = element_object.get_element_and_isotope()
     mass = str(isotope)
     if not mass:
         mass = self.__masses.get_standard_isotope(element)
     else:
         mass = float(mass)
     return mass
Beispiel #3
0
    def __init__(self, axes, masses, element_colormap, settings, element=None, isotope=None,
                 element_type="ERD", color=None, points=None, scatter=None,
                 weight_factor=1, transposed=False):
        '''Inits Selection class.
        
        Args:
            axes: Matplotlib FigureCanvas's subplot
            masses: Reference to element masses object of main program.
            element_colormap: Default colors for new element selections.
            settings: Measurement's settings to which selector belongs. 
                      (for selection dialog)
            element: String representing element
            isotope: String representing isotope
            element_type: "ERD" or "RBS"
            color: String representing color for the element
            points: String list representing points in selection.
                    "X1, X2, X3;Y1, Y2, Y3"
            scatter: String representing scatter element. 
            weight_factor: Weight factor for the element.
            transposed: Boolean representing if axes are transposed.
        '''
        self.id = Selection.GLOBAL_ID
        self.masses = masses  # Element isotopes
        self.element_colormap = element_colormap
        self.settings = settings
        
        if color != None:
            self.default_color = color
        elif element != None:
            self.default_color = self.element_colormap[element]
        else:  # By change that color is not in element_colormap
            self.default_color = "red" 
        
        self.type = element_type
        self.element = Element(element, isotope)
        self.weight_factor = weight_factor
        self.element_scatter = Element(scatter)
        
        self.events_counted = False
        self.event_count = 0
        self.__is_transposed = False
        self.is_closed = False
        self.points = None 
        self.axes = axes
        self.axes_limits = AxesLimits()
            
        Selection.GLOBAL_ID += 1

        if points != None:
            points = points.split(';')
            if transposed:
                points[0], points[1] = points[1], points[0]
            x = [int(i) for i in points[0].split(',')]  #  
            y = [int(i) for i in points[1].split(',')]  #
            point_count = len(x)  #
            for i in range(point_count):  #
                self.add_point((x[i], y[i]))
            self.end_selection()
    def on_draw(self):
        '''Draw method for matplotlib.
        '''
        self.axes.clear()  # Clear old stuff
        
        # keys = sorted(self.split.keys())
        keys = [item[0] for item in sorted(self.split.items(),
                                           key=lambda x: self.__sortt(x[0]))]
        for key in keys:
            cut_file = key.split('.')
            element_object = Element(cut_file[0].strip())
            element, isotope = element_object.get_element_and_isotope()
            if key in self.__ignore_elements:
                continue
            # Check RBS selection
            rbs_string = ""
            if len(cut_file) == 2:
                if key + ".cut" in self.__rbs_list.keys():
                    element_object = self.__rbs_list[key + ".cut"]
                    element, isotope = element_object.get_element_and_isotope()
                    rbs_string = "*"
            else:
                if key + cut_file[2] in self.__rbs_list.keys():
                    element_object = self.__rbs_list[key + cut_file[2]]
                    element, isotope = element_object.get_element_and_isotope()
                    rbs_string = "*"
            
            # Get color for selection
            color_string = "{0}{1}{2}".format(isotope, element, cut_file[1])
            if not color_string in self.selection_colors:
                color = "red"
            else:
                color = self.selection_colors[color_string]
            
            # Set label text
            if len(cut_file) == 2:
                label = r"$^{" + str(isotope) + "}$" + element + rbs_string
            else: 
                label = r"$^{" + str(isotope) + "}$" + element + rbs_string \
                        + "$_{split: " + cut_file[2] + "}$"
            # Modify data if scaled to 100.
            data = self.split[key]
            if self.__scale_mode == 2:
                modifier = 100 / self.split[key][0]
                data = [i * modifier for i in data]
            self.axes.plot(data,
                           color=color,
                           label=label)
 
        if self.draw_legend:
            if not self.__initiated_box:
                self.fig.tight_layout(pad=0.5)
                box = self.axes.get_position()
                self.axes.set_position([box.x0, box.y0,
                                        box.width * 0.9, box.height])
                self.__initiated_box = True
            
            handles, labels = self.axes.get_legend_handles_labels()
            leg = self.axes.legend(handles,
                                   labels,
                                   loc=3,
                                   bbox_to_anchor=(1, 0),
                                   borderaxespad=0,
                                   prop={'size':12})
            for handle in leg.legendHandles:
                handle.set_linewidth(3.0)
        
        # Scale based on values
        x_min, x_max = self.axes.get_xlim()
        y_min, y_max = self.axes.get_ylim()
        
        # Y-axis scaling option, 0 = 0-max, 1 = min-max
        if self.y_scale == 0:
            y_min = 0
        
        # Set limits accordingly
        self.axes.set_ylim([y_min, y_max]) 
        self.axes.set_xlim([x_min, x_max])
        
        # Scale for log
        if self.__scale_mode == 1:
            self.axes.set_yscale('symlog')
        else:
            self.axes.set_yscale('linear')
        
        # Set axes names
        if self.__scale_mode == 2:
            self.axes.set_ylabel("Scaled count")
        else:
            self.axes.set_ylabel("Count")
        self.axes.set_xlabel("Split")
             
        # Remove axis ticks
        self.remove_axes_ticks()
        self.canvas.draw()
Beispiel #5
0
class Selection:
    """Selection object which knows all selection points.
    """

    LINE_STYLE = "-"  # Default line style for selections
    LINE_MARKER = "o"  # Default node style for selections
    LINE_MARKER_SIZE = 3.0
    GLOBAL_ID = 0

    def __init__(
        self,
        axes,
        masses,
        element_colormap,
        settings,
        element=None,
        isotope=None,
        element_type="ERD",
        color=None,
        points=None,
        scatter=None,
        weight_factor=1,
        transposed=False,
    ):
        """Inits Selection class.
        
        Args:
            axes: Matplotlib FigureCanvas's subplot
            masses: Reference to element masses object of main program.
            element_colormap: Default colors for new element selections.
            settings: Measurement's settings to which selector belongs. 
                      (for selection dialog)
            element: String representing element
            isotope: String representing isotope
            element_type: "ERD" or "RBS"
            color: String representing color for the element
            points: String list representing points in selection.
                    "X1, X2, X3;Y1, Y2, Y3"
            scatter: String representing scatter element. 
            weight_factor: Weight factor for the element.
            transposed: Boolean representing if axes are transposed.
        """
        self.id = Selection.GLOBAL_ID
        self.masses = masses  # Element isotopes
        self.element_colormap = element_colormap
        self.settings = settings

        if color != None:
            self.default_color = color
        elif element != None:
            self.default_color = self.element_colormap[element]
        else:  # By change that color is not in element_colormap
            self.default_color = "red"

        self.type = element_type
        self.element = Element(element, isotope)
        self.weight_factor = weight_factor
        self.element_scatter = Element(scatter)

        self.events_counted = False
        self.__event_count = 0
        self.__is_transposed = False
        self.is_closed = False
        self.points = None
        self.axes = axes
        self.axes_limits = AxesLimits()

        Selection.GLOBAL_ID += 1

        if points != None:
            points = points.split(";")
            if transposed:
                points[0], points[1] = points[1], points[0]
            x = [int(i) for i in points[0].split(",")]  #
            y = [int(i) for i in points[1].split(",")]  #
            point_count = len(x)  #
            for i in range(point_count):  #
                self.add_point((x[i], y[i]))
            self.end_selection()

    def add_point(self, point):
        """Adds a point to selection.
        
        Adds a point to selection. If selection is closed, do nothing.
        
        Args:
            point: Point (x, y) to be added to selection.
        
        Return:
            0: Point was added.
            -1: If selection is closed.
        """
        if self.is_closed:
            return -1
        else:
            if self.points == None:
                self.points = Line2D(
                    [point[0]],
                    [point[1]],
                    linestyle=Selection.LINE_STYLE,
                    marker=Selection.LINE_MARKER,
                    markersize=Selection.LINE_MARKER_SIZE,
                    color=self.default_color,
                )
            else:
                x, y = self.points.get_data()
                x.append(point[0])
                y.append(point[1])
                self.points.set_data(x, y)
            self.axes.add_line(self.points)
            return 0

    def undo_last(self):
        """Undo last point in selection.
        
        Return:
            1: If selection is closed or there are no points in selection.
            0: If everything is ok.
        """
        if self.is_closed:
            return 1
        # After this, purge the last points so no duplicates should be inside.
        x, y = self.points.get_data()
        if not x:
            return 1
        x.pop()
        y.pop()
        self.points.set_data(x, y)
        return 0

    def get_points(self):
        """Get points in selection 
        
        Get points in selection in list. Format: ((x1,y1), (x2,y2), ...). 
        If no points, empty list is returned
        
        Return:
           ((x1, y1), (x2, y2), ...)
        """
        points = self.points.get_data()
        pointlist = []
        n = 0
        x = len(points[0])
        while n < x:
            pointlist.append([points[0][n], points[1][n]])
            n += 1
        return pointlist

    def get_first(self):
        """Get first point in selection
        
        Return:
            None: If no point in selection
            (x, y): Otherwise
        """
        if self.count() > 0:
            x, y = self.points.get_data()
            return (x[0], y[0])  # TODO: Should this be tuple or a class?
        else:
            return None

    def get_last(self):
        """Get last point in selection
        
        Return:
            None: If no point in selection
            (x, y): Otherwise
        """
        if self.count() > 0:
            x, y = self.points.get_data()
            return (x[-1], y[-1])  # TODO: Should this be tuple or a class?
        else:
            return None

    def count(self):
        """Get the count of node points in selection.
        
        Return
            Returns the count of node points in selection.
        """
        if self.points == None:  # No data yet, "empty" list
            return 0
        return len(self.points.get_data()[0])  # X data count is fine.

    def end_selection(self, canvas=None):
        """End selection.
        
        Ends selection. If selection is open and canvas is not None, it will 
        show dialog to select element information and draws into canvas 
        before opening the dialog.
        
        Args:
            canvas: Matplotlib's FigureCanvas or None when we don't want 
                    to new selection window. None, when loading selections 
                    so we do not want to open new selection settings dialog.

        Return:
            True: Selection was completed
            False: Selection settings was not set (cancel button)
        """
        for point in self.get_points():
            self.axes_limits.update_limits(point)

        # Add first point again, so drawing the line is closed.
        # Then remove it, so no duplicates in points. (roundabout)
        self.add_point(self.get_first())
        x, y = self.points.get_data()
        x.pop()
        y.pop()

        selection_completed = True
        if canvas != None:
            canvas.draw_idle()
            selection_settings_dialog = SelectionSettingsDialog(self)
            # True = ok, False = cancel -> delete selection
            selection_completed = selection_settings_dialog.isOk
        self.is_closed = True
        return selection_completed

    def delete(self):
        """Delete this selection.
        """
        self.points.set_data(((), ()))
        self.points = None
        self.masses = None
        self.element_colormap = None

    def draw(self):
        """Draw selection points into graph (matplotlib) axes
        """
        self.axes.add_line(self.points)

    def set_color(self, color):
        """Set selection color
        
        Args:
            color: String representing color. 
                   Format is whatever QtGui.QColor(string) understands.
        """
        self.points.set_color(color)

    def reset_color(self):
        """Reset selection color to default color.
        """
        self.set_color(self.default_color)

    def __save_points(self, is_transposed):
        """Get selection points in format for saving.
        
        Args:
            is_transposed: Boolean representing if axes are transposed.
            
        Return:
            Returns string representing current points in selection.
        """
        # [1, 4, 2, 6]
        # to
        # 1,4,2,6
        x, y = self.points.get_data()
        x = ",".join(str(i) for i in x)
        y = ",".join(str(j) for j in y)
        # x = str(x).strip('[').strip(']').strip(' ')  # TODO: format?
        # y = str(y).strip('[').strip(']').strip(' ')  # TODO: format?
        if is_transposed:
            x, y = y, x
        s = (x, y)
        return ";".join(s)

    def save_string(self, is_transposed):
        """Get selection in string format for selectiong file save.
        
        Args:
            is_transposed: Boolean representing if axes are transposed.
            
        Return:
            String representing current selection object.
        """
        element, isotope = self.element.get_element_and_isotope()
        save_string = "{0}    {1}    {2}    {3}    {4}    {5}    {6}".format(
            self.type,
            element,
            isotope,
            self.weight_factor,
            self.element_scatter,
            self.default_color,
            self.__save_points(is_transposed),
        )
        return save_string

    def transpose(self, transpose):
        """Transpose selection points.
        
        Args:
            transpose: Boolean representing whether to transpose selection points.
        """
        if transpose:  #  and not self.__is_transposed
            self.__is_transposed = True
            x, y = self.points.get_data()
            x.append(x[0])
            y.append(y[0])
            self.points.set_data(y, x)
        elif not transpose:  # and self.__is_transposed
            self.__is_transposed = False
            x, y = self.points.get_data()
            x.append(x[0])
            y.append(y[0])
            self.points.set_data(y, x)

    def get_event_count(self):
        """Get the count of event points within the selection.
        
        Return:
            Returns an integer representing the count of event points within 
            the selection.
        """
        return self.__event_count

    def point_inside(self, point):
        """Check if point is inside selection.
        
        Args:
            point: [X, Y] representing a point.
            
        Return:
            Returns True if point is within selection. False otherwise.
        """
        if not self.axes_limits.is_inside(point):
            return False
        inside = self.__point_inside_polygon(point[0], point[1], self.get_points())
        # While at it, increase event point counts if not counted already.
        if inside and not self.events_counted:
            self.__event_count += 1
        return inside

    def __point_inside_polygon(self, x, y, poly):
        """Finds out if a point x, y is inside a polygon "poly"
        
        Determine if a point is inside a given polygon or not
        Polygon is a list of (x,y) pairs.        
        
        Algorithm got from: http://www.ariel.com.au/a/python-point-int-poly.html
        """
        n = len(poly)
        inside = False

        p1x, p1y = poly[0]
        for i in range(n + 1):
            p2x, p2y = poly[i % n]
            if y > min(p1y, p2y):
                if y <= max(p1y, p2y):
                    if x <= max(p1x, p2x):
                        if p1y != p2y:
                            xinters = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
                        if p1x == p2x or x <= xinters:
                            inside = not inside
            p1x, p1y = p2x, p2y
        return inside
    def on_draw(self):
        '''Draw method for matplotlib.
        '''
        # Values for zoom
        x_min, x_max = self.axes.get_xlim()
        y_min, y_max = self.axes.get_ylim()
        
        self.axes.clear()  # Clear old stuff
                
        self.axes.set_ylabel("Yield (counts)")
        self.axes.set_xlabel("Energy (MeV)")
        
        element_counts = {}
        keys = [item[0] for item in sorted(self.histed_files.items(),
                                           key=lambda x: self.__sortt(x[0]))]
        for key in keys:
            cut_file = key.split('.')
            cut = self.histed_files[key]
            element_object = Element(cut_file[0])  # Yeah...
            element, isotope = element_object.get_element_and_isotope()
            if key in self.__ignore_elements:
                continue
            
            # Check RBS selection
            rbs_string = ""
            if len(cut_file) == 2:
                if key + ".cut" in self.__rbs_list.keys():
                    element_object = self.__rbs_list[key + ".cut"]
                    element, isotope = element_object.get_element_and_isotope()
                    rbs_string = "*"
            else:
                if key in self.__rbs_list.keys():
                    element_object = self.__rbs_list[key]
                    element, isotope = element_object.get_element_and_isotope()
                    rbs_string = "*"
                    
            x = tuple(float(pair[0]) for pair in cut)
            y = tuple(float(pair[1]) for pair in cut)
            
            # Get color for selection
            dirtyinteger = 0
            while "{0}{1}{2}".format(isotope, element, dirtyinteger) in element_counts:
                dirtyinteger += 1
            color_string = "{0}{1}{2}".format(isotope, element, dirtyinteger)
            element_counts[color_string] = 1
            if not color_string in self.__selection_colors:
                color = "red"
            else:
                color = self.__selection_colors[color_string]
            
            if len(cut_file) == 2:
                label = r"$^{" + str(isotope) + "}$" + element + rbs_string
            else: 
                label = r"$^{" + str(isotope) + "}$" + element + rbs_string \
                        + "$_{split: " + cut_file[2] + "}$"
            self.axes.plot(x, y,
                           color=color,
                           label=label)
        
        if self.draw_legend:
            if not self.__initiated_box:
                self.fig.tight_layout(pad=0.5)
                box = self.axes.get_position()
                self.axes.set_position([box.x0, box.y0,
                                        box.width * 0.9, box.height])
                self.__initiated_box = True
            
            handles, labels = self.axes.get_legend_handles_labels()
            leg = self.axes.legend(handles,
                                   labels,
                                   loc=3,
                                   bbox_to_anchor=(1, 0),
                                   borderaxespad=0,
                                   prop={'size':12})
            for handle in leg.legendHandles:
                handle.set_linewidth(3.0)
        
        if x_max > 0.09 and x_max < 1.01:  # This works...
            x_max = self.axes.get_xlim()[1]
        if y_max > 0.09 and y_max < 1.01:
            y_max = self.axes.get_ylim()[1]
        
        # Set limits accordingly
        self.axes.set_ylim([y_min, y_max])
        self.axes.set_xlim([x_min, x_max])
         
        if self.__log_scale:
            self.axes.set_yscale('symlog')
        
        # Remove axis ticks
        self.remove_axes_ticks()

        # Draw magic
        self.canvas.draw()