Esempio n. 1
0
class MoveBoxRoutine(AniRoutine):
    def __init__(self, figure, plot_cood):
        super().__init__(figure, plot_cood)
        self.move_box = TextBox(self.ax, 'Move #: ', 0)

    def update(self, index):
        self.move_box.set_val(index)
Esempio n. 2
0
def view():
    
    # fig, ax = plt.subplots()
    fig, ax = plt.subplots()
    
    # axes style
    ax.set_title('B-Spline-Curves')
    ax.set_xlim(1, 10)
    ax.set_ylim(1, 24)
    box = ax.get_position()
    ax.set_position([box.x0, box.y0, box.width * 0.7, box.height])

    # fig layout
    plt.text(10.3, 18, "User Tips:", fontfamily='fantasy', fontstyle='italic',
             fontsize='large', fontweight='roman', color='r', backgroundcolor='#87CEEB',  # skyblue
             bbox=dict(boxstyle="round", fc='#87CEEB'), rasterized='True'
             )
    plt.text(10.5, 11, "Add  point: $Mouse-Right$\n"
                       "Drag point: $Mouse-Left$\n"
                       "Hide Line: h / H\nExit: q / Q\n",
             fontfamily='serif', fontstyle='oblique', fontsize='medium', color='#000080'
             )
    
    # add new line button, input textbox and radio button
    addlinebtn = fig.add_axes([0.75, 0.22, 0.2, 0.075])
    inputbox = fig.add_axes([0.85, 0.12, 0.1, 0.07])
    rax = fig.add_axes([0.75, 0.32, 0.2, 0.12])
    
    # button click
    btncallback = CreatLine(ax)
    binsert = Button(addlinebtn, 'New Line', color='#00BFFF')
    binsert.on_clicked(btncallback.createnewline)
    
    # input submit
    input_text = TextBox(inputbox, "Degree : ")
    input_text.on_submit(change_degree)
    input_text.set_val("3")
    
    # radio callback
    radio = RadioButtons(rax, ("Uniform", "Clamped"))
    radio.on_clicked(change_type)

    # add first line
    CreatLine(ax).createnewline(event=None)
    ax.legend(loc='upper left', bbox_to_anchor=(1, 1.02), fontsize='medium', shadow='True')

    plt.show()
class numeric_field:
    def __init__(self, inp_ax, label, regexp, maxlen, decpoint=None):
        self.val = ''
        self.curpos = 0
        self.pattern = re.compile(regexp)
        self.maxlen = maxlen
        self.decpoint = decpoint
        self.tb = TextBox(inp_ax, label)
        self.tb.on_text_change(self.tc_func)

    def tc_func(self, inp):
        if (len(inp) > self.maxlen):
            self.tb.cursor_index = self.curpos
            self.tb.set_val(self.val)
            return
        if (self.decpoint and inp.find('.') < 0
                and len(inp) > self.maxlen - 1):
            self.tb.cursor_index = self.curpos
            self.tb.set_val(self.val)
            return
        if (not self.pattern.match(inp)):
            self.tb.cursor_index = self.curpos
            self.tb.set_val(self.val)
            return
        self.val = inp
        self.curpos = self.tb.cursor_index
Esempio n. 4
0
class DGILibPlot(object):
    """DGILibPlot
   
    The `DGILibPlot` class is responsible with plotting the electrical current
    (Amperes) data and gpio state data (values of `1`/`0`) obtained from an
    Atmel board.

    The X axis represents time in seconds, while the Y axis represents
    the electrical current in Amperes.

    There are two ways that the gpio pins state can be shown along with the
    electrical current. One is the `line` method and one is the `highlight`
    method. The `line` method shows a square waveform, a typical byproduct of
    the digital signal that gpio pins usually have. The `highlight` method
    highlights only particular parts of the plot with semi-transparent
    coloured areas, where the pins have a value of interest (set using the
    ``plot_pins_values`` argument of the class).

    Below are shown some examples of `DGILibPlot` and the two methods of
    drawing the gpio pins  (`line`/`highlight`).

    **Example plots using "line" method:**

    .. figure:: images/plot_line_1.png
       :scale: 60%

       Figure 1: Example of plot with the 'line' method chosen for the drawing of
       pins. All of the pins are being plotted, so you can always see their
       `True`/`False` values.

    .. figure:: images/plot_line_2.png
       :scale: 60%

       Figure 2: The same plot with the same data as figure 1, only zoomed in.

    .. figure:: images/plot_line_3.png
       :scale: 60%

       Figure 3: The same plot with the same data as figure 1 and 2, only even
       more zoomed in. Here we can clearly see that gpio pins 0, 2 and 3 have
       defaulted on a single value all along the program's execution on the
       board. We can however clearly see the toggling of pin 1,
       represented in orange.

    **Example plots using "highlight" method:**

    .. figure:: images/plot_highlight_1.png
       :scale: 60%

       Figure 4: Example of plot with the 'highlight' method chosen for the
       drawing of pins. The time the pins are holding the value of interest (in
       this case, `True` value) is small every time. This is why we can see the
       highlighted areas looking more like vertical lines when zoomed
       out. The only pin being toggled by the program on the board is
       pin 1, hence it's why we only see one color of highlighted areas.

    .. figure:: images/plot_highlight_2.png
       :scale: 60%

       Figure 5: The same plot with the same data as figure 1, only zoomed in.

    .. figure:: images/plot_highlight_3.png
       :scale: 60%

       Figure 6: The same plot with the same data as figure 1 and 2, only even
       more zoomed in. Now we can see one of the the  highlight
       area in its proper form.

    **Parameters**

    The parameters listed in the section below can be passed as arguments when
    initializing the `DGILibPlot` object, or as arguments to a `DGILibExtra`
    object. They can be included in a configuration dictionary
    (:py:class:`dict` object) and then unwrapped in the initialization function
    call of either the `DGILibPlot` object or the `DGILibExtra` object (by
    doing: ``dgilib_plot = DGILibPlot(**config_dict)`` or ``with
    DGILibExtra(**config_dict) as dgilib: ...``).

    Parameters
    ----------
    dgilib_extra : DGILibExtra
        A `DGILibExtra` object can be specified, from where the plot can obtain
        the electrical current and gpio state data. If a `DGILibExtra` object
        is not desired to be specified however, then it should be set to
        `None`.

        (the default is `None`, meaning that measurements data (in the form
        of a :class:`DGILibData` should be manually called as 
        function updates))

    fig : matplotlib.pyplot.figure, optional
        If it is wanted so that the data is to be plotted on an already
        existing `matplotlib` figure, then the object representing the already
        instantiated figure can be specified for this parameter. For example,
        the electrical current data and gpio state data can be plotted
        in a subplot of a figure window that holds other plots as well.

        (the default is `None`, meaning that a new figure object will be
        created internally)

    ax : matplotlib.pyplot.axes, optional
        If it is wanted so that the data is to be plotted on an already
        existing `matplotlib` axes, then the object representing the already
        instantiated axes can be specified for this parameter.

        (the default is `None`, meaning that a new axes object will be
        created internally)

    ln : matplotlib.pyplot.lines2d, optional
        If it is wanted so that the data is to be plotted on an already
        existing `matplotlib` `Lines2D` object, then the object representing
        the already instantiated `Lines2D` object can be specified for this
        parameter.

        (the default is `None`, meaning that a new `Lines2D` object will be
        created internally)

    window_title : str, optional
        If another window title than the default is desired to be used, it can
        be specified here.

        (the default is ``Plot of current (in amperes) and gpio pins``)

    plot_xmax : int, optional
        This *initializes* the figure view to a maximum of `plot_xmax` on
        the X axis, where the data to be plotted. Later, the user can change
        the figure view using the bottom sliders of the plot figure.

        (the default is an arbitrary `10`)

    plot_ymax : int, optional
        This *initializes* the figure view to a maximum of `plot_xmax` on
        the Y axis, where the data to be plotted. Later, the user can change
        the figure view using the bottom sliders of the plot figure.

        (the default is `0.005`, meaning 5 mA, so that something as
        energy consuming as a blinking LED can be shown by a `DGILibPlot`
        with default settings)

    plot_pins : list(bool, bool, bool, bool), optional
        Set the pins to be drawn in the plot, out of the 4 GPIO available pins
        that the Atmel board gives data about to be sent through the computer
        through the Atmel Embedded Debugger (EDBG) Data Gateway Interface
        (DGI).

        (the default is `[True, True, True, True]`, meaning all pins are
        drawn)

    plot_pins_method : str, optional
        Set the *method* of drawing the pin. The values can be either
        ``"line"`` or ``"highlight"``. Refer to the above figures to see
        the differences.

        (the default is `"highlight"`)

    plot_pins_colors : list(str, str, str, str), optional
        Set the colors of the semi-transparent highlight areas drawn when using
        the `highlight` method, or the lines when using the `lines` method of
        drawing pins. 
        
        (the default is `["red", "orange", "blue", "green"]`,
        meaning that pin 0 will have a `red` semi-transparent highlight area or
        line, pin 1 will have `orange` ones, and so on)

    automove_method : str, optional
        When the plot is receiving data live from the measurements taken in
        real-time from the board (as opposed to receiving all the data to be
        plotted at once, say, when reading the data from saved csv files), and
        `plot_xmax` is smaller than the expected size of the data in the end,
        then at some point the data will update past the figure view.
        `DGILibPlot` automatically moves the figure view to the last timestamp
        of the latest data received, and it can do so in two ways, depending on
        the value of ``automove_method``.

        The `page` method changes the figure view in increments of
        ``plot_ymax``, when the data updates past the figure view, as if the
        plot is turning one "page" at a time. The `latest_data` method makes
        the figure view always have the latest data in view, meaning that it
        moves in small increments so that it always keeps the latest data point
        `0.15` seconds away from the right edge of the figure view. The `0.15`
        seconds value is an arbitrary hard-coded value, chosen after some
        experiments.

        (the default is 'latest_data', meaning the plot's figure view will
        follow the latest data in smaller increments, keeping the latest data
        always on the right side of the plot)

    verbose : int
        Specifies verbosity:

        - 0: Silent

        - 1: Currently prints if data is missing, either as an object or as \
        values, when :func:`update_plot` is being called.

        (the default is `0`)

    Attributes
    ----------
    axvspans : list(4 x list(matplotlib.pyplot.axvspan))
        The way the semi-transparent coloured areas for the gpio pins are drawn
        on the plot is by using ``matplotlib.pyplot.axvspan`` objects. The
        `axvspan` objects are collected in a list for potential use for later.
        (e.g.: such as to delete them, using the :func:`clear_pins` method).

        (the default is 4 empty lists, meaning no highlighting of areas of
        interest has occured yet)

    annotations : list(4 x list(str))
        As we have seen in figures 4, 5, 6, for the `highlight` method of
        drawing pins, the counting or iteration of the highlighted areas are
        also showed on the plot. There are 4 pins, so therefore 4 lists of the
        counting/iteration stored as strings are saved by the `DGILibPlot` for
        later use by developers (e.g.: to replace from numbers to actual
        descriptions and then call the redrawing of pins).

        (the default is 4 empty lists, meaning no annotations for the
        highlighted areas of interest were placed yet)

    preprocessed_averages_data : list(4 x list(tuple(int, \
    tuple(float, float), int, float)))
        As the `highlight` method draws the pins on the plot with the help of
        the :class:`HoldTimes` class, that means the plot knows afterwards the
        time intervals in which the pins have values of interest. This can be
        valuable for a subsequent averaging function that wants to calculate
        faster the average current or energy consumption of the the board
        activity only where it was highlighted on the plot. As such,
        `DGILibPlot` prepares a list of 4 lists of tuples, each for every pin,
        the tuple containing the iteration index of the highlighted area of
        interest the pins kept the same value consecutively (called a `hold`
        time), another tuple containing the timestamps with respect to the
        electrical current data, which says the beginning and end times of that
        `hold` interval,  an index in the list of the electrical current data
        points where the respective hold time starts and, lastly, a `None`
        value, which then should be replaced with a :py:class:`float` value for
        the the average current or charge during that hold time.

        (the default is 4 empty lists, meaning no gathered preprocessed
        averages data yet)

    iterations : list(4 x int)
        As the plot is being updated live, the `iterations` list holds the
        number of highlighed areas that have been drawn already for for each
        pin. As the whole measurement data gets plotted, the iterations list
        practically holds the number of iterations the of all the areas
        of interest for each pin (which can be, for example, the number
        of `for` loops that took place in the program itself running on the
        board).

        (the default are 4 ``0`` values, meaning no areas of interest
        on the gpio data has been identified)

    last_xpos : float
        As the plot is being updated live, the figure view moves along with the
        latest data to be shown on the plot. If the user desires to stop this
        automatic movement and focus on some specific area of the plot, while
        the data is still being updated in real-time, the figure needs to
        detect that it should stop following the data to not disturb the user.
        It does so by comparing the current x-axis position value of the x axis
        shown, with the last x-axis position value saved, before doing any
        automatic movement of the figure view. If they are different, no
        automatic movement is being done from now on.
        
    xylim_mutex : Lock
        As there are many ways to move, zoom and otherwise manipulate the
        figure view to different sections of the plot, using the `matplotlib`'s
        implicit movement and zoom controls, or the freshly built `DGILibPlot`
        sliders appearing at the bottom (See figures), or the automatic
        following of the latest data feature, there is a multi-threading aspect
        involved and therefore a mutex should be involved, in the form
        of a `Lock` object, to prevent anomalies.

    hold_times_obj: HoldTimes
        Only instantiated when `highlight` method is being used for drawing
        pins information, the :class:`HoldTimes` class holds the algorithm that
        works on the live data to obtain the timestamps of areas of interest of
        the gpio data, in order to be highlighted on the plot. As the algorithm
        works on live updating data, the areas of interst can be cut off
        between updates of data. As such, the :class:`HoldTimes` keeps
        information for the algorithm to work with, in order to advert this.    
    """
    def __init__(self, dgilib_extra=None, *args, **kwargs):
        self.dgilib_extra = dgilib_extra

        # Maybe the user wants to put the power figure along with
        # other figures he wants
        self.fig = kwargs.get("fig")
        if self.fig is None:
            self.fig = plt.figure(figsize=(8, 6))

        # Set window title if supplied, if not set a default
        self.window_title = kwargs.get(
            "window_title", "Plot of current (in amperes) and" + "gpio pins")
        self.fig.canvas.set_window_title(self.window_title)

        self.ax = kwargs.get("ax")
        if self.ax is None:
            self.ax = self.fig.add_subplot(1, 1, 1)
            self.ax.set_xlabel('Time [s]')
            self.ax.set_ylabel('Current [A]')

        # We need the Line2D object as well, to update it
        if (len(self.ax.lines) == 0):
            self.ln, = self.ax.plot([], [], 'r-', label="Power")
        else:
            self.ln = self.ax.lines[0]
            self.ln.set_xdata([])
            self.ln.set_ydata([])

        # Initialize xmax, ymax of plot initially
        self.plot_xmax = kwargs.get("plot_xmax", None)
        if self.plot_xmax is None:
            self.plot_xauto = True
            self.plot_xmax = 10
        else:
            self.plot_xauto = False

        self.plot_ymax = kwargs.get("plot_ymax", None)
        if self.plot_ymax is None:
            self.plot_yauto = True
            self.plot_ymax = 0.005
        else:
            self.plot_yauto = False

        self.plot_pins = kwargs.get("plot_pins", [True, True, True, True])
        self.plot_pins_values = kwargs.get("plot_pins_values",
                                           [True, True, True, True])
        self.plot_pins_method = kwargs.get("plot_pins_method",
                                           "highlight")  # or "line"
        self.plot_pins_colors = kwargs.get("plot_pins_colors",
                                           ["red", "orange", "blue", "green"])
        self.automove_method = kwargs.get("automove_method",
                                          "latest_data")  # or "page"
        self.axvspans = [[], [], [], []]
        self.annotations = [[], [], [], []]
        self.preprocessed_averages_data = [[], [], [], []]
        #self.total_average = [0,0,0,0]
        self.iterations = [0, 0, 0, 0]
        self.last_xpos = 0.0
        self.xylim_mutex = Lock()

        #self.refresh_plot_pause_secs = kwargs.get("refresh_plot_pause_secs", 0.00000001)

        if self.plot_pins_method == "highlight":
            self.hold_times_obj = HoldTimes()

        if self.plot_pins_method == "line":
            self.ax_pins = self.ax.twinx()
            self.ax_pins.set_ylabel('Pin Value')
            self.ax_pins.set_ylim([-0.1, 1.1])
            self.ax_pins.set_yticks([0, 1])
            self.ax_pins.set_yticklabels(["Low", "High"])
            self.ln_pins = list(
                self.plot_pins)  # Instantiate as copy of plot_pins
            for pin, plot_pin in enumerate(self.plot_pins):
                if plot_pin:
                    self.ln_pins[pin] = self.ax_pins.plot(
                        [], [], label=f"gpio{pin}")[0]
            self.ax_pins.legend(handles=[
                ln_pin
                for ln_pin in self.ln_pins if not isinstance(ln_pin, bool)
            ] + [self.ln])  # Should actually check if it is a lines instance

        # Hardwiring these values to 0
        self.plot_xmin = 0
        self.plot_ymin = 0

        # We need these values from the user (or from the superior class),
        #   hence no default values
        # TODO: Are they really needed though?
        self.plot_xdiv = kwargs.get("plot_xdiv", min(5, self.plot_xmax))
        self.plot_xstep = kwargs.get("plot_xstep", 0.5)
        self.plot_xstep_default = self.plot_xstep
        # self.duration = kwargs.get("duration", max(self.plot_xmax, 5))

        # We'll have some sliders to zoom in and out of the plot, as well as a cursor to move around when zoomed in
        # Leave space for sliders at the bottom
        plt.subplots_adjust(bottom=0.3)
        # Show grid
        self.ax.grid()

        # Slider color
        self.axcolor = 'lightgoldenrodyellow'
        # Title format
        # Should use this https://matplotlib.org/gallery/recipes/placing_text_boxes.html
        self.title_avg = "Total avg curr: %1"
        self.title_vis = "Visible avg curr: %1"
        self.title_pin = "Avg curr in %1: %2"  # "calculate_average(data[INTERFACE_POWER])*1e3:.4} mA"
        self.title_time = "Time spent in %1: %2"
        self.ax.set_title("Waiting for data...")

        # Hold times for pins list, we're going to collect them
        self.hold_times_sum = 0.00
        self.hold_times_next_index = 0  # Will be incremented to 0 later
        self.hold_times_already_drawn = []

        self.verbose = kwargs.get("verbose", 0)

        self.initialize_sliders()

    def initialize_sliders(self):
        self.axpos = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor=self.axcolor)
        self.axwidth = plt.axes([0.25, 0.15, 0.65, 0.03],
                                facecolor=self.axcolor)
        self.resetax = plt.axes([0.8, 0.025, 0.1, 0.04])

        self.spos = Slider(self.axpos,
                           'x',
                           0,
                           self.plot_xmax,
                           valinit=0,
                           valstep=self.plot_xstep)
        self.swidth = Slider(self.axwidth,
                             'xmax',
                             0,
                             self.plot_xmax,
                             valinit=self.plot_xdiv,
                             valstep=self.plot_xstep)
        self.resetbtn = Button(self.resetax,
                               'Reset',
                               color=self.axcolor,
                               hovercolor='0.975')

        #TODO: Change to pixel sizes
        self.xleftax = plt.axes([0.4, 0.025, 0.095,
                                 0.04])  # x_pos, y_pos, width, height
        self.xrightax = plt.axes([0.5, 0.025, 0.095, 0.04])
        self.xmaxleftax = plt.axes([0.6, 0.025, 0.095, 0.04])
        self.xmaxrightax = plt.axes([0.7, 0.025, 0.095, 0.04])
        self.xstepupax = plt.axes([0.3, 0.025, 0.095, 0.04])
        self.xstepdownax = plt.axes([0.2, 0.025, 0.095, 0.04])

        self.xleftbtn = Button(self.xleftax,
                               '<x',
                               color=self.axcolor,
                               hovercolor='0.975')
        self.xrightbtn = Button(self.xrightax,
                                'x>',
                                color=self.axcolor,
                                hovercolor='0.975')
        self.xmaxleftbtn = Button(self.xmaxleftax,
                                  'xmax-',
                                  color=self.axcolor,
                                  hovercolor='0.975')
        self.xmaxrightbtn = Button(self.xmaxrightax,
                                   'xmax+',
                                   color=self.axcolor,
                                   hovercolor='0.975')
        self.xstepupbtn = Button(self.xstepupax,
                                 'xstep+',
                                 color=self.axcolor,
                                 hovercolor='0.975')
        self.xstepdownbtn = Button(self.xstepdownax,
                                   'xstep-',
                                   color=self.axcolor,
                                   hovercolor='0.975')

        self.xstepax = plt.axes([0.1, 0.025, 0.095, 0.04])
        self.xsteptb = TextBox(self.xstepax,
                               'xstep',
                               initial=str(self.plot_xstep))

        def xstep_submit(text):
            self.plot_xstep = float(text)

        self.xsteptb.on_submit(xstep_submit)

        def increase_x(event):
            #if ((self.spos.val + self.plot_xstep) <= (self.plot_xmax - self.swidth.val)):
            self.spos.set_val(self.spos.val + self.plot_xstep)
            update_pos(self.spos.val)

        def decrease_x(event):
            #if ((self.spos.val - self.plot_xstep) >= (self.plot_xmin)):
            self.spos.set_val(self.spos.val - self.plot_xstep)
            update_pos(self.spos.val)

        def increase_xmax(event):
            #if ((self.swidth.val + self.plot_xstep) <= self.plot_xmax):
            self.swidth.set_val(self.swidth.val + self.plot_xstep)
            update_width(self.swidth.val)

        def decrease_xmax(event):
            if ((self.swidth.val - self.plot_xstep) >=
                (self.plot_xmin + 0.000001)):
                self.swidth.set_val(self.swidth.val - self.plot_xstep)
                update_width(self.swidth.val)

        def increase_xstep(event):
            val = float(self.xsteptb.text)
            if ((val + 0.05) < (self.swidth.val - 0.000001)):
                self.xsteptb.set_val("{0:.2f}".format(val + 0.05))
                xstep_submit(self.xsteptb.text)

        def decrease_xstep(event):
            val = float(self.xsteptb.text)
            if ((val - 0.05) >= (0.05)):
                self.xsteptb.set_val("{0:.2f}".format(val - 0.05))
                xstep_submit(self.xsteptb.text)

        self.xleftbtn.on_clicked(decrease_x)
        self.xrightbtn.on_clicked(increase_x)
        self.xmaxleftbtn.on_clicked(decrease_xmax)
        self.xmaxrightbtn.on_clicked(increase_xmax)
        self.xstepupbtn.on_clicked(increase_xstep)
        self.xstepdownbtn.on_clicked(decrease_xstep)

        # I'm not sure how to detach these without them forgetting their parents (sliders)
        def update_pos(val):
            if self.xylim_mutex.acquire(False):
                pos = self.spos.val
                width = self.swidth.val

                #self.set_axis(pos, pos + width, self.plot_ymin, self.plot_ymax, "update_pos function")
                self.ax.axis(
                    [pos, pos + width, self.plot_ymin, self.plot_ymax])

                self.xylim_mutex.release()

        def update_width(val):
            if self.xylim_mutex.acquire(False):
                pos = self.spos.val
                width = self.swidth.val

                self.axpos.clear()
                self.spos.__init__(self.axpos,
                                   'x',
                                   0,
                                   width,
                                   valinit=pos,
                                   valstep=self.plot_xstep)
                self.spos.on_changed(update_pos)
                self.spos.set_val(pos)

                #self.set_axis(pos, pos + width, self.plot_ymin, self.plot_ymax, "update_width function")
                self.ax.axis(
                    [pos, pos + width, self.plot_ymin, self.plot_ymax])

                self.xylim_mutex.release()

        self.spos.on_changed(update_pos)
        self.swidth.on_changed(update_width)

        # TODO: This
        def see_all(event):
            if self.xylim_mutex.acquire(False):

                #self.set_axis(0, self.last_timestamp, self.plot_ymin, self.plot_ymax, "see_all function")
                self.ax.axis(
                    [0, self.last_timestamp, self.plot_ymin, self.plot_ymax])
                self.last_xpos = -1

                self.xylim_mutex.release()

        def reset(event):
            if self.xylim_mutex.acquire(False):
                self.swidth.set_val(self.plot_xmax)

                self.axpos.clear()
                self.spos.__init__(self.axpos,
                                   'x',
                                   0,
                                   self.plot_xmax,
                                   valinit=0,
                                   valstep=self.plot_xstep_default)
                self.spos.on_changed(update_pos)

                self.xsteptb.set_val(str(self.plot_xstep_default))

                #self.set_axis(self.plot_xmin, self.plot_xmax, self.plot_ymin, self.plot_ymax, "reset function")
                self.ax.axis([
                    self.plot_xmin, self.plot_xmax, self.plot_ymin,
                    self.plot_ymax
                ])
                self.last_xpos = -1

                self.xylim_mutex.release()

        self.resetbtn.on_clicked(reset)

        self.spos.set_val(0)
        self.swidth.set_val(self.plot_xmax)

        # Auto-change the sliders/buttons when using plot tools
        def on_xlims_change(axes):
            if self.xylim_mutex.acquire(False):  # Non-blocking
                xlim_left = self.ax.get_xlim()[0]
                xlim_right = self.ax.get_xlim()[1]

                pos = xlim_left
                width = xlim_right - xlim_left

                self.spos.set_val(pos)
                self.swidth.set_val(width)
                self.last_xpos = -1

                self.xylim_mutex.release()

        def on_ylims_change(axes):
            print(self.ax.get_ylim())

        self.ax.callbacks.connect('xlim_changed', on_xlims_change)
        #self.ax.callbacks.connect('ylim_changed', on_ylims_change)

    def update_plot(self, data):
        verbose = self.verbose

        if data is None:
            data = self.dgilib_extra.data

        if (not data):
            if verbose:
                print(
                    "dgilib_plot.update_plot: Expected 'data' containing interfaces. Got 'data' with no interfaces. Returning from call with no work done."
                )
            return
        if (not data.power):
            if verbose:
                print(
                    "dgilib_plot.update_plot: Expected 'data' containing power data. Got 'data' with interfaces but no power timestamp & value pairs. Returning from call with no work done."
                )
            return
        if (not data.gpio):
            if verbose:
                print(
                    "dgilib_plot.update_plot: Expected 'data' containing gpio data. Got 'data' with interfaces but no gpio timestamp & value pairs."
                )
            return

        if not plt.fignum_exists(self.fig.number):
            plt.show()
        else:
            plt.draw()
        self.refresh_plot()

        #TODO: ln might have an update_callback and then it can listen to the data being updated instead of updating data here
        self.ln.set_xdata(data.power.timestamps)
        self.ln.set_ydata(data.power.values)

        automove = True
        current_xpos = self.ax.get_xlim()[0]

        if self.last_xpos != current_xpos:
            automove = False

        if automove and self.xylim_mutex.acquire(False):
            last_timestamp = data.power.timestamps[-1]

            pos = self.spos.val
            width = self.swidth.val

            if (last_timestamp > (pos + width)):
                if self.automove_method == "page":
                    self.spos.set_val(pos + width)
                elif self.automove_method == "latest_data":
                    arbitrary_amount = 0.15
                    if last_timestamp > width:
                        self.spos.set_val(last_timestamp + arbitrary_amount -
                                          width)

            pos = self.spos.val
            width = self.swidth.val

            self.ax.axis([pos, pos + width, self.plot_ymin, self.plot_ymax])
            self.last_xpos = pos

            self.xylim_mutex.release()

        self.refresh_plot()

        self.draw_pins(data)

    def clear_pins(self):
        """
        Clears the highlighted areas on the plot that represent the state of the gpio pins
        (as seen in figures 4, 5, 6). Using this method only makes sense if the `highlight`
        method of drawing pins was used.
        """
        if self.axvspans is None:
            return

        for axvsp in self.axvspans:
            axvsp.remove()

    def draw_pins(self, data):
        """draw_pins [summary]
        
        Raises
        ------
        ValueError
            Raised when `plot_pins_method` member of class has another 
            string value than the ones available (`highlight`, `line`)

        Parameters
        ----------
        data : DGILibData
            :class:`DGILibData` object that contains the GPIO data to be drawn
            on the plot.
        """
        # Here we set defaults (with 'or' keyword ...)
        ax = self.ax
        plot_pins = self.plot_pins
        plot_pins_values = self.plot_pins_values
        #plot_pins_method = self.plot_pins_method or "highlight"
        plot_pins_colors = self.plot_pins_colors

        # Here we do checks and stop drawing pins if something is unset
        if ax is None: return
        if plot_pins is None: return

        verbose = self.verbose

        no_of_pins = len(self.plot_pins)

        if self.plot_pins_method == "highlight":

            for pin_idx in range(no_of_pins):  # For every pin number (0,1,2,3)

                if plot_pins[pin_idx] == True:  # If we want them plotted

                    hold_times = self.hold_times_obj.identify_hold_times(
                        pin_idx, plot_pins_values[pin_idx], data.gpio)

                    if hold_times is not None:
                        for ht in hold_times:
                            axvsp = ax.axvspan(ht[0],
                                               ht[1],
                                               color=plot_pins_colors[pin_idx],
                                               alpha=0.25)
                            self.axvspans[pin_idx].append(axvsp)

                            x_halfway = (ht[1] - ht[0]) / 4 + ht[0]
                            y_halfway = (self.plot_ymax -
                                         self.plot_ymin) / 2 + self.plot_ymin
                            annon = ax.annotate(str(self.iterations[pin_idx] +
                                                    1),
                                                xy=(x_halfway, y_halfway))
                            self.annotations[pin_idx].append(annon)

                            self.iterations[pin_idx] += 1

                            # TODO:  The start and stop indexes of the data points that are area of interest
                            # might be more useful for an averaging function, but currently the plot uses
                            # the coordinates of the X axis(the start/stop timestamps) in order to highlight
                            # the areas of interest.
                            self.preprocessed_averages_data[pin_idx].append(
                                (self.iterations[pin_idx], ht, 0, None))

            # This should be in update_plot()
            self.ax.set_title(
                f"Logging. Collected {len(data.power)} power samples and {len(data.gpio)} gpio samples."
            )

        elif self.plot_pins_method == "line":
            extend_gpio = data.gpio.timestamps[-1] < data.power.timestamps[-1]
            for pin, plot_pin in enumerate(self.plot_pins):
                if plot_pin:
                    self.ln_pins[pin].set_xdata(data.gpio.timestamps +
                                                extend_gpio *
                                                [data.power.timestamps[-1]])
                    self.ln_pins[pin].set_ydata(
                        data.gpio.get_select_in_value(pin) +
                        extend_gpio * [data.gpio.values[-1][pin]])
            self.ax.set_title(
                f"Logging. Collected {len(data.power)} power samples and {len(data.gpio)} gpio samples."
            )
            self.fig.show()
        else:
            raise ValueError(
                f"Unrecognized plot_pins_method: {self.plot_pins_method}")

    def plot_still_exists(self):
        """plot_still_exists 
        
        Can be used in a boolean (e.g.: `if`, `while`) clause to check if the
        plot is still shown inside a window (e.g.: to unpause program
        functionality if the plot is closed).

        Also used in the :func:`keep_plot_alive` member function of the
        class.

        Returns
        -------
        bool
            Returns `True` if the plot still exists and `False` otherwise.
        """
        return plt.fignum_exists(self.fig.number)

    def refresh_plot(self):
        """refresh_plot

        Makes a few `matplotlib` specific calls to refresh and redraw the plot
        (especially when new data is to be drawn). 
        
        Is used in :func:`update_plot` member function of the class.
        """
        self.ax.relim()  # recompute the data limits
        self.ax.autoscale_view()  # automatic axis scaling
        self.fig.canvas.flush_events()

    def keep_plot_alive(self):
        while self.plot_still_exists():
            self.refresh_plot()
        """keep_plot_alive
        
        Pauses program functionality until the plot is closed. Does so
        by refreshing the plot using :func:`refresh_plot`.
        """

    def pause(self, time=0.000001):
        """pause

        Calls `matplotlib's` `pause` function for an amount of seconds.

        Parameters
        ----------
        time : float
            The number of seconds the plot should have time to refresh itself
            and pause program functionality.
        """
        plt.pause(time)
Esempio n. 5
0
class Polygon:
    def __init__(self,imgs_raw,path,fnum):
        self.imgs_raw=imgs_raw
        self.path=path
        self.fnum=fnum
        self.data_fname=fname_format(path,fnum)
        fig=plt.figure(str(fnum))
        self.sfigs=[]
        self.sfigs+=[plt.subplot(1,2,1)]

        plt.imshow(imgs_raw[0])
        self.sfigs+=[plt.subplot(1,2,2)]
        plt.imshow(imgs_raw[1])
        self.verts_list=[None]*len(imgs_raw)
        self.lasssos = [ LassoSelector(ax, self.on_select, button=3 ) for ax in self.sfigs ]


        axsave = plt.axes([0.8, 0.05, 0.1, 0.075])
        bsave = Button(axsave, 'Save')
        bsave.on_clicked(self.save)

        axadd = plt.axes([0.7, 0.05, 0.1, 0.075])
        badd = Button(axadd, 'Add')
        badd.on_clicked(self.add)

        axdel = plt.axes([0.6, 0.05, 0.1, 0.075])
        bdel = Button(axdel, 'Del')
        bdel.on_clicked(self.delete)

        cid = fig.canvas.mpl_connect('button_press_event', self.onclick)

        axbox = plt.axes([0.1, 0.05, 0.45, 0.075])
        self.text_box = TextBox(axbox, '', initial='?')
        #text_box.on_submit(submit)

        try:
            self.object_list=pickle.load(open(self.data_fname,'rb'))
        except:
            print('no data file for fnum=',fnum)
            self.object_list=[]
        self.objects_hdls=None
        self.draw_objs()

        self.selected_obj_ind=-1

        plt.show()

    def on_select(self,verts):
        print('selecing in',self.last_ind_ax)
        verts.append(verts[0])
        #verts=Path(verts,closed=True).cleaned().vertices
        self.verts_list[self.last_ind_ax]=verts

    def draw_objs(self,selected=-1):
        if self.objects_hdls is not None:
            for h in self.objects_hdls:
                #print('----',h)
                h[0].remove()

        self.objects_hdls=[]

        h=self.objects_hdls

        for ind,obj in enumerate(self.object_list):
            for find,subp in enumerate(self.sfigs):
                data = obj['pts'][find]
                if data is not None:
                    xs,ys=np.array(data).T
                    h.append(subp.plot(xs,ys,'y'))
                    h.append(subp.plot(xs[0],ys[0],'or' if selected==ind else 'oy',alpha=0.5))

    def get_closest(self,x,y,ax_ind):
        max_ind=-1
        max_val=30 #minmal distance to accept click
        for ind,obj in enumerate(self.object_list):
            vrts= obj['pts'][ax_ind]
            if vrts is not None:
                d = abs(vrts[0][0]-x) + abs(vrts[0][1]-y)
                if d< max_val:
                    max_val=d
                    max_ind=ind
        return max_ind

    def delete(self,event):
        if self.selected_obj_ind != -1:
            self.object_list.pop(self.selected_obj_ind)
            self.selected_obj_ind=-1
            self.verts_list=[None]*len(self.verts_list)
            self.draw_objs()
            plt.draw()

    def save(self,event):
        with open(self.data_fname,'wb') as fd:
            pickle.dump(self.object_list,fd)



    def add(self,event):
        #import pdb;pdb.set_trace()
        if any(self.verts_list):
            obj = {}
            obj['pts'] = self.verts_list.copy()
            obj['desc'] = self.text_box.text
            self.object_list.append(obj)
            print('len of object_list',len(self.object_list))
            self.draw_objs()
            plt.draw()
            self.verts_list=[None]*len(self.verts_list)


    def onclick(self,event):
        #print('%s click: button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
        #          ('double' if event.dblclick else 'single', event.button,
        #                     event.x, event.y, event.xdata, event.ydata))
        ind=self.sfigs.index(event.inaxes) if event.inaxes in self.sfigs else -1
        print('inaxes',ind)
        x,y=event.xdata,event.ydata
        #self.sfigs[ind].plot(x,y,'or')
        if ind >= 0:
            self.last_ind_ax=ind
            cind=self.get_closest(x,y,ind)
            self.selected_obj_ind=cind
            if cind>-1:
                self.draw_objs(cind)
                self.text_box.set_val(self.object_list[cind]['desc'])
                plt.draw()
class TTFVisualizer:
    index = 0
    node_colors = []
    node_labels = {}
    node_positions = []
    interactions = []
    G = nx.MultiGraph()
    ax = []
    run_btn = {}
    next_trans_btn = {}
    next_btn = {}

    def __init__(self, ttfObject):
        self.index = 0
        self.ttfObject = ttfObject
        #set the graph
        self.G.add_nodes_from(range(0, self.ttfObject.numberOfAgents))
        self.node_positions = nx.spring_layout(self.G)

    def run_ttf(self):
        #turn on pyplot interactive mode

        fig, axes = plt.subplots(nrows=2,
                                 ncols=1,
                                 gridspec_kw={'height_ratios': [20, 1]})
        self.ax = axes.flatten()
        self.ax[1].set_axis_off()
        plt.tight_layout()
        #set the node colors
        self.set_node_colors()
        self.set_node_labels()
        nx.draw(self.G,
                ax=self.ax[0],
                with_labels=True,
                node_color=self.node_colors,
                pos=self.node_positions,
                labels=self.node_labels,
                linewidths=4,
                font_size=12,
                node_size=500,
                width=2)

        for i in range(self.ttfObject.numberOfAgents):
            for j in range(self.ttfObject.numberOfAgents):
                if (self.ttfObject.probabilityMatrix[i][j] != 0):
                    source, target = i, j
                    arrowprops = dict(
                        arrowstyle="<|-",
                        color="black",
                        shrinkA=15,
                        shrinkB=15,
                        patchA=None,
                        patchB=None,
                        connectionstyle="arc3,rad=0.1",
                    )
                    self.ax[0].annotate("",
                                        xy=self.node_positions[source],
                                        xytext=self.node_positions[target],
                                        arrowprops=arrowprops)

        #run button
        axcut = plt.axes([0.01, 0.002, 0.1, 0.075])
        self.run_btn = Button(axcut, 'Run')
        self.run_btn.on_clicked(self.run)

        #next button
        axcut = plt.axes([0.12, 0.002, 0.1, 0.075])
        self.next_btn = Button(axcut, 'Next')
        self.next_btn.on_clicked(self.next)

        # #next data transfer button
        # axcut = plt.axes([0.23, 0.002, 0.2, 0.075])
        # self.next_trans_btn = Button(axcut, 'Next Transfer')
        # self.next_trans_btn.on_clicked(self.run)

        #add text with time and energy consumed
        axcut = plt.axes([0.63, 0.002, 0.1, 0.075])
        self.text_box1 = TextBox(axcut, "Time: ")
        self.text_box1.set_val(str(self.index))
        axcut = plt.axes([0.83, 0.002, 0.1, 0.075])
        self.text_box2 = TextBox(axcut, "Energy: ")
        self.text_box2.set_val(str(self.ttfObject.numberOfDataTransitions))
        plt.show()

    def run(self, event):
        while self.ttfObject.is_termination_configuration() != True:
            self.ax[0].clear()
            self.interactions.append(self.ttfObject.next_interaction())
            print('Current interaction: ', self.interactions[self.index])
            print('Number of interactions: ', self.index + 1)

            #set the node colors
            self.set_node_colors()
            self.set_node_labels()
            self.set_sender_reciver_colors(self.index)
            self.set_interaction_edge_color(self.index)

            nx.draw(self.G,
                    ax=self.ax[0],
                    with_labels=True,
                    node_color=self.node_colors,
                    pos=self.node_positions,
                    labels=self.node_labels,
                    linewidths=4,
                    font_size=12,
                    node_size=500,
                    width=2)

            if not self.ttfObject.is_termination_configuration():
                plt.pause(0.2)
                self.text_box2.set_val(
                    str(self.ttfObject.numberOfDataTransitions))
                # #increase the interactions number
                self.index += 1

                self.text_box1.set_val(str(self.index))
                plt.show()
            else:
                print("Done")
                self.index += 1
                self.text_box1.set_val(str(self.index))
                self.text_box2.set_val(
                    str(self.ttfObject.numberOfDataTransitions))
                plt.show()
                f = open("test_ttf.txt", "a+")
                f.write("Time = " + str(self.index) + "      Energy = " +
                        str(self.ttfObject.numberOfDataTransitions) + '\n')
                f.close()
                plt.show(block=True)

    def next(self, event):
        if not self.ttfObject.is_termination_configuration():
            self.ax[0].clear()
            self.interactions.append(self.ttfObject.next_interaction())
            print('Current interaction: ', self.interactions[self.index])
            print('Number of interactions: ', self.index + 1)
            print('Number of transitions: ',
                  self.ttfObject.numberOfDataTransitions)

            #set the node colors
            self.set_node_colors()
            self.set_node_labels()
            self.set_sender_reciver_colors(self.index)
            self.set_interaction_edge_color(self.index)

            nx.draw(self.G,
                    ax=self.ax[0],
                    with_labels=True,
                    node_color=self.node_colors,
                    pos=self.node_positions,
                    labels=self.node_labels,
                    linewidths=4,
                    font_size=12,
                    node_size=500,
                    width=2)

            self.text_box2.set_val(str(self.ttfObject.numberOfDataTransitions))
            self.index += 1
            self.text_box1.set_val(str(self.index))
            plt.show()

    def set_node_colors(self):
        #set the node colors and positions
        self.node_colors = []
        self.node_colors = [
            'blue' for x in range(self.ttfObject.numberOfAgents)
        ]
        for i in range(len(self.ttfObject.tokenList)):
            if self.ttfObject.tokenList[i] == 0:
                self.node_colors[i] = 'gray'
        self.node_colors[0] = 'red'

    def set_sender_reciver_colors(self, interactionIndex):
        self.node_colors[self.interactions[interactionIndex][0][1]] = 'yellow'
        self.node_colors[self.interactions[interactionIndex][0][0]] = 'orange'
        if self.ttfObject.is_termination_configuration():
            self.node_colors[0] = 'green'

    def set_node_labels(self):
        #set the node lables
        k = 0
        self.node_labels = {}
        for el in self.ttfObject.tokenList:
            self.node_labels[k] = chr(ord('a') + k) + '(' + str(el) + ')'
            k += 1

    def set_interaction_edge_color(self, interactionIndex):
        for i in range(self.ttfObject.numberOfAgents):
            for j in range(self.ttfObject.numberOfAgents):
                if (self.ttfObject.probabilityMatrix[i][j] != 0):
                    source, target = i, j
                    color = 'black'
                    if source == self.interactions[
                            self.index][0][1] and target == self.interactions[
                                self.index][0][0]:
                        if self.interactions[self.index][1]:
                            color = 'green'
                        else:
                            color = 'red'
                    arrowprops = dict(
                        arrowstyle="<|-",
                        color=color,
                        shrinkA=15,
                        shrinkB=15,
                        patchA=None,
                        patchB=None,
                        connectionstyle="arc3,rad=0.1",
                    )
                    self.ax[0].annotate('',
                                        xy=self.node_positions[source],
                                        xytext=self.node_positions[target],
                                        arrowprops=arrowprops)
Esempio n. 7
0
def _multi_fig(fig, num_cams, gain_min, gain_max, gain_default, exposure_min,
               exposure_max, exposure_default, fps_min, fps_max, fps_default):
    """ Creates multi cam GUI figure """

    # Position params
    padding = 0.01
    row_height = 0.02
    num_top_rows = 1
    num_bottom_rows = 4
    num_cams_width = (1 - 3 * padding) / 2
    cam_plot_height_offset = num_bottom_rows * row_height + num_bottom_rows * padding
    cam_plot_width = (1 - (num_cams + 1) * padding) / num_cams + 2 * padding
    cam_plot_height = 1 - cam_plot_height_offset - (num_top_rows * row_height +
                                                    num_top_rows * padding)
    name_format_width = (1 - 3 * padding) / 2
    save_width = (0.5 - (num_cams + 1.5) * padding) / (num_cams + 1)
    num_images_width = (((1 - 3 * padding) / 2) - 3 * padding) / 8
    delay_width = (((1 - 3 * padding) / 2) - 3 * padding) / 8
    num_bursts_width = (((1 - 3 * padding) / 2) - 3 * padding) / 8
    counter_width = (((1 - 3 * padding) / 2) - 3 * padding) / 8

    # num cams button
    num_cams_button_pos = [
        padding, 1 - row_height - padding, num_cams_width, row_height
    ]
    num_cams_button_axes = fig.add_axes(num_cams_button_pos)
    num_cams_button = Button(num_cams_button_axes, 'Set # Cams')
    num_cams_button.label.set_fontsize(7)

    # num cams text
    num_cams_text_pos = [
        num_cams_button_pos[0] + num_cams_button_pos[2] + padding,
        num_cams_button_pos[1], num_cams_width, row_height
    ]
    num_cams_text_axes = fig.add_axes(num_cams_text_pos)
    num_cams_text = TextBox(num_cams_text_axes, '')
    num_cams_text.set_val(str(num_cams))

    # cam plots
    cam_plot_dicts = []
    for i in range(num_cams):
        # Set camera string; note that first camera is considered "primary"
        cam_str = 'Cam ' + str(i + 1)
        if i == 0:
            cam_str = cam_str + " (primary)"
        else:
            cam_str = cam_str + " (secondary)"

        cam_plot_pos = [
            i * (cam_plot_width - padding), cam_plot_height_offset,
            cam_plot_width, cam_plot_height
        ]
        cam_plot_dict = _cam_plot(fig, cam_plot_pos, cam_str, row_height,
                                  gain_min, gain_max, gain_default, padding)
        # Append
        cam_plot_dicts.append(cam_plot_dict)

    # exposure slider
    exposure_pos = [0, cam_plot_height_offset - row_height, 1, row_height]
    exposure_slider, exposure_text = _slider_with_text(
        fig, exposure_pos, 'Exposure', exposure_min, exposure_max,
        exposure_default, padding)

    # FPS slider
    fps_pos = [
        exposure_pos[0], exposure_pos[1] - row_height - padding, 1, row_height
    ]
    fps_slider, fps_text = _slider_with_text(fig, fps_pos, 'FPS', fps_min,
                                             fps_max, fps_default, padding)

    # name format
    name_format_pos = [
        name_format_width + 2 * padding, fps_pos[1] - row_height - padding,
        name_format_width, row_height
    ]
    name_format_axes = fig.add_axes(name_format_pos)
    name_format_text = TextBox(name_format_axes, 'Name format')
    name_format_text.label.set_fontsize(7)
    name_format_text.set_val('{serial}_{datetime}_{cam}_{frameid}_{counter}')

    # save cam buttons
    save_cam_buttons = []
    for i in range(num_cams):
        # save button
        save_cam_button_pos = [
            i * save_width + (i + 1) * padding, padding, save_width, row_height
        ]
        save_cam_button_axes = fig.add_axes(save_cam_button_pos)
        save_cam_button = Button(save_cam_button_axes,
                                 'Save Cam "' + str(i + 1) + '"')
        save_cam_button.label.set_fontsize(7)
        # Append
        save_cam_buttons.append(save_cam_button)

    # multi save button
    save_multi_button_pos = [
        num_cams * save_width + (num_cams + 1) * padding, padding, save_width,
        row_height
    ]
    save_multi_button_axes = fig.add_axes(save_multi_button_pos)
    save_multi_button = Button(save_multi_button_axes, 'Save Multi')
    save_multi_button.label.set_fontsize(7)

    # num images text
    num_images_text_pos = [
        save_multi_button_pos[0] + save_multi_button_pos[2] +
        num_images_width + padding, save_multi_button_pos[1], num_images_width,
        row_height
    ]
    num_images_text_axes = fig.add_axes(num_images_text_pos)
    num_images_text = TextBox(num_images_text_axes, '# Images')
    num_images_text.label.set_fontsize(7)
    num_images_text.set_val(1)

    # delay
    delay_pos = [
        num_images_text_pos[0] + num_images_text_pos[2] + delay_width +
        padding, num_images_text_pos[1], delay_width, row_height
    ]
    delay_axes = fig.add_axes(delay_pos)
    delay_text = TextBox(delay_axes, 'Delay')
    delay_text.label.set_fontsize(7)
    delay_text.set_val(1)

    # num burst
    num_bursts_pos = [
        delay_pos[0] + delay_pos[2] + num_bursts_width + padding, delay_pos[1],
        num_bursts_width, row_height
    ]
    num_bursts_axes = fig.add_axes(num_bursts_pos)
    num_bursts_text = TextBox(num_bursts_axes, '# Burst')
    num_bursts_text.label.set_fontsize(7)
    num_bursts_text.set_val(1)

    # counter
    counter_pos = [
        num_bursts_pos[0] + num_bursts_pos[2] + counter_width + padding,
        num_bursts_pos[1], counter_width, row_height
    ]
    counter_axes = fig.add_axes(counter_pos)
    counter_text = TextBox(counter_axes, 'Counter')
    counter_text.label.set_fontsize(7)
    counter_text.set_val(1)

    return {
        'num_cams_button': num_cams_button,
        'num_cams_text': num_cams_text,
        'cam_plot_dicts': cam_plot_dicts,
        'exposure_slider': exposure_slider,
        'exposure_text': exposure_text,
        'fps_slider': fps_slider,
        'fps_text': fps_text,
        'name_format_text': name_format_text,
        'save_cam_buttons': save_cam_buttons,
        'save_multi_button': save_multi_button,
        'num_images_text': num_images_text,
        'delay_text': delay_text,
        'num_bursts_text': num_bursts_text,
        'counter_text': counter_text
    }
Esempio n. 8
0
class PointBrowser(object):
    """
    See "Event Handling" example from matplotlib documentation:
    https://matplotlib.org/examples/event_handling/data_browser.html

    Click on a point to select and highlight it -- the data that
    generated the point will be shown in the lower axes.  Use the 'a'
    and 's' keys to browse through the next and previous points along x-axis (ordered by RdTools estimate).
    """

    def __init__(self, data, xlim=None, ylim=None, prcntl=95):
        logging.info('NEW SESSION')
        warnings.filterwarnings("ignore")
        self.scsf_cache_dir = './local_cache/'
        if not os.path.exists(self.scsf_cache_dir):
            os.makedirs(self.scsf_cache_dir)

        ordering = np.argsort(data['rd']).values
        self.data = data.iloc[ordering]
        self.xs = self.data['rd'].values
        self.ys = self.data['deg'].values

        gs = GridSpec(4, 3)
        fig = plt.figure('DataViewer', figsize=(8, 16))
        ax = [plt.subplot(gs[0, :2])]  # Main scatter plot
        with sns.axes_style('white'):
            ax.append(plt.subplot(gs[0, -1]))  # Record viewing panel
            ax[-1].set_axis_off()
            ax.append(plt.subplot(gs[1, :]))  # Timeseries heatmap view
            ax.append(plt.subplot(gs[2, :]))  # ClearSky heatmap view
        ax.append(plt.subplot(gs[3, :]))  # Daily Energy view
        self.fig = fig
        self.ax = ax

        self.ax[0].set_title('click on point to view record')
        self.ax[0].set_xlabel('RdTools Estimate YoY deg (%)')
        self.ax[0].set_ylabel('SCSF Estimate YoY deg (%)')
        self.ax[2].set_title('Measured power')
        self.ax[2].set_xlabel('Day number')
        self.ax[2].set_yticks([])
        self.ax[2].set_ylabel('(sunset)        Time of day        (sunrise)')

        self.line, = self.ax[0].plot(self.xs, self.ys, '.', picker=5)  # 5 points tolerance
        m = np.logical_and(
            np.logical_and(
                self.data['res-median'] < np.percentile(self.data['res-median'], prcntl),
                self.data['res-var'] < np.percentile(self.data['res-var'], prcntl)
            ),
            self.data['res-L0norm'] < np.percentile(self.data['res-L0norm'], prcntl)
        )
        m = np.logical_not(m.values)
        self.ax[0].plot(self.xs[m], self.ys[m], '.')
        if xlim is None:
            xlim = self.ax[0].get_xlim()
        if ylim is None:
            ylim = self.ax[0].get_ylim()
        pts = (
            min(xlim[0], ylim[0]),
            max(xlim[1], ylim[1])
        )
        self.ax[0].plot(pts, pts, ls='--', color='red')
        self.ax[0].set_xlim(xlim)
        self.ax[0].set_ylim(ylim)
        self.text = self.ax[0].text(0.05, 0.95, 'system ID: none',
                                    transform=self.ax[0].transAxes, va='top')
        self.selected, = self.ax[0].plot([self.xs[0]], [self.ys[0]], 'o', ms=6, alpha=0.4,
                                         color='yellow', visible=False)

        with sns.axes_style('white'):
            ax.append(plt.axes([.77, .5 * (1 + .57), .2, .05 / 2]))  # Text box entry
            ax.append(plt.axes([.82, .5 * (1 + .5), .1, .05 / 2]))  # run SCSF button
        self.text_box = TextBox(self.ax[-2], 'ID Number')
        self.button = Button(self.ax[-1], 'run SCSF', color='red')
        self.lastind = None
        self.D = None
        self.ics = None
        self.cb = None
        self.cb2 = None
        self.local_cash = {}
        self.prcntl = prcntl
        plt.tight_layout()

        self.fig.canvas.mpl_connect('pick_event', self.onpick)
        self.fig.canvas.mpl_connect('key_press_event', self.onpress)
        self.text_box.on_submit(self.submit)
        self.button.on_clicked(self.clicked)

        plt.show()

    def submit(self, text):
        logging.info('submit: ' + str(text))
        asrt = np.argsort(np.abs(self.data.index - float(text)))
        sysid = self.data.index[asrt[0]]
        bool_list = self.data.index == sysid
        # bool_list = self.data.index == int(text)
        index_lookup = np.arange(self.data.shape[0])
        self.lastind = int(index_lookup[bool_list])
        logging.info('selected index: ' + str(self.lastind))
        self.update()

    def clicked(self, event):
        if self.lastind is None:
            logging.info('button click: nothing selected!')
            return
        sysid = self.data.iloc[self.lastind].name
        logging.info('button click: current ID: {}'.format(sysid))

        self.ax[3].cla()
        self.ax[3].text(0.05, 0.95, 'initializing algorithm...', transform=self.ax[3].transAxes,
                        va='top', fontname='monospace')
        self.ax[3].set_xlabel('Day number')
        self.ax[3].set_yticks([])
        self.ax[3].set_ylabel('(sunset)        Time of day        (sunrise)')
        plt.tight_layout()
        self.fig.canvas.draw()

        self.ax[4].cla()

        D = self.D
        cached_files = os.listdir(self.scsf_cache_dir)
        fn = 'pvo_' + str(sysid) + '.scsf'
        if fn in cached_files:
            ics = IterativeClearSky()
            ics.load_instance(self.scsf_cache_dir + fn)
            self.ics = ics
            self.ax[4].plot(np.sum(ics.D, axis=0) * 24 / ics.D.shape[0], linewidth=1, label='raw data')
            use_day = ics.weights > 1e-1
            days = np.arange(ics.D.shape[1])
            self.ax[4].scatter(days[use_day], np.sum(ics.D, axis=0)[use_day] * 24 / ics.D.shape[0],
                               color='orange', alpha=0.7, label='days selected')
            self.ax[4].legend()
            self.ax[4].set_title('Daily Energy')
            self.ax[4].set_xlabel('Day Number')
            self.ax[4].set_ylabel('kWh')
            self.ax[3].cla()
            self.ax[3].text(0.05, 0.95, 'loading cached results...', transform=self.ax[3].transAxes,
                            va='top', fontname='monospace')
            self.ax[3].set_xlabel('Day number')
            self.ax[3].set_yticks([])
            self.ax[3].set_ylabel('(sunset)        Time of day        (sunrise)')
            self.show_ticks(self.ax[2])
            plt.tight_layout()
            self.fig.canvas.draw()
        else:
            ics = IterativeClearSky(D)
            self.ics = ics
            self.ax[4].plot(np.sum(ics.D, axis=0) * 24 / ics.D.shape[0], linewidth=1, label='raw data')
            use_day = ics.weights > 1e-1
            days = np.arange(ics.D.shape[1])
            self.ax[4].scatter(days[use_day], np.sum(ics.D, axis=0)[use_day] * 24 / ics.D.shape[0],
                               color='orange', alpha=0.7, label='days selected')
            self.ax[4].legend()
            self.ax[4].set_title('Daily Energy')
            self.ax[4].set_xlabel('Day Number')
            self.ax[4].set_ylabel('kWh')
            self.ax[3].cla()
            self.ax[3].text(0.05, 0.95, 'running algorithm...', transform=self.ax[3].transAxes,
                            va='top', fontname='monospace')
            self.ax[3].set_xlabel('Day number')
            self.ax[3].set_yticks([])
            self.ax[3].set_ylabel('(sunset)        Time of day        (sunrise)')
            self.show_ticks(self.ax[2])
            plt.tight_layout()
            self.fig.canvas.draw()
            logging.info('starting algorithm')
            config_l = CONFIG1.copy()
            config_l['max_iter'] = 1
            obj_vals = ics.calc_objective(False)
            old_obj = np.sum(obj_vals)
            ti = time.time()
            for cntr in range(CONFIG1['max_iter']):
                ics.minimize_objective(**config_l)
                logging.info('min iteration {} complete'.format(cntr + 1))
                obj_vals = ics.calc_objective(False)
                new_obj = np.sum(obj_vals)
                improvement = (old_obj - new_obj) * 1. / old_obj
    
                self.ax[3].cla()
                self.ax[3].set_xlabel('Day number')
                self.ax[3].set_yticks([])
                self.ax[3].set_ylabel('(sunset)        Time of day        (sunrise)')
                s1 = 'Iteration {} complete: obj = {:.2f}, f1 = {:.2f}'.format(cntr + 1, new_obj, obj_vals[0])
                s2 = 'Improvement: {:.2f}%'.format(100 * improvement)
                tf = time.time()
                s3 = 'Time elapsed: {:.2f} minutes'.format((tf - ti) / 60.)
                textout = '\n'.join([s1, s2, s3])
                logging.info(textout)
                self.ax[3].text(0.05, 0.95, textout, transform=self.ax[3].transAxes,
                                va='top', fontname='monospace')
                plt.tight_layout()
                self.fig.canvas.draw()
                old_obj = new_obj
                if improvement <= CONFIG1['eps']:
                    break
            ics.save_instance(self.scsf_cache_dir + fn)

        logging.info('algorithm complete')
        self.ax[4].plot((ics.R_cs.value[0] * np.sum(ics.L_cs.value[:, 0])) * 24 / ics.D.shape[0], linewidth=1,
                        label='clear sky estimate')
        self.ax[4].legend()
        logging.info('first plot complete')
        with sns.axes_style('white'):
            self.ax[3].cla()
            bar = self.ax[3].imshow(ics.L_cs.value.dot(ics.R_cs.value), cmap='hot',
                                    vmin=0, vmax=np.max(ics.D), interpolation='none',
                                    aspect='auto')
            if self.cb2 is not None:
                self.cb2.remove()
            self.cb2 = plt.colorbar(bar, ax=self.ax[3], label='kW')
        self.show_ticks(self.ax[3])
        self.ax[3].set_title('Estimated clear sky power')
        self.ax[3].set_xlabel('Day number')
        self.ax[3].set_yticks([])
        self.ax[3].set_ylabel('(sunset)        Time of day        (sunrise)')
        logging.info('second plot complete')
        plt.tight_layout()
        self.fig.canvas.draw()
        return

    def show_ticks(self, ax):
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()
        use_day = self.ics.weights > 1e-1
        days = np.arange(self.ics.D.shape[1])
        y1 = np.ones_like(days[use_day]) * self.D.shape[0] * .99
        ax.scatter(days[use_day], y1, marker='|', color='yellow', s=2)
        ax.scatter(days[use_day], .995 * y1, marker='|', color='yellow', s=2)
        ax.set_xlim(*xlim)
        ax.set_ylim(*ylim)
        return

    def onpress(self, event):
        if self.lastind is None:
            return

        logging.info('press event: ' + str(event.key))

        if event.key == 'a':
            inc = -1
            self.lastind += inc
            self.lastind = np.clip(self.lastind, 0, len(self.xs) - 1)
        elif event.key == 's':
            inc = 1
            self.lastind += inc
            self.lastind = np.clip(self.lastind, 0, len(self.xs) - 1)
        else:
            return

        self.update()

    def onpick(self, event):
        if event.artist != self.line:
            return True

        N = len(event.ind)
        if not N:
            return True

        # the click locations
        x = event.mouseevent.xdata
        y = event.mouseevent.ydata

        logging.info('pick: ' + str(x) + ', ' + str(y))

        distances = np.hypot(x - self.xs[event.ind], y - self.ys[event.ind])
        indmin = distances.argmin()
        dataind = event.ind[indmin]

        self.lastind = dataind
        self.update()

    def update(self):
        if self.lastind is None:
            return

        dataind = self.lastind
        prcntl = self.prcntl

        logging.info('updating, ID = {}'.format(self.data.iloc[dataind].name))

        self.selected.set_visible(True)
        self.selected.set_data(self.xs[dataind], self.ys[dataind])

        out1 = 'system ID: {:d}'.format(self.data.iloc[dataind].name)
        out2 = str(self.data.iloc[dataind])
        # self.text_box.set_val('')

        idxs = np.arange(len(self.data.columns))
        if self.data.iloc[dataind]['res-median'] > np.percentile(self.data['res-median'], prcntl):
            l1 = out2.split('\n')
            i = idxs[self.data.columns == 'res-median'][0]
            l1[i] = '*' + l1[i][:-2] + '*'
            out2 = '\n'.join(l1)
        if self.data.iloc[dataind]['res-var'] > np.percentile(self.data['res-var'], prcntl):
            l1 = out2.split('\n')
            i = idxs[self.data.columns == 'res-var'][0]
            l1[i] = '*' + l1[i][:-2] + '*'
            out2 = '\n'.join(l1)
        if self.data.iloc[dataind]['res-L0norm'] > np.percentile(self.data['res-L0norm'], prcntl):
            l1 = out2.split('\n')
            i = idxs[self.data.columns == 'res-L0norm'][0]
            l1[i] = '*' + l1[i][:-2] + '*'
            out2 = '\n'.join(l1)

        self.text.set_text(out1)
        self.ax[1].cla()
        self.ax[1].text(0.00, 0.95, out2, transform=self.ax[1].transAxes, va='top', fontname='monospace')
        self.ax[1].set_axis_off()
        self.ax[2].cla()
        self.ax[2].text(0.05, 0.95, 'data loading...', transform=self.ax[2].transAxes, va='top', fontname='monospace')
        self.ax[2].set_xlabel('Day number')
        self.ax[2].set_yticks([])
        self.ax[2].set_ylabel('(sunset)        Time of day        (sunrise)')
        self.ax[3].cla()
        self.ax[4].cla()
        self.ics = None
        plt.tight_layout()
        self.fig.canvas.draw()

        with sns.axes_style('white'):
            idnum = self.data.iloc[dataind].name
            if idnum in self.local_cash.keys():
                df = self.local_cash[idnum]
            else:
                df = load_sys(idnum=idnum, local=False)
                self.local_cash[idnum] = df
            days = df.resample('D').max().index[1:-1]
            start = days[0]
            end = days[-1]
            D = df.loc[start:end].iloc[:-1].values.reshape(288, -1, order='F')
            self.D = D
            self.ax[2].cla()
            foo = self.ax[2].imshow(D, cmap='hot', interpolation='none', aspect='auto')
            if self.cb is not None:
                self.cb.remove()
            self.cb = plt.colorbar(foo, ax=self.ax[2], label='kW')

        self.ax[2].set_xlabel('Day number')
        self.ax[2].set_yticks([])
        self.ax[2].set_ylabel('(sunset)        Time of day        (sunrise)')
        self.ax[2].set_title('Measured power')

        self.text_box.set_val('')
        self.fig.canvas.draw()
Esempio n. 9
0
class LoaderUI(object):
    def __init__(self):
        self.full_sensor_data = None
        self.selected_data = None
        self.spe_file = None
        self.selector = None
        self.pol_angle = None
        self.success = False

        dir = os.path.dirname(__file__)
        filename = os.path.join(dir, 'style', 'custom-wa.mplstyle')
        plt.style.use(filename)

        fig = plt.figure()
        fig.set_size_inches(20, 12, forward=True)
        fig.canvas.set_window_title('Load Data')

        grid_shape = (16, 28)
        # Make open, load, draw buttons
        self.full_sensor_ax = plt.subplot2grid(grid_shape, (0, 0),
                                               colspan=13,
                                               rowspan=13)
        self.selected_ax = plt.subplot2grid(grid_shape, (0, 15),
                                            colspan=13,
                                            rowspan=4)
        axopen = plt.subplot2grid(grid_shape, (14, 4), colspan=4)
        axload = plt.subplot2grid(grid_shape, (14, 20), colspan=4)
        axfull_lambda = plt.subplot2grid(grid_shape, (11, 16), colspan=4)
        axpix_min = plt.subplot2grid(grid_shape, (7, 16), colspan=4)
        axpix_max = plt.subplot2grid(grid_shape, (7, 23), colspan=4)
        axrefresh = plt.subplot2grid(grid_shape, (11, 23), colspan=4)
        axpol_angle = plt.subplot2grid(grid_shape, (9, 23), colspan=4)

        bload = Button(axload, 'Load Selected', color='0.25', hovercolor='0.3')
        bload.on_clicked(self._load_callback)
        bopen = Button(axopen, 'Open File', color='0.25', hovercolor='0.3')
        bopen.on_clicked(self._open_callback)

        self.chk_full_lambda = CheckButtons(axfull_lambda, ['Full Lambda'],
                                            [True])
        self.chk_full_lambda.on_clicked(self._full_lambda_callback)

        self.ypix_min = TextBox(axpix_min,
                                'Sel. Lower \nbound ',
                                '0',
                                color='0.25',
                                hovercolor='0.3')

        self.ypix_max = TextBox(axpix_max,
                                'Sel. Upper \nbound ',
                                '0',
                                color='0.25',
                                hovercolor='0.3')

        self.refresh_selection = Button(axrefresh,
                                        'Refresh Selection',
                                        color='0.25',
                                        hovercolor='0.3')
        self.refresh_selection.on_clicked(self._refresh_selection_callback)

        self.txt_pol_angle = TextBox(axpol_angle,
                                     'Pol. Angle \n (deg) ',
                                     '0',
                                     color='0.25',
                                     hovercolor='0.3')

        self._full_lambda_callback(None)

        plt.show(block=True)

    def _rect_select_callback(self, eclick, erelease):
        x1, y1 = eclick.xdata, eclick.ydata
        x2, y2 = erelease.xdata, erelease.ydata

    def _span_select_callback(self, ymin, ymax):
        ymin = int(np.floor(ymin))
        ymax = int(np.ceil(ymax))
        self.selected_data = self.full_sensor_data[ymin:ymax + 1, :]
        self.ypix_min.set_val(str(ymin))
        self.ypix_max.set_val(str(ymax))
        self._image_selected_data(ymin, ymax)

    def _load_callback(self, event):
        if self.spe_file is not None and self.selected_data is not None:
            self.pol_angle = float(self.txt_pol_angle.text)
            self.success = True
            plt.close()
            mpl.rcParams.update(mpl.rcParamsDefault)
        else:
            print(
                'Invalid loader state: must have loaded file and selected data'
            )

    def _open_callback(self, event):
        # calls general observation load function
        root = tk.Tk()
        root.withdraw()
        filename = filedialog.askopenfilename()
        if filename is not '':
            self.spe_file = spe_loader.load_from_files([filename])
            self.full_sensor_data = self.spe_file.data[0][0]
            self._image_full_sensor_data()
        else:
            return

    def _full_lambda_callback(self, event):
        if self.selector is not None:
            self.selector.set_visible(False)
        chk_status = self.chk_full_lambda.get_status()
        if chk_status[0]:
            self.selector = SpanSelector(self.full_sensor_ax,
                                         self._span_select_callback,
                                         direction='vertical',
                                         minspan=5,
                                         useblit=True,
                                         span_stays=False,
                                         rectprops=dict(facecolor='red',
                                                        alpha=0.2))
        else:
            self.selector = RectangleSelector(
                self.full_sensor_ax,
                self._rect_select_callback,
                drawtype='box',
                useblit=True,
                button=[1, 3],  # don't use middle button
                minspanx=1,
                minspany=0.1,
                spancoords='data',
                interactive=True)

    def _refresh_selection_callback(self, event):
        ymin = int(self.ypix_min.text)
        ymax = int(self.ypix_max.text)
        self._span_select_callback(ymin, ymax)

    def _image_full_sensor_data(self):
        self.full_sensor_ax.clear()
        self._full_lambda_callback(None)
        self.full_sensor_ax.imshow(self.full_sensor_data, aspect='auto')
        self.full_sensor_ax.set_title('Source Data')

    def _image_selected_data(self, ymin, ymax):
        self.selected_ax.clear()
        self.selected_ax.imshow(self.selected_data, aspect='auto')
        title = 'Selected: {0} rows ({1} -> {2})\n' \
                '{3} wavelengths ({4:.3f} -> {5:.3f})'.format(self.selected_data.shape[0], ymin, ymax,
                                                     self.selected_data.shape[1], self.spe_file.wavelength[0],
                                                     self.spe_file.wavelength[-1])
        self.selected_ax.set_title(title)
def __spincam_gui():

    # Get figure
    fig = plt.figure(1)
    fig2 = plt.figure(2)

    # Set position params
    padding = 0.01
    options_height = 0.02
    num_options = 6
    cam_plot_height_offset = num_options * options_height + num_options * padding
    cam_plot_width = 0.75
    cam_plot_height = 1 - cam_plot_height_offset

    # cid = fig.canvas.mpl_connect('button_press_event', onclick)

    # Display Camera Image
    display_pos = [0, cam_plot_height_offset, cam_plot_width, cam_plot_height]
    display_dict = __cam_plot(fig, display_pos, 'Camera', options_height,
                              padding)
    # Set initial values
    # Set callbacks
    display_dict['find_and_init_button'].on_clicked(__test)
    ''' 
    # Start stream
    start_stream_button_pos = [padding,
                               display_pos[1] - options_height,
                               0.5 - 2 * padding,
                               options_height]
    start_stream_button_axes = fig.add_axes(start_stream_button_pos)
    start_stream_button = Button(start_stream_button_axes, 'Start Stream')
    start_stream_button.label.set_fontsize(7)

    # Set callback
    start_stream_button.on_clicked(__start_stream)

    # Stop stream
    stop_stream_button_pos = [start_stream_button_pos[0] + start_stream_button_pos[2] + 2 * padding,
                              display_pos[1] - options_height,
                              0.5 - 2 * padding,
                              options_height]
    stop_stream_button_axes = fig.add_axes(stop_stream_button_pos)
    stop_stream_button = Button(stop_stream_button_axes, 'Stop Stream')
    stop_stream_button.label.set_fontsize(7)

    # Set callback
    stop_stream_button.on_clicked(__stop_stream)
    '''
    start_stream_button_pos = [
        padding, display_pos[1] - options_height, 0.5 - 2 * padding,
        options_height
    ]
    start_stream_button_axes = fig.add_axes(start_stream_button_pos)
    start_stream_button = Button(start_stream_button_axes, 'Open Preview')
    start_stream_button.label.set_fontsize(7)

    # Set callback
    start_stream_button.on_clicked(__open_preview)

    # Stop stream
    stop_stream_button_pos = [
        start_stream_button_pos[0] + start_stream_button_pos[2] + 2 * padding,
        display_pos[1] - options_height, 0.5 - 2 * padding, options_height
    ]
    stop_stream_button_axes = fig.add_axes(stop_stream_button_pos)
    stop_stream_button = Button(stop_stream_button_axes, 'Plot Histogram')
    stop_stream_button.label.set_fontsize(7)

    # Set callback
    stop_stream_button.on_clicked(__plot_hist)

    # fps
    fps_pos = [
        0, start_stream_button_pos[1] - options_height - padding, 1,
        options_height
    ]
    (fps_slider, fps_text) = __slider_with_text(fig, fps_pos, 'FPS', __FPS_MIN,
                                                __FPS_MAX, __FPS_MIN, padding)
    # Set callbacks
    fps_slider.on_changed(__fps_slider)
    fps_text.on_submit(__fps_text)

    # Exposure
    exposure_pos = [
        0, fps_pos[1] - options_height - padding, 1, options_height
    ]
    (exposure_slider,
     exposure_text) = __slider_with_text(fig, exposure_pos, 'Exposure',
                                         __EXPOSURE_MIN, __EXPOSURE_MAX,
                                         __EXPOSURE_MIN, padding)
    # Set callbacks
    exposure_slider.on_changed(__exposure_slider)
    exposure_text.on_submit(__exposure_text)

    # Set default directory to current
    directory_pos = [0.13, exposure_pos[1], 0.66, options_height]
    directory_axes = fig2.add_axes(directory_pos)
    directory_text = TextBox(directory_axes, 'Directory')
    directory_text.label.set_fontsize(7)
    directory_text.set_val('')

    directory_button_pos = [
        directory_pos[0] + directory_pos[2] + padding, directory_pos[1], 0.16,
        options_height
    ]
    directory_button_axes = fig2.add_axes(directory_button_pos)
    directory_button = Button(directory_button_axes, 'Choose Directory')
    directory_button.label.set_fontsize(7)

    directory_button.on_clicked(__choose_directory)

    # Set name format
    name_format_pos = [
        directory_pos[0], directory_pos[1] - options_height - padding, 0.5,
        options_height
    ]
    name_format_axes = fig2.add_axes(name_format_pos)
    name_format_text = TextBox(name_format_axes, 'Name format')
    name_format_text.label.set_fontsize(7)
    name_format_text.set_val('test_{date}')

    # Set save primary button
    save_button_pos = [
        directory_pos[1], name_format_pos[1] - options_height - padding, 0.2,
        options_height
    ]
    save_button_axes = fig2.add_axes(save_button_pos)
    save_button = Button(save_button_axes, 'Start Acquisition(no z-scan)')
    save_button.label.set_fontsize(7)
    # Set callback
    save_button.on_clicked(__acquire_no_z)

    # Set num images text
    num_images_text_pos = [
        cam_plot_width - 20 * padding, padding, 0.1 - 2 * padding,
        options_height
    ]
    #save_button.on_clicked(__save_fourcolor)

    # Set num images text
    avg_images_text_pos = [
        save_button_pos[0] + save_button_pos[2] + padding +
        (0.5 - 2 * padding) * 0.1875 + 2 * padding,
        name_format_pos[1] - options_height - padding,
        (0.2 - 2 * padding) * 0.8125 - padding, options_height
    ]
    avg_images_text_axes = fig2.add_axes(avg_images_text_pos)
    avg_images_text = TextBox(avg_images_text_axes, '# to Avg')
    avg_images_text.label.set_fontsize(7)
    avg_images_text.set_val(10)

    # Set counter
    counter_pos = [
        name_format_pos[0] + name_format_pos[2] + 10 * padding,
        directory_pos[1] - options_height - padding, 0.2, options_height
    ]
    counter_axes = fig2.add_axes(counter_pos)
    counter_text = TextBox(counter_axes, 'Counter')
    counter_text.label.set_fontsize(7)
    counter_text.set_val(1)

    # Set num images text
    num_images_text_pos = [
        avg_images_text_pos[0] + avg_images_text_pos[2] + 12 * padding,
        name_format_pos[1] - options_height - padding, 0.1 - 2 * padding,
        options_height
    ]
    num_images_text_axes = fig2.add_axes(num_images_text_pos)
    num_images_text = TextBox(num_images_text_axes, '# to Acquire')
    num_images_text.label.set_fontsize(7)
    num_images_text.set_val(1)

    stage_dict = __stage_gui(fig2)

    return {
        'fig': fig,
        'display_dict': display_dict,
        'stage_dict': stage_dict,
        'start_stream_button': start_stream_button,
        'stop_stream_button': stop_stream_button,
        'save_button': save_button,
        'name_format_text': name_format_text,
        'counter_text': counter_text,
        'num_images_text': num_images_text,
        'avg_images_text': avg_images_text,
        'fps_slider': fps_slider,
        'fps_text': fps_text,
        'exposure_slider': exposure_slider,
        'exposure_text': exposure_text,
        'directory_text': directory_text,
        'directory_button': directory_button
    }
Esempio n. 11
0
class ViewImageStack(object):  # interactive image viewer for a stack of images
    def __init__(self, chunk_size_current, img_data, trainid_data,
                 pulseid_data, cellid_data, is_good_data, view_cmap, view_clip,
                 view_figsz, dir_save):

        self.fg = plt.figure(figsize=view_figsz)
        self.cmap = view_cmap
        self.clmin = view_clip[0]
        self.clmax = view_clip[1]
        self.dirsave = dir_save

        self.imtot = chunk_size_current  # total number of images in the file
        self.X = img_data
        self.trainid_data = trainid_data
        self.pulseid_data = pulseid_data
        self.cellid_data = cellid_data
        self.imtype = is_good_data
        self.ind = 0  #initial image to show, e.g, 0 or self.imtot//2

        self.mindef = self.clmin  # default values used for error handling
        self.maxdef = self.clmax
        clrinact = 'lightgray'  # 'papayawhip' 'lightgray'
        clrhover = 'darkgray'  # 'salmon' 'darkgray'

        # axes for all visual components
        self.ax = self.fg.add_subplot(111)
        self.cbax = self.fg.add_axes(
            [0.85, 0.1, 0.03,
             0.77])  # for colorbar [left, bottom, width, height]
        self.resax = self.fg.add_axes([0.05, 0.83, 0.1,
                                       0.05])  # for 'Reset' button
        self.rax = self.fg.add_axes([0.05, 0.72, 0.1, 0.1],
                                    facecolor=clrinact)  # for radiobuttons
        self.minax = self.fg.add_axes([0.04, 0.65, 0.12, 0.05
                                       ])  # min and max values for datarange
        self.maxax = self.fg.add_axes([0.04, 0.59, 0.12, 0.05])
        self.imnax = self.fg.add_axes([0.07, 0.23, 0.1, 0.04],
                                      facecolor=clrinact)  # chose image number
        self.savebut = self.fg.add_axes([0.05, 0.30, 0.1,
                                         0.05])  # for 'Save image' button
        self.exitax = self.fg.add_axes([0.05, 0.93, 0.1,
                                        0.05])  # for 'Exit' button

        # visual components
        self.im = self.ax.imshow(self.X[self.ind, :, :],
                                 cmap=self.cmap,
                                 clim=(self.clmin, self.clmax))
        self.cls = plt.colorbar(self.im, cax=self.cbax)
        self.averbtn = Button(self.savebut, 'Save png', color=clrinact)
        self.resbt = Button(self.resax, 'Reset view', color=clrinact)
        self.exitbt = Button(self.exitax, 'Exit', color=clrinact)
        self.tbmin = TextBox(self.minax,
                             'min:',
                             initial=str(self.clmin),
                             color=clrinact)
        self.tbmax = TextBox(self.maxax,
                             'max:',
                             initial=str(self.clmax),
                             color=clrinact)
        self.rb = RadioButtons(self.rax, ('lin', 'log'),
                               active=0,
                               activecolor='red')
        self.imnum = TextBox(self.imnax,
                             'jump to \n image #',
                             initial=str(self.ind + 1),
                             color=clrinact)

        strID = "Image information:\nTrainID: " + str(
            self.trainid_data[self.ind]) + "\nPulseID: " + str(
                self.pulseid_data[self.ind]) + "\nCellID: " + str(
                    self.cellid_data[self.ind]) + "\nImage type: " + str(
                        self.imtype[self.ind])
        self.textID = self.fg.text(0.03, 0.085, strID)

        self.fg.canvas.mpl_connect('scroll_event', self.on_scroll)
        self.fg.canvas.mpl_connect('button_press_event', self.on_press)
        self.fg.canvas.mpl_connect('key_press_event', self.on_keypress)

        self.update()
        plt.show(block=True)

    def on_press(self, event):

        if event.inaxes == self.rax.axes:
            self.update()

        if event.inaxes == self.resax.axes:  # 'reset view' button  : default datarange, linear scale, first image
            self.clmin = self.mindef
            self.clmax = self.maxdef
            self.tbmin.set_val(self.clmin)
            self.tbmax.set_val(self.clmax)
            self.rb.set_active(0)
            self.ind = 0
            print('updated data range is [%s , %s ]' %
                  (self.clmin, self.clmax))
            self.update()

        if event.inaxes == self.exitax:
            sys.exit(0)  # exit program

        if event.inaxes == self.savebut.axes:  # 'save image' button

            items = [
                self.ax, self.cbax,
                self.cbax.get_yaxis().get_label(),
                self.ax.get_xaxis().get_label(),
                self.ax.get_yaxis().get_label()
            ]
            bbox = Bbox.union([item.get_window_extent() for item in items])
            extent = bbox.transformed(self.fg.dpi_scale_trans.inverted())
            strim = 'img_trID_{:d}_plID_{:d}_ceID_{:d}_type_{:d}.png'.format(
                self.trainid_data[self.ind], self.pulseid_data[self.ind],
                self.cellid_data[self.ind], self.imtype[self.ind])
            self.fg.savefig(self.dirsave + strim, bbox_inches=extent)

    def on_keypress(self, event):

        #if (event.inaxes == self.minax.axes) | (event.inaxes == self.maxax.axes):
        if event.key == 'enter':  #one may face bad script behaviour here if some specific keyboard button like 'tab' has been pressed
            try:
                self.clmin = float(self.tbmin.text)
                self.clmax = float(self.tbmax.text)
                #print('updated data range is [%s , %s ]' %(self.clmin, self.clmax))
            except:
                print('inappropriate values for data range specified')
                self.tbmin.set_val(self.clmin)
                self.tbmax.set_val(self.clmax)
            self.update()

        if (event.inaxes == self.imnax):
            if event.key == 'enter':  #one may face bad script behaviour here if some specific keyboard button like 'tab' has been pressed
                try:
                    val = int(self.imnum.text)
                    if (val >= 1) & (val <= self.imtot):
                        self.ind = val - 1
                    else:
                        print('inappropriate image number specified')
                        self.imnum.set_val(str(self.ind + 1))
                except:
                    print('inappropriate image number specified')
                    self.imnum.set_val(str(self.ind + 1))
                self.update()

    def on_scroll(self, event):

        if event.button == 'up':
            self.ind = (self.ind + 1) % self.imtot
        else:
            self.ind = (self.ind - 1) % self.imtot
        self.update()

    def update(self):

        self.ax.set_title(
            'image # %s out of %s \n (use scroll wheel to navigate through images)'
            % (self.ind + 1, self.imtot))

        # choose linear or log scale
        if self.rb.value_selected == 'lin':
            self.im.set_data(self.X[self.ind, :, :])
        else:
            with np.errstate(divide='ignore', invalid='ignore'):
                self.im.set_data(np.log10(self.X[self.ind, :, :]))
                #self.im.set_clim(np.log10(self.clmin), np.log10(self.clmax))  #adjust scaling
        # update display representation
        self.im.set_clim(self.clmin, self.clmax)

        strID = "Image information:\nTrainID: " + str(
            self.trainid_data[self.ind]) + "\nPulseID: " + str(
                self.pulseid_data[self.ind]) + "\nCellID: " + str(
                    self.cellid_data[self.ind]) + "\nImage type: " + str(
                        self.imtype[self.ind])
        self.textID.set_text(strID)

        self.cls.draw_all()
        self.im.axes.figure.canvas.draw()

    def __del__(self):

        self.fg.canvas.mpl_disconnect(self.on_scroll)
        self.fg.canvas.mpl_disconnect(self.on_press)
        self.fg.canvas.mpl_disconnect(self.on_keypress)
Esempio n. 12
0
class MultiRoi:
    def __init__(self, img=None, roi_types=(),
                 color_cycle=('b', 'g', 'r', 'c', 'm', 'y', 'k'),
                 finish_callback=None):

        self.color_cycle = color_cycle
        self.mask_fig = plt.figure(figsize=(5, 3))
        self.mask_fig_idx = 1
        self.mask_axes = self.mask_fig.gca()
        self.mask_axes.set_title("Mask")
        self.mask_axes.set_axis_off()
        self.img_fig = plt.figure(figsize=(10, 6))
        self.img_fig_idx = 2
        self.img_axes = self.img_fig.gca()
        self.img_axes.set_axis_off()
        self.__image = None
        self.image = img
        # __mask is for visualization, mask is for labling
        self.__mask = None if img is None else np.zeros(img.shape)
        self.mask = None if img is None else np.zeros(img.shape[:2])
        self.rois = []
        self.roi_values = {}
        self.roi_value_colors = {}
        self.current_roi_value = None
        self.finish_callback = finish_callback
        self.textbox = None
        self.buttons = []
        for roi_name in roi_types:
            self.__add_roi_type(roi_name)
        self.make_widgets()
        self.update_plot()

    @property
    def image(self):
        return self.__image

    @image.setter
    def image(self, img):
        self.__image = img
        self.__mask = None if img is None else np.zeros(img.shape)
        self.mask = None if img is None else np.zeros(img.shape[:2],
                                                      dtype=np.uint8)
        if self.__image is not None:
            self.update_plt_mask()
            self.update_plt_img()
        self.rois = []  # empty rois

    @staticmethod
    def update_plot():
        if sys.flags.interactive:
            plt.show(block=False)
        else:
            plt.show(block=True)
        # plt.show(block=True)

    def make_widgets(self):
        self.textbox = TextBox(ax=plt.axes([0.2, 0.07, 0.1, 0.04]),
                               label="ROI Name: ", initial='[roi_name]')
        btn_finish = Button(plt.axes([0.8, 0.07, 0.1, 0.04]), 'Finish')
        btn_finish.on_clicked(self.finish)
        btn_clear = Button(plt.axes([0.7, 0.07, 0.1, 0.04]), 'Clear')
        btn_clear.on_clicked(self.clear_rois)
        btn_add = Button(plt.axes([0.6, 0.07, 0.1, 0.04]), 'New ROI')
        btn_add.on_clicked(self.new_roi)
        btn_new = Button(plt.axes([0.5, 0.07, 0.1, 0.04]), 'New ROI Type')
        btn_new.on_clicked(self.new_roi_type)
        self.buttons.extend([btn_new, btn_add, btn_clear, btn_finish])
        # plt.show(block=True)

    def completed(self):
        if len(self.rois) > 0:
            return all(r.completed for r in self.rois)
        else:
            return True

    def __add_roi_type(self, roi_name):
        if roi_name in self.roi_values.values():
            return
        roi_value = len(self.roi_values.keys()) + 1
        self.roi_values[roi_value] = roi_name
        self.roi_value_colors[roi_value] = np.random.rand(3)
        btn = Button(plt.axes([0.1 * roi_value, 0.02, 0.1, 0.04]), roi_name)
        btn.on_clicked(lambda x: self.select_roi_type(roi_value, x))
        self.buttons.append(btn)
        return roi_value

    def select_roi_type(self, idx, event):
        self.textbox.set_val(self.roi_values[idx])
        self.current_roi_value = idx

    def new_roi_type(self, event):
        roi_name = self.textbox.text
        if roi_name in self.roi_values.values():
            msg = "{} ROI already exists.".format(roi_name)
            self.log(logging.WARNING, msg)
            return
        # roi_value begins from 1
        roi_value = self.__add_roi_type(roi_name)
        self.roi_values[roi_value] = roi_name
        # generate a color randomly for this type of ROI
        self.roi_value_colors[roi_value] = np.random.rand(3)
        if self.completed():
            self.current_roi_value = roi_value
        msg = "Add New ROI Type: {}".format(roi_name)
        self.log(logging.INFO, msg)
        self.update_plot()

    def new_roi(self, event):
        if self.__image is None:
            self.log(logging.WARNING, "No image loaded yet.")
            return
        if not self.completed():
            self.log(logging.INFO, "Some roi(s) haven't been completed.")
            return
        rois_cnt = len(self.rois)
        try:
            roi_name = self.roi_values[self.current_roi_value]
        except KeyError:
            return
        msg = "Creating new ROI {}, type {}".format(rois_cnt, roi_name)
        self.log(logging.INFO, msg)
        plt.draw()
        roi_color = self.color_cycle[rois_cnt % len(self.color_cycle)]
        roi = RoiPoly(roi_val=self.current_roi_value,
                      color=roi_color, fig=self.img_fig, ax=self.img_axes,
                      close_fig=False, show_fig=False,
                      completed_callback=self.roi_completed)
        self.rois.append(roi)

    def roi_completed(self, roi: RoiPoly):
        msg = "ROI {} completed".format(roi.value)
        self.log(logging.INFO, msg)
        mask = roi.get_mask(self.__image.shape[:2])
        self.mask[mask] = roi.value
        self.__mask[mask] = self.roi_value_colors[roi.value]
        self.update_plt_mask()

    def clear_rois(self, event):
        self.image = np.array(self.__image)
        self.update_plot()

    def finish(self, event):
        if not self.completed():
            self.log(logging.INFO, "Some roi(s) haven't been completed")
            return
        if self.finish_callback:
            if self.finish_callback(self):
                logging.log(logging.INFO, "Finishing signal from callback.")
                plt.close('all')
            else:
                pass
        else:
            self.log(logging.WARNING, "No callback after finishing a ROI.")
            plt.close('all')

    def update_img_title(self, title):
        plt.figure(self.img_fig_idx)
        self.img_axes.set_title(title)
        plt.draw()

    def update_mask_title(self, title):
        plt.figure(self.mask_fig_idx)
        plt.title(title)
        plt.draw()
        plt.figure(self.img_fig_idx)

    def update_plt_img(self):
        plt.figure(self.img_fig_idx)
        self.img_axes.clear()
        self.img_axes.set_axis_off()
        self.img_axes.imshow(self.__image)
        plt.draw()

    def update_plt_mask(self):
        plt.figure(self.mask_fig_idx)
        self.mask_axes.imshow(self.__mask)
        plt.draw()
        plt.figure(self.img_fig_idx)

    def log(self, level, msg):
        logging.log(level, msg)
        self.update_img_title(msg)
Esempio n. 13
0
class Oscillo:
    def __init__(
        self,
        channel_list,
        sampling=5e3,
        volt_range=10.0,
        trigger_level=None,
        trigsource=None,
        backend="daqmx",
    ):
        if backend not in Backends:
            raise ValueError(f"Backend {backend:} is not available.")
        self.backend = backend
        self.channel_list = channel_list
        self.sampling = sampling
        self.volt_range = volt_range
        self.ignore_voltrange_submit = False
        self.trigger_level = trigger_level
        self.trigger_source = trigsource
        self.N = 1024
        plt.ion()
        self.fig = plt.figure()
        # left, bottom, width, height
        self.ax = self.fig.add_axes([0.1, 0.1, 0.7, 0.8])
        self.running = False
        self.last_trigged = 0
        self.ask_pause_acqui = False
        self.paused = False

        self.freq = None
        self.Pxx = None
        self.N_spectra = 0
        self.fig_spectrum = None
        self.hanning = True
        self.ac = True
        self.power_spectrum = True
        self.spectrum_unit = 1.0
        self.spectrum_unit_str = "V^2/Hz"
        self.system = None
        self.saved_spectra = list()

        self.fig_stats = None

        # Configure widgets
        left, bottom = 0.825, 0.825
        width, height = 0.15, 0.075
        vpad = 0.02

        ax_sampling = self.fig.add_axes([left, bottom, width, height])
        bottom -= height * 1.25 + 2 * vpad
        self.textbox_sampling = TextBox(ax_sampling,
                                        label="",
                                        initial=f"{sampling:.1e}")
        self.textbox_sampling.on_submit(self.ask_sampling_change)
        _ = ax_sampling.text(0, 1.25, "Sampling")

        ax_enable_trigger = self.fig.add_axes([left, bottom, width, height])
        bottom -= height * 1.25 + 2 * vpad
        self.textbox_triggersource = TextBox(ax_enable_trigger,
                                             label="",
                                             initial="None")
        self.textbox_triggersource.on_submit(self.ask_trigger_change)
        _ = ax_enable_trigger.text(0, 1.25, "Trigger")

        ax_triggerlevel = self.fig.add_axes([left, bottom, width, height])
        bottom -= height * 1.25 + 2 * vpad
        if trigger_level is not None:
            initial_value = f"{trigger_level:.2f}"
        else:
            initial_value = "1.0"
        self.textbox_triggerlevel = TextBox(ax_triggerlevel,
                                            label="",
                                            initial=initial_value)
        self.textbox_triggerlevel.on_submit(self.ask_trigger_change)
        _ = ax_triggerlevel.text(0, 1.25, "Level")

        ax_winsize = self.fig.add_axes([left, bottom, width, height])
        bottom -= height * 1.25 + 2 * vpad
        self.textbox_winsize = TextBox(ax_winsize,
                                       label="",
                                       initial=f"{self.N:d}")
        self.textbox_winsize.on_submit(self.ask_winsize_change)
        _ = ax_winsize.text(0, 1.25, "Win size")

        ax_voltrange = self.fig.add_axes([left, bottom, width, height])
        bottom -= height * 1.25 + 2 * vpad
        self.textbox_voltrange = TextBox(ax_voltrange,
                                         label="",
                                         initial=f"{self.volt_range:.1f}")
        self.textbox_voltrange.on_submit(self.ask_voltrange_change)
        _ = ax_voltrange.text(0, 1.25, "Range")

        ax_start_stats = self.fig.add_axes([left, bottom, width, height])
        bottom -= height + vpad
        self.btn_start_stats = Button(ax_start_stats, label="Stats")
        self.btn_start_stats.on_clicked(self.start_stats)

        ax_start_spectrum = self.fig.add_axes([left, bottom, width, height])
        bottom -= height + vpad
        self.btn_start_spectrum = Button(ax_start_spectrum, label="FFT")
        self.btn_start_spectrum.on_clicked(self.start_spectrum)

    def clean_spectrum(self, *args):
        self.freq = None
        self.Pxx = None
        self.N_spectra = 0

    def start_stats(self, event):
        if self.fig_stats is None:
            self.fig_stats = dict()
            self.box_mean = dict()
            self.box_std = dict()
            self.box_min = dict()
            self.box_max = dict()
            self.box_freq = dict()
        nbox = 5
        height = 1.0 / (nbox + 1)
        padding = height / 4
        for chan in self.channel_list:
            if chan not in self.fig_stats:
                self.fig_stats[chan] = plt.figure(figsize=(2, 4))
                self.fig_stats[chan].canvas.set_window_title(chan)

                ax_mean = self.fig_stats[chan].add_axes(
                    [0.25, 9 * height / 2, 0.7, height - padding])
                self.box_mean[chan] = TextBox(ax_mean,
                                              label="Mean",
                                              initial="")

                ax_std = self.fig_stats[chan].add_axes(
                    [0.25, 7 * height / 2, 0.7, height - padding])
                self.box_std[chan] = TextBox(ax_std, label="Std", initial="")

                ax_min = self.fig_stats[chan].add_axes(
                    [0.25, 5 * height / 2, 0.7, height - padding])
                self.box_min[chan] = TextBox(ax_min, label="Min", initial="")

                ax_max = self.fig_stats[chan].add_axes(
                    [0.25, 3 * height / 2, 0.7, height - padding])
                self.box_max[chan] = TextBox(ax_max, label="Max", initial="")

                ax_freq = self.fig_stats[chan].add_axes(
                    [0.25, height / 2, 0.7, height - padding])
                self.box_freq[chan] = TextBox(ax_freq,
                                              label="Freq",
                                              initial="")

    def start_spectrum(self, *args, **kwargs):
        if self.fig_spectrum is None:
            self.fig_spectrum = plt.figure()
            self.ax_spectrum = self.fig_spectrum.add_axes([0.1, 0.1, 0.7, 0.8])

            # Widgets
            ax_hanning = self.fig_spectrum.add_axes([0.825, 0.75, 0.15, 0.15])
            self.checkbox_hanning = CheckButtons(ax_hanning, ["Hanning", "AC"],
                                                 [self.hanning, self.ac])
            self.checkbox_hanning.on_clicked(self.ask_hanning_change)

            ax_spectrum_unit = self.fig_spectrum.add_axes(
                [0.825, 0.51, 0.15, 0.25])
            self.radio_units = RadioButtons(
                ax_spectrum_unit,
                ["V^2/Hz", "V/sq(Hz)", "mV/sq(Hz)", "µV/sq(Hz)", "nV/sq(Hz)"],
            )
            self.radio_units.on_clicked(self.ask_spectrum_units_change)

            ax_restart = self.fig_spectrum.add_axes([0.825, 0.35, 0.15, 0.075])
            self.btn_restart = Button(ax_restart, label="Restart")
            self.btn_restart.on_clicked(self.clean_spectrum)

            ax_save_hold = self.fig_spectrum.add_axes(
                [0.825, 0.25, 0.15, 0.075])
            self.btn_save_hold = Button(ax_save_hold, label="Hold&Save")
            self.btn_save_hold.on_clicked(self.save_hold)

        self.clean_spectrum()

    def save_hold(self, event):
        if self.N_spectra > 0:
            dt = datetime.now()
            filename = (f"pymanip_oscillo_{dt.year:}-{dt.month}-{dt.day}"
                        f"_{dt.hour}-{dt.minute}-{dt.second}.hdf5")
            bb = self.freq > 0
            with h5py.File(filename) as f:
                f.attrs["ts"] = dt.timestamp()
                f.attrs["N_spectra"] = self.N_spectra
                f.attrs["sampling"] = self.sampling
                f.attrs["volt_range"] = self.volt_range
                f.attrs["N"] = self.N
                f.create_dataset("freq", data=self.freq[bb])
                f.create_dataset("Pxx", data=self.Pxx[bb] / self.N_spectra)
            self.saved_spectra.append({
                "freq": self.freq[bb],
                "Pxx": self.Pxx[bb] / self.N_spectra
            })

    def ask_spectrum_units_change(self, event):
        power_spectrum_dict = {
            "V^2/Hz": True,
            "V/sq(Hz)": False,
            "mV/sq(Hz)": False,
            "µV/sq(Hz)": False,
            "nV/sq(Hz)": False,
        }
        spectrum_unit_dict = {
            "V^2/Hz": 1.0,
            "V/sq(Hz)": 1.0,
            "mV/sq(Hz)": 1e3,
            "µV/sq(Hz)": 1e6,
            "nV/sq(Hz)": 1e9,
        }
        if event in power_spectrum_dict:
            self.spectrum_unit_str = event
            self.power_spectrum = power_spectrum_dict[event]
            self.spectrum_unit = spectrum_unit_dict[event]

    async def winsize_change(self, new_N):
        await self.pause_acqui()
        old_N = self.N
        self.N = new_N
        self.clean_spectrum()
        self.figure_t_axis()
        try:
            self.system.configure_clock(self.sampling, self.N)
        except Exception as e:
            print(e)
            self.N = old_N
        await self.restart_acqui()

    def ask_winsize_change(self, label):
        try:
            new_N = int(label)
        except ValueError:
            print("winsize must be an integer")
            return
        loop = asyncio.get_event_loop()
        asyncio.ensure_future(self.winsize_change(new_N), loop=loop)

    def ask_trigger_change(self, label):
        changed = False
        trigger_source = self.textbox_triggersource.text
        possible_trigger_source = self.system.possible_trigger_channels()
        if trigger_source not in possible_trigger_source:
            print(f"{trigger_source:} is not an acceptable trigger source")
            print("Possible values:", possible_trigger_source)
            trigger_source = None
            self.textbox_triggersource.set_val("None")
        if trigger_source == "None":
            trigger_source = None
        if self.trigger_source != trigger_source:
            self.trigger_source = trigger_source
            changed = True
        if self.trigger_source is not None:
            try:
                trigger_level = float(self.textbox_triggerlevel.text)
            except ValueError:
                trigger_level = self.trigger_level
            val_str = f"{trigger_level:.2f}"
            self.textbox_triggerlevel.set_val(val_str)
            if trigger_level != self.trigger_level:
                self.trigger_level = trigger_level
                changed = True
        if changed:
            loop = asyncio.get_event_loop()
            asyncio.ensure_future(self.trigger_change(), loop=loop)

    async def pause_acqui(self):
        self.ask_pause_acqui = True
        await self.system.stop()
        while not self.paused:
            await asyncio.sleep(0.5)

    async def restart_acqui(self):
        self.ask_pause_acqui = False
        while self.paused:
            await asyncio.sleep(0.5)

    async def trigger_change(self):
        print("Awaiting pause")
        await self.pause_acqui()
        print("Acquisition paused")
        if self.trigger_level is not None:
            trigger_source = self.trigger_source
            trigger_level = self.trigger_level
            self.system.configure_trigger(trigger_source, trigger_level)
        else:
            self.system.configure_trigger(None)
        self.clean_spectrum()
        await self.restart_acqui()

    async def sampling_change(self):
        await self.pause_acqui()
        try:
            self.system.configure_clock(self.sampling, self.N)
        except Exception:
            print("Invalid sampling frequency")
            self.ask_sampling_change(self.system.samp_clk_max_rate)
            return
        if self.system.sample_rate != self.sampling:
            self.ask_sampling_change(self.system.sample_rate)
            return
        self.figure_t_axis()
        self.clean_spectrum()
        await self.restart_acqui()

    def ask_sampling_change(self, sampling):
        try:
            self.sampling = float(sampling)
            changed = True
        except ValueError:
            print("Wrong value:", sampling)
            changed = False
        self.textbox_sampling.set_val(f"{self.sampling:.1e}")
        if changed:
            loop = asyncio.get_event_loop()
            asyncio.ensure_future(self.sampling_change(), loop=loop)

    def ask_hanning_change(self, label):
        self.hanning, self.ac = self.checkbox_hanning.get_status()
        self.clean_spectrum()

    def figure_t_axis(self):
        self.t = np.arange(self.N) / self.sampling
        if self.t[-1] < 1:
            self.t *= 1000
            self.unit = "[ms]"
        else:
            self.unit = "[s]"

    async def run_gui(self):
        while self.running:
            if time.monotonic() - self.last_trigged > self.N / self.sampling:
                self.ax.set_title("Waiting for trigger")
            self.fig.canvas.start_event_loop(0.5)
            await asyncio.sleep(0.05)
            if not plt.fignum_exists(self.fig.number):
                self.running = False
            if self.fig_spectrum and not plt.fignum_exists(
                    self.fig_spectrum.number):
                self.fig_spectrum = None
                self.freq = None
                self.Pxx = None
                self.N_spectra = 0
            if self.fig_stats is not None:
                for chan in list(self.fig_stats.keys()):
                    if not plt.fignum_exists(self.fig_stats[chan].number):
                        self.fig_stats.pop(chan)
                        self.box_mean.pop(chan)
                        self.box_std.pop(chan)
                        self.box_min.pop(chan)
                        self.box_max.pop(chan)
                        self.box_freq.pop(chan)
                    if not self.fig_stats:
                        self.fig_stats = None

    def ask_voltrange_change(self, new_range):
        if not self.ignore_voltrange_submit:
            try:
                new_range = float(new_range)
            except ValueError:
                print("Volt range must be a float")
                return
            loop = asyncio.get_event_loop()
            asyncio.ensure_future(self.voltrange_change(new_range), loop=loop)

    async def voltrange_change(self, new_range):
        await self.pause_acqui()
        self.volt_range = new_range
        self.clean_spectrum()
        self.create_system()
        await self.restart_acqui()
        actual_range = self.system.actual_ranges[0]
        print("actual_range =", actual_range)
        self.ignore_voltrange_submit = True
        self.textbox_voltrange.set_val(f"{actual_range:.1f}")
        self.ignore_voltrange_submit = False

    def create_system(self):
        if self.system is not None:
            self.system.close()
        self.system = Backends[self.backend]()
        self.ai_channels = list()
        for chan in self.channel_list:
            ai_chan = self.system.add_channel(chan,
                                              terminal_config=TC.Diff,
                                              voltage_range=self.volt_range)
            self.ai_channels.append(ai_chan)
        self.system.configure_clock(self.sampling, self.N)
        self.textbox_sampling.set_val(f"{self.system.sample_rate:.1e}")
        if self.trigger_level is not None:
            trigger_source = self.channel_list[self.trigger_source]
            self.system.configure_trigger(trigger_source,
                                          trigger_level=self.trigger_level)
        else:
            self.system.configure_trigger(None)
        self.figure_t_axis()

    async def run_acqui(self):
        self.create_system()
        try:
            while self.running:
                while self.ask_pause_acqui and self.running:
                    self.paused = True
                    await asyncio.sleep(0.5)
                self.paused = False
                if not self.running:
                    break
                self.system.start()
                data = await self.system.read()
                await self.system.stop()
                if data is None:
                    continue
                self.last_trigged = self.system.last_read
                self.ax.cla()
                if len(self.channel_list) == 1:
                    self.ax.plot(self.t, data, "-")
                elif len(self.channel_list) > 1:
                    for d in data:
                        self.ax.plot(self.t, d, "-")
                if self.trigger_source not in (None, "Ext"):
                    self.ax.plot([self.t[0], self.t[-1]],
                                 [self.trigger_level] * 2, "g--")
                self.ax.set_xlim([self.t[0], self.t[-1]])
                self.ax.set_title("Trigged!")
                self.ax.set_xlabel("t " + self.unit)
                if self.fig_spectrum:
                    self.ax_spectrum.cla()
                    if self.saved_spectra:
                        for spectra in self.saved_spectra:
                            self.ax_spectrum.loglog(spectra["freq"],
                                                    spectra["Pxx"], "-")
                    if self.N_spectra == 0:
                        self.freq = np.fft.fftfreq(self.N, 1.0 / self.sampling)
                        bb = self.freq > 0
                        norm = math.pi * math.sqrt(self.N / self.sampling)
                        if self.hanning:
                            window = np.hanning(self.N)
                        else:
                            window = np.ones((self.N, ))
                        if len(self.channel_list) == 1:
                            if self.ac:
                                m = np.mean(data)
                            else:
                                m = 0.0
                            self.Pxx = (np.abs(
                                np.fft.fft((data - m) * window) / norm)**2)
                        else:
                            if self.ac:
                                ms = [np.mean(d) for d in data]
                            else:
                                ms = [0.0 for d in data]
                            self.Pxx = [
                                np.abs(np.fft.fft((d - m) * window) / norm)**2
                                for d, m in zip(data, ms)
                            ]
                        self.N_spectra = 1
                    else:
                        if len(self.channel_list) == 1:
                            if self.ac:
                                m = np.mean(data)
                            else:
                                m = 0.0
                            self.Pxx += (np.abs(
                                np.fft.fft((data - m) * window) / norm)**2)
                        else:
                            if self.ac:
                                ms = [np.mean(d) for d in data]
                            else:
                                ms = [0.0 for d in data]
                            for p, d, m in zip(self.Pxx, data, ms):
                                p += np.abs(
                                    np.fft.fft((d - m) * window) / norm)**2
                        self.N_spectra += 1
                    if self.power_spectrum:

                        def process_spec(s):
                            return self.spectrum_unit * s

                    else:

                        def process_spec(s):
                            return self.spectrum_unit * np.sqrt(s)

                    if len(self.channel_list) == 1:
                        self.ax_spectrum.loglog(
                            self.freq[bb],
                            process_spec(self.Pxx[bb] / self.N_spectra),
                            "-",
                        )
                    else:
                        for p in self.Pxx:
                            self.ax_spectrum.loglog(
                                self.freq[bb],
                                process_spec(p[bb] / self.N_spectra), "-")
                    self.ax_spectrum.set_xlabel("f [Hz]")
                    self.ax_spectrum.set_ylabel(self.spectrum_unit_str)
                    self.ax_spectrum.set_title(f"N = {self.N_spectra:d}")
                if self.fig_stats:
                    if len(self.channel_list) == 1:
                        list_data = [data]
                    else:
                        list_data = data
                    for chan, d in zip(self.channel_list, list_data):
                        if chan in self.fig_stats:
                            self.box_mean[chan].set_val("{:.5f}".format(
                                np.mean(d)))
                            self.box_std[chan].set_val("{:.5f}".format(
                                np.std(d)))
                            self.box_min[chan].set_val("{:.5f}".format(
                                np.min(d)))
                            self.box_max[chan].set_val("{:.5f}".format(
                                np.max(d)))
                            ff = np.fft.fftfreq(self.N, 1.0 / self.sampling)
                            pp = np.abs(np.fft.fft(d - np.mean(d)))
                            ii = np.argmax(pp)
                            self.box_freq[chan].set_val("{:.5f}".format(
                                ff[ii]))

        finally:
            self.system.close()

    def ask_exit(self, *args, **kwargs):
        self.running = False

    def run(self):
        loop = asyncio.get_event_loop()
        self.running = True
        if sys.platform == "win32":
            signal.signal(signal.SIGINT, self.ask_exit)
        else:
            for signame in ("SIGINT", "SIGTERM"):
                loop.add_signal_handler(getattr(signal, signame),
                                        self.ask_exit)

        loop.run_until_complete(
            asyncio.gather(self.run_gui(), self.run_acqui()))
Esempio n. 14
0
class Monster():
    '''
	class for instantiating a Monster Object, which contains some basic information
	about a monster (AC and HP, + a name) and which interfaces with an Encounter 
	to show a dynamic bar graph of your monsters' HP in battle.
	'''
    def __init__(self, monster_name, HP, AC):
        '''
		Initialize Monster 
		------------------
		Params: 
			monster_name (string): name to label the bar/textbox for each monster. Shorter is better...
			HP (int/float): value of the monster's initial HP 
			AC (int/float): value for the monster's AC (static, but displayed for ease of viewing)
		Returns:
			None 
		'''
        self.monster_name = monster_name
        self.HP = HP
        self.init_HP = HP
        self.AC = AC

    def update_barnum(self, barnum):
        '''
		Tells each monster which mpl bar it is. 
		-------------------
		Params:
		barnum (int): bar number in overall mpl figure corresponding to this monster.
		'''
        self.barnum = barnum

    def create_textbox(self, axes):
        '''
		Create textbox entry space and label for each monster, using input axes calculated from 
		the full monster list supplied to Encounter. 
		--------------------------
		Params:
			axes (array_like): list containing mpl axes argument, e.g., [0.1,0.1,0.8,0.8]
		Returns:
			None
		'''
        self.textboxaxes = plt.axes(axes)
        self.textboxaxes.text(0.5,
                              1.2,
                              self.monster_name,
                              horizontalalignment='center',
                              verticalalignment='center',
                              transform=self.textboxaxes.transAxes)
        self.textbox = TextBox(self.textboxaxes, label='', initial='')
        self.textbox.on_submit(self.update_damage)

    def update_damage(self, damage):
        '''
		Method to update the bar on the plot for this monster's HP based on input damage. 
		Negative damage corresponds to gaining HP. 
		---------------------------
		Params: 
			damage (int/float): amount of damage to subtract from the current HP.
		Returns:
			None, but on_submit will run this on <enter> or clicking out of the textbox. Updates the bar width.
		'''
        try:
            sub_value = eval(damage)
        except:
            self.textbox.set_val('')
            return
        self.HP -= sub_value
        bars[self.barnum].set_width(self.HP)

        if self.HP < 0.2 * self.init_HP:
            bars[self.barnum].set_color('r')
        elif self.HP > 0.2 * self.init_HP:
            bars[self.barnum].set_color('C0')

        self.textbox.set_val('')
Esempio n. 15
0
class interceptor():

    sol_range = (1, 15)     # range of possible solutions
    tv_range = (1, 30)      # range of coorinates of the target velocity vector
    mv = np.array([0,4])    # velocity vector of the missile
    mp0 = np.array([0,0])   # initial position of the missile
    font = 'monospace'
    figsize = (6,6)

    launched = False        # flag inticating if the missile launch time has been entered by the user
    t0 = 0                  # missile launch time


    def __init__(self, q=None):
        # select the velocity and the initial position of the target
        self.tp0 = np.array([0, 0])    # position of the target
        self.tv0 = np.array([0, 0])    # velocity vector of the target

        # select target velocity and problem solution at random
        # check if these choices are reasonable; if not try again
        while self.tp0[1] <= 0 or self.tv0[0] == 0:
            self.tv0 = self.choose_tv()
            # self.sol is the solution vector
            # self.sol[1] is the correct launch time of the missile
            # self.sol[0] is the duration of the flight is the missile to the inteception point
            self.sol = self.choose_sol()
            self.tp0 = self.sol[0]*self.mv - np.sum(self.sol)*self.tv0 # initial position of the target
        
        
        # limits of plot axes
        self.xmax = abs(self.tp0[0]) + 10
        self.xmin = (-1)*abs(self.tp0[0]) -10
        self.ymax = max(abs(self.tp0[1]), self.sol[0]*self.mv[1]) +15
        self.ymin = -1
        self.start_game(q)
        
   
        
    def start_game(self, q=None):
        #if q='show' the missile launch time will be displayed
        # in the time entry box
    
        # reset initial values
        self.tp = self.tp0.copy()
        self.tv = self.tv0.copy()
        self.mp = self.mp0.copy()
        # distance to target
        self.dist = np.linalg.norm(self.tp - self.mp)
        self.launched = False
        self.t0 = 0

        # set up plot
        self.fig = plt.figure(figsize = self.figsize)
        #main axes object
        self.ax = axbox = plt.axes([0.1, 0.15, 0.8, 0.8])
        #textbox axes object
        self.t_ax= plt.axes([0.8, 0.05, 0.1, 0.05])
        self.ax.set_facecolor('k')
        self.ax.set_xlim(self.xmin, self.xmax)
        self.ax.set_ylim(self.ymin, self.ymax)
        self.ax.grid(alpha = 0.2, color='g')

        # text box for entering the missile launch time
        istr = ('' if q != 'show' else str(self.sol[1]))
        self.text_box = TextBox(self.t_ax, 'Select missile launch time $t_0=$ ', initial=istr)
        self.text_box.on_submit(self.missile_launch)


        #text with problem data
        text1 = 'target position         =  [{:4}, {:4}]'.format(self.tp[0], self.tp[1])
        text2 = 'target velocity vector  =  [{:4}, {:4}]'.format(self.tv[0], self.tv[1])
        text3 = '---------------------------------------'
        text4 = 'missile position        =  [{:4}, {:4}]'.format(self.mp[0], self.mp[1])
        text5 = 'missile velocity vector =  [{:4}, {:4}]'.format(self.mv[0], self.mv[1])
        
        # text for the final screen
        summary = []
        summary.append('TARGET INTERCEPTED') 
        summary.append('MISSION SUMMARY:')
        summary.append('----------------------------------------')
        summary.append('initial target position  =  [{:4}, {:4}]'.format(self.tp0[0], self.tp0[1]))
        summary.append('target velocity vector   =  [{:4}, {:4}]'.format(self.tv0[0], self.tv0[1]))
        summary.append('----------------------------------------')
        summary.append('initial missile position =  [{:4}, {:4}]'.format(self.mp0[0], self.mp0[1]))
        summary.append('missile velocity vector  =  [{:4}, {:4}]'.format(self.mv[0], self.mv[1]))
        summary.append('----------------------------------------')
        summary.append('missile launch time      =  {:>5.2f}'.format(self.sol[1]))
        summary.append('target interception time =  {:>5.2f}'.format(np.sum(self.sol)))
        summary.append('----------------------------------------')
        summary.append('THE END') 
        self.summary_text = '\n'.join(summary)
        
        # self.text_all is the string displyed on the plot
        self.text_all = '\n'.join([text1, text2, text3, text4, text5])
        self.data_text = self.ax.text(0.05, 0.95,
                                      self.text_all,
                                      transform=self.ax.transAxes,
                                      color='g',
                                      family = self.font,
                                      verticalalignment = 'top',
                                     )
        #target position
        self.tp_plot, = self.ax.plot(*list(self.tp), 'g+', ms=7)
        #target velocity vector
        self.tv_plot, = self.ax.plot(*zip(list(self.tp), list(self.tp+self.tv)), 'g')
        #missile position
        self.mp_plot, = self.ax.plot(*list(self.mp), 'g^')
        #missile velocity vector
        self.mv_plot, = self.ax.plot(*zip(list(self.mp), list(self.mp+self.mv)), 'g')


        #animation
        self.ani = FuncAnimation(self.fig,
                                 func = self.update_plot,
                                 init_func= self.init_plot,
                                 frames=self.frames,
                                 interval=20,
                                 blit=True,
                                 repeat=False
                                )

        plt.show()
    
    
    def missile_launch(self, t0):
        '''
        function linked to the text box
        for entering missile launch time
        '''
        try:
            # check if a numerical value has been entered
            self.t0 = float(t0)
            self.launched = True
        except:
            self.text_box.set_val("")


    def choose_tv(self):
        '''
        selects a random
        target velocity vector
        '''
        return  np.random.randint(*self.tv_range, 2)

    def choose_sol(self):
        '''
        selects a random
        problem solution
        '''
        return np.random.randint(*self.sol_range, 2)


    def init_plot(self):
        '''
        initialized animation
        '''
        self.tv_plot.set_visible(False)
        self.mv_plot.set_visible(False)
        return self.data_text, self.tp_plot, self.mp_plot, self.tv_plot, self.mv_plot

    def update_plot(self, t):
        '''
        updates plot on each animation frame
        '''
        self.tv_plot.set_visible(True)
        self.mv_plot.set_visible(True)
        self.data_text.set_text(self.text_all)
        if t >= 0:
            self.tv_plot.set_visible(False)
            self.mv_plot.set_visible(False)
            self.tp_plot.set_data(*list(self.tp.T))
            self.mp_plot.set_data(*list(self.mp))

        return self.data_text, self.tp_plot, self.mp_plot, self.tv_plot, self.mv_plot

    def frames(self):
        '''
        generating fuction which
        computes data for each animation frame
        '''
        incr = 0.04    # time increment on each animation frame
        fired = False  # flag indicating if the missile has been fired
        hit = False    # flag indicating if the target has been hit

        N = 50         # number of animated particles after missile-target collision
        spread = np.array([0.02*self.xmax, 0.02*self.ymax], dtype=float) # controls the spread of particles
        fall_rate = np.array([0, -0.003*self.ymax]) # controls the fall rate of particles
        brightness = 0.95  # controls decrease in the brightness of the particles
        alpha = 1      # initial transparency of the target marker
        
        #do not animate until missile launch time has been entered
        while not self.launched:
            yield -1

        # start time count
        t = 0
        while True:
            yield t
            if not fired:
                self.text_all = 'time: {:.2f}\ntarget distance: {:.2f}\nmissile launch in {:.2f}'.format(
                    t, self.dist, self.t0 - t, )
            else:
                self.text_all = 'time: {:.2f}\ntarget distance: {:.2f}\nmissile en route'.format(t, self.dist)
            t += incr


            if not hit:
                # increment target position
                self.tp = self.tp + incr*self.tv
                if t > self.t0:
                    if not fired:
                        # just for aesthetic: a small missile back jump just before it is launched
                        self.mp = self.mp - np.array([0, 0.5])
                        fired = True
                    else:
                        # increment missile position
                        self.mp = self.mp + incr*self.mv

                    # if missile is above target or target crossed the missile axis then the missile will not hit
                    if self.tp[0] > 2 or self.mp[1] > self.tp[1] + 2:
                        self.text_all = 'time: {:.2f}\ntarget lost'.format(t)
                        
                self.dist = np.linalg.norm(self.tp - self.mp)

                # missile hit
                if self.t0 == self.sol[1] and t >= np.sum(self.sol):
                    self.tp = np.zeros((N,2), dtype=float) + self.tp - np.array([0, -0.2])
                    self.mp = self.mp + np.array([0, 0.5])
                    hit = True

            else:
                #after the hit
                # remove the missile plot
                self.mp_plot.set_visible(False)
                # replace the target by a particle cloud
                self.tp = self.tp + (np.random.rand(N, 2)-0.5)*spread + fall_rate
                self.tp_plot.set_markersize(1.5)
                alpha = min(alpha*brightness + 0.05*np.random.rand(1)[0], 1)
                self.tp_plot.set_alpha(alpha)    
                text_end = int((t - np.sum(self.sol))/incr)
                self.text_all = '\n'+ self.summary_text[:text_end]
Esempio n. 16
0
class SpectraViewer:
    def __init__(self, spectrometer):
        """ A matplotlib-based window to display and manage a spectrometer
        to replace the insanely inept OceanView software from OceanInsight or 
        the dude-wtf?1 software from Stellarnet.
        If anybody reads this from Ocean Insight, you can direct people
        to this Python script.  It is simpler to call it directly from the
        spectrometer object with its own display function that will instantiate
        a SpectraViewer and call its display function with itself as a paramater.

        Parameters
        ----------

        spectrometer: Spectrometer
            A spectrometer from Ocean Insight or Stellarnet
        """

        self.spectrometer = spectrometer
        self.lastSpectrum = []
        self.whiteReference = None
        self.darkReference = None
        self.figure = None
        self.axes = None
        self.quitFlag = False
        self.saveBtn = None
        self.quitBtn = None
        self.lightBtn = None
        self.darkBtn = None
        self.integrationTimeBox = None
        self.animation = None

    def display(self):
        """ Display the spectrum in free-running mode, with simple
        autoscale, save and quit buttons as well as a text entry for
        the integration time. This is the only user-facing function that 
        is needed.
        """
        self.figure, self.axes = self.createFigure()

        self.setupLayout()
        self.quitFlag = False
        self.animation = animation.FuncAnimation(self.figure,
                                                 self.animate,
                                                 interval=100)
        plt.show()

    def createFigure(self):
        """ Create a matplotlib figure with decent properties. """

        SMALL_SIZE = 14
        MEDIUM_SIZE = 18
        BIGGER_SIZE = 36

        plt.rc('font', size=SMALL_SIZE)  # controls default text sizes
        plt.rc('axes', titlesize=SMALL_SIZE)  # fontsize of the axes title
        plt.rc('axes', labelsize=MEDIUM_SIZE)  # fontsize of the x and y labels
        plt.rc('xtick', labelsize=MEDIUM_SIZE)  # fontsize of the tick labels
        plt.rc('ytick', labelsize=MEDIUM_SIZE)  # fontsize of the tick labels
        plt.rc('legend', fontsize=SMALL_SIZE)  # legend fontsize
        plt.rc('figure', titlesize=BIGGER_SIZE)  # fontsize of the figure title

        fig, axes = plt.subplots()
        fig.set_size_inches(10, 6, forward=True)
        serialNumber = self.spectrometer.getSerialNumber()
        model = self.spectrometer.model
        fig.canvas.manager.set_window_title(
            'Spectrometer [serial # {0}, model {1}]'.format(
                serialNumber, model))
        axes.set_xlabel("Wavelength [nm]")
        axes.set_ylabel("Intensity [arb.u]")
        return fig, axes

    def setupLayout(self):
        axScale = plt.axes([0.125, 0.90, 0.13, 0.075])
        axLight = plt.axes([0.25, 0.90, 0.08, 0.075])
        axDark = plt.axes([0.30, 0.90, 0.08, 0.075])
        axTime = plt.axes([0.59, 0.90, 0.08, 0.075])
        axSave = plt.axes([0.73, 0.90, 0.08, 0.075])
        axQuit = plt.axes([0.82, 0.90, 0.08, 0.075])
        self.saveBtn = Button(axSave, 'Save')
        self.saveBtn.on_clicked(self.clickSave)
        self.quitBtn = Button(axQuit, 'Quit')
        self.quitBtn.on_clicked(self.clickQuit)
        self.autoscaleBtn = Button(axScale, 'Autoscale')
        self.autoscaleBtn.on_clicked(self.clickAutoscale)

        rootDir = os.path.dirname(os.path.abspath(__file__))

        try:
            axLight.imshow(plt.imread("{0}/lightbulb.png".format(rootDir)))
            axLight.set_xticks([])
            axLight.set_yticks([])
            self.lightBtn = Button(axLight, '')
        except:
            self.lightBtn = Button(axLight, 'W')
        self.lightBtn.on_clicked(self.clickWhiteReference)

        try:
            axDark.imshow(plt.imread("{0}/darkbulb.png".format(rootDir)))
            axDark.set_xticks([])
            axDark.set_yticks([])
            self.darkBtn = Button(axDark, '')
        except:
            self.darkBtn = Button(axDark, 'D')
        self.darkBtn.on_clicked(self.clickDarkReference)

        currentIntegrationTime = self.spectrometer.getIntegrationTime()
        self.integrationTimeBox = TextBox(
            axTime,
            'Integration time [ms]',
            initial="{0}".format(currentIntegrationTime),
            label_pad=0.1)
        self.integrationTimeBox.on_submit(self.submitTime)
        self.figure.canvas.mpl_connect('key_press_event', self.keyPress)

    def plotSpectrum(self, spectrum=None):
        """ Plot a spectrum into the figure or request a new spectrum. This
        is called repeatedly when the display function is called."""
        if spectrum is None:
            spectrum = self.spectrometer.getSpectrum()

        if len(self.axes.lines) == 0:
            self.axes.plot(self.spectrometer.wavelength, spectrum, 'k')
            self.axes.set_xlabel("Wavelength [nm]")
            self.axes.set_ylabel("Intensity [arb.u]")
        else:
            self.axes.lines[0].set_data(self.spectrometer.wavelength,
                                        spectrum)  # set plot data
            self.axes.relim()

    def animate(self, i):
        """ Internal function that is called repeatedly to manage the
        update  of the spectrum plot. It is better to use the `animation`
        strategy instead of a loop with  plt.pause() because plt.pause() will
        always bring the window to the  foreground. 

        This function is also responsible for determining if the user asked to quit. 
        """
        try:
            self.lastSpectrum = self.spectrometer.getSpectrum()
            if self.darkReference is not None:
                self.lastSpectrum -= self.darkReference
            if self.whiteReference is not None:
                np.seterr(divide='ignore', invalid='ignore')
                if self.darkReference is not None:
                    self.lastSpectrum = self.lastSpectrum / (
                        self.whiteReference - self.darkReference)
                else:
                    self.lastSpectrum = self.lastSpectrum / self.whiteReference

            self.plotSpectrum(spectrum=self.lastSpectrum)
        except usb.core.USBError as err:
            print("The spectrometer was disconnected. Quitting.")
            self.quitFlag = True

        if self.quitFlag:
            self.animation.event_source.stop()
            self.animation = None
            plt.close()

    def keyPress(self, event):
        """ Event-handling function for keypress: if the user clicks command-Q
        on macOS, it will nicely quit."""

        if event.key == 'cmd+q':
            self.clickQuit(event)
        if event.key == 'backspace':
            self.clickClearReferences(event)

    def submitTime(self, event):
        """ Event-handling function for when the user hits return/enter 
        in the integration time text field. The new integration time 
        is set in the spectrometer.

        We must autoscale the plot because the intensities could be very different.
        However, it takes a small amount of time for the spectrometer to react.
        We wait 0.3 seconds, which is small enough to not be annoying and seems to
        work fine.

        Anything incorrect will bring the integration time to 3 milliseconds.
        """
        try:
            time = float(self.integrationTimeBox.text)
            if time == 0:
                raise ValueError('Requested integration time is invalid: \
the text "{0}" converts to 0.')
            self.spectrometer.setIntegrationTime(time)
            plt.pause(0.3)
            self.axes.autoscale_view()
        except Exception as err:
            print("Error when setting integration time: ", err)
            self.integrationTimeBox.set_val("3")

    def clickAutoscale(self, event):
        """ Event-handling function to autoscale the plot """
        self.axes.autoscale_view()

    def clickClearReferences(self, event):
        """ Event-handling function to acquire a white reference """
        self.whiteReference = None
        self.lightBtn.color = '0.85'
        self.darkReference = None
        self.darkBtn.color = '0.85'
        plt.pause(0.3)
        self.axes.autoscale_view()

    def clickWhiteReference(self, event):
        """ Event-handling function to acquire a white reference """
        if self.whiteReference is None:
            self.whiteReference = self.spectrometer.getSpectrum()
            self.lightBtn.color = '0.99'
        else:
            self.whiteReference = None
            self.lightBtn.color = '0.85'
        plt.pause(0.3)
        self.axes.autoscale_view()

    def clickDarkReference(self, event):
        """ Event-handling function to acquire a dark reference """
        if self.darkReference is None:
            self.darkReference = self.spectrometer.getSpectrum()
            self.darkBtn.color = '0.99'
        else:
            self.darkReference = None
            self.darkBtn.color = '0.85'
        plt.pause(0.3)
        self.axes.autoscale_view()

    def clickSave(self, event):
        """ Event-handling function to save the file.  We stop the animation
        to avoid acquiring more spectra. The last spectrum acquired (i.e.
        the one displayed) after we have requested the filename. 
        The data is saved as a CSV file, and the animation is restarted.
        
        Technical note: To request the filename, we use different strategies on 
        different platforms.  On macOS, we can use a function from the backend.
        On Windows and others, we fall back on Tk, which is usually installed 
        with python.
        """

        self.animation.event_source.stop()
        filepath = "spectrum.csv"
        try:
            filepath = backends.backend_macosx._macosx.choose_save_file(
                'Save the data', filepath)
        except:
            import tkinter as tk
            from tkinter import filedialog

            root = tk.Tk()
            root.withdraw()
            filepath = filedialog.asksaveasfilename()

        if filepath is not None:
            self.spectrometer.saveSpectrum(filepath,
                                           spectrum=self.lastSpectrum,
                                           whiteReference=self.whiteReference,
                                           darkReference=self.darkReference)

        self.animation.event_source.start()

    def clickQuit(self, event):
        """ Event-handling function to quit nicely."""
        self.quitFlag = True
Esempio n. 17
0
class FlightAnim:
    def __init__(self):
        self.pd = PlanetData('GEO')
        self.simulator = Simulator(self.pd)

        self.tf = 1.0e8  # max time for simulation
        self.delta_t_mars = 0.0
        self.Xs = []
        self.Ts = []

        self.difficulty = 1
        # 1 = just hit space around mars in distance of 0.1 AE
        # 2 = 0.01 AE
        # 3 = orbit

        max = 3.0 * self.pd.AE

        self.box_lbx = -max
        self.box_ubx = max
        self.box_lby = -max
        self.box_uby = max

        self.fig = plt.figure()
        gs = gridspec.GridSpec(10, 10)
        self.ax = plt.subplot(gs[1:7, 0:6])
        self.ax.grid(True)
        command_input_fields = 5
        self.ax_command_input = []
        self.command_text_boxes = []
        self.commands = {0: np.array([0.0, 600.0, 0.0, 5.0])}
        for i in range(1, command_input_fields):
            self.commands[i] = None

        # set up axes
        for i in range(0, len(self.commands.keys())):
            self.ax_command_input.append(plt.subplot(gs[i + 1, 7:]))

        # define command input field
        for i in range(0, len(self.commands.keys())):
            if i == 0:
                initial = str(self.commands[i][0]) + " " + str(self.commands[i][1]) + " " + str(self.commands[i][2]) \
                          + " " + str(self.commands[i][3])
            else:
                initial = ""
            self.command_text_boxes.append(
                TextBox(self.ax_command_input[i],
                        'Befehl {} '.format(i + 1),
                        initial=initial))
            f = functools.partial(self.submit_command, i)
            self.command_text_boxes[i].on_submit(f)

        self.ax_mars_delta_t = plt.subplot(gs[command_input_fields + 1, 7:])

        self.delta_t_mars_text_box = TextBox(self.ax_mars_delta_t,
                                             'Delta t Mars ',
                                             initial='0.0')
        self.delta_t_mars_text_box.on_submit(self.submit_delta_t_mars)

        # outputs
        self.ax_time = plt.subplot(gs[0, 4:6])
        self.ax_time.get_xaxis().set_visible(False)
        self.ax_time.get_yaxis().set_visible(False)
        self.text_time = self.ax_time.text(0.1, 0.5, 't = 0.0')

        self.ax_comdescript = plt.subplot(gs[0, 6:])
        self.ax_comdescript.get_xaxis().set_visible(False)
        self.ax_comdescript.get_yaxis().set_visible(False)
        self.text_comdescript = self.ax_comdescript.text(
            0.1, 0.1, 'Zeit, Dauer, Winkel, Schub')
        self.text_comvar = self.ax_comdescript.text(
            0.1, 0.6, 't,    delta t,  w,         u')

        self.ax_level = plt.subplot(gs[0, 0:2])
        self.ax_level.get_xaxis().set_visible(False)
        self.ax_level.get_yaxis().set_visible(False)
        self.text_level = self.ax_level.text(0.1, 0.5, 'Level 1')

        self.ax_info = plt.subplot(gs[7:10, 0:5])
        self.ax_info.get_xaxis().set_visible(False)
        self.ax_info.get_yaxis().set_visible(False)
        self.text_vel_rocket = self.ax_info.text(0.1, 0.25,
                                                 'v_{R} = (0.0, 0.0)')

        self.ax_info.get_xaxis().set_visible(False)
        self.ax_info.get_yaxis().set_visible(False)
        self.text_vel_mars = self.ax_info.text(0.1, 0.75, 'v_{M} = (0.0, 0.0)')

        self.ax_infocontrol = plt.subplot(gs[8:10, 5:9])
        self.ax_infocontrol.get_xaxis().set_visible(False)
        self.ax_infocontrol.get_yaxis().set_visible(False)
        self.text_setfaster = self.ax_infocontrol.text(
            0.1, 0.1, 'Sim-Geschw. erhoehen : +')
        self.ax_infocontrol.get_xaxis().set_visible(False)
        self.ax_infocontrol.get_yaxis().set_visible(False)
        self.text_setslower = self.ax_infocontrol.text(
            0.1, 0.35, 'Sim-Geschw. verringern : -')
        self.ax_infocontrol.get_xaxis().set_visible(False)
        self.ax_infocontrol.get_yaxis().set_visible(False)
        self.text_setpause = self.ax_infocontrol.text(
            0.1, 0.75, 'Pause : Pfeiltaste runter')

        self.victory_text = self.ax_info.text(0.1, 0.25, 'Victory!')

        self.ax_button = plt.subplot(gs[9, 9])

        self.ax.set_ylim([self.box_lby, self.box_uby])
        self.ax.set_xlim([self.box_lbx, self.box_ubx])
        self.ax.figure.canvas.draw()

        self.rocket_x = []
        self.rocket_y = []
        self.line_rocket, = self.ax.plot(self.rocket_x,
                                         self.rocket_y,
                                         'k',
                                         animated=False)
        self.point_rocket, = self.ax.plot([], [],
                                          color='k',
                                          marker='o',
                                          markersize=2,
                                          animated=False)

        self.earth_x = []
        self.earth_y = []
        self.line_earth, = self.ax.plot(self.earth_x,
                                        self.earth_y,
                                        color='b',
                                        linestyle='--',
                                        animated=False)
        self.earth = Ellipse((1 * self.pd.AE, 0),
                             0.1 * self.pd.AE,
                             0.1 * self.pd.AE,
                             animated=False,
                             color='blue')

        self.mars_x = []
        self.mars_y = []
        self.line_mars, = self.ax.plot(self.mars_x,
                                       self.mars_y,
                                       color='r',
                                       linestyle='--',
                                       animated=False)
        self.mars = Ellipse((0, 1.5173 * self.pd.AE),
                            0.1 * self.pd.AE,
                            0.1 * self.pd.AE,
                            animated=False,
                            color='red')

        self.sun_x = []
        self.sun_y = []
        self.line_sun, = self.ax.plot(self.sun_x,
                                      self.sun_y,
                                      color='y',
                                      linestyle='--')
        self.sun = Ellipse((0, 0),
                           0.2 * self.pd.AE,
                           0.2 * self.pd.AE,
                           animated=False,
                           color='yellow')

        self.text_rocket = self.ax.text(0,
                                        0,
                                        'Rakete',
                                        verticalalignment='bottom')
        self.text_earth = self.ax.text(0, 0, 'Erde', verticalalignment='top')
        self.text_mars = self.ax.text(0, 0, 'Mars', verticalalignment='top')
        self.text_sun = self.ax.text(0, 0, 'Sonne', verticalalignment='top')

        self.ax.add_artist(self.earth)
        self.ax.add_artist(self.mars)
        self.ax.add_artist(self.sun)

        self.ax.add_artist(self.text_rocket)
        self.ax.add_artist(self.text_earth)
        self.ax.add_artist(self.text_mars)
        self.ax.add_artist(self.text_sun)

        self.ax_time.add_artist(self.text_time)

        self.button_run = Button(self.ax_button,
                                 'Start',
                                 color='g',
                                 hovercolor='g')
        self.button_run.on_clicked(self.callback_button_run)

        #self.fig.canvas.mpl_connect('motion_notify_event', self.axes_enter)
        #self.fig.canvas.mpl_connect('resize_event', self.axes_enter)
        self.fig.canvas.mpl_connect('key_press_event', self.handleKeys)

        self.ax.set_aspect('equal')

        self.speed = 10
        self.myframe = 0

        self.anim_running = False
        self.anim = None
        self.redraw = False

    def init_func(self):
        print("init function")
        # initialize plot data
        self.line_rocket.set_data([], [])
        self.line_earth.set_data([], [])
        self.line_mars.set_data([], [])
        self.point_rocket.set_data([], [])

        self.earth.center = (0, 0)
        self.mars.center = (0, 0)
        self.sun.center = (0, 0)

        self.text_rocket.set_text('')
        self.text_earth.set_text('')
        self.text_mars.set_text('')
        self.text_sun.set_text('')
        self.text_time.set_text('')
        self.text_vel_rocket.set_text('')
        self.text_vel_mars.set_text('')
        self.victory_text.set_text('')
        self.text_level.set_text('')

        return self.line_rocket, self.line_earth, self.line_mars, self.point_rocket, self.earth, self.mars, self.sun, \
               self.text_rocket, self.text_earth, self.text_mars, self.text_sun, self.text_time, self.text_vel_rocket, \
               self.text_vel_mars, self.victory_text, self.text_level

    def update_func(self, frame):
        if self.anim_running:
            self.myframe = min(self.myframe, len(self.Ts) - 1)

            self.text_rocket.set_text('Rakete')
            self.text_earth.set_text('Erde')
            self.text_mars.set_text('Mars')
            self.text_sun.set_text('Sonne')

            # update plot data for rocket
            pos_rocket = self.Xs[self.myframe, 0:2]
            self.rocket_x.append(pos_rocket[0])
            self.rocket_y.append(pos_rocket[1])
            self.line_rocket.set_data(self.rocket_x, self.rocket_y)
            self.point_rocket.set_data(pos_rocket[0], pos_rocket[1])
            self.text_rocket.set_position(pos_rocket)

            # update plot data for earth
            pos_earth = self.Xs[self.myframe, 4:6]
            self.earth_x.append(pos_earth[0])
            self.earth_y.append(pos_earth[1])
            self.line_earth.set_data(self.earth_x, self.earth_y)
            self.earth.center = pos_earth
            self.text_earth.set_position(pos_earth)

            # update plot data for mars
            pos_mars = self.Xs[self.myframe, 8:10]
            self.mars_x.append(pos_mars[0])
            self.mars_y.append(pos_mars[1])
            self.line_mars.set_data(self.mars_x, self.mars_y)
            self.mars.center = pos_mars
            self.text_mars.set_position(pos_mars)

            # update displayed texts
            t = self.Ts[self.myframe]
            vel_rocket = self.Xs[self.myframe][2:4]
            vel_mars = self.Xs[self.myframe][10:12]
            self.text_time.set_text('t = {:6.0f} s'.format(t))
            self.text_vel_rocket.set_text('v_R = ({:6.0f}, {:6.0f})'.format(
                vel_rocket[0], vel_rocket[1]))
            self.text_vel_mars.set_text('v_M = ({:6.0f}, {:6.0f})'.format(
                vel_mars[0], vel_mars[1]))
            self.text_level.set_text('Level {}'.format(self.difficulty))

            # check victory conditions
            dist_rocket_mars = np.linalg.norm(
                np.array(pos_rocket) - np.array(pos_mars))
            vel_dist_rocket_mars = np.linalg.norm(
                np.array(vel_rocket) - np.array(vel_mars))
            self.check_victory(dist_rocket_mars, vel_dist_rocket_mars)

            self.myframe += max(1, self.speed * self.speed)
        else:
            # do nothing
            pass

        return self.line_rocket, self.line_earth, self.line_mars, self.point_rocket, self.earth, self.mars, self.sun, \
               self.text_rocket, self.text_earth, self.text_mars, self.text_sun, self.text_time, self.text_vel_rocket, \
               self.text_vel_mars, self.victory_text, self.text_level

    def check_victory(self, dist, vel_dist):
        victory = False
        if self.difficulty == 1:
            if dist < 0.05 * self.pd.AE:
                victory = True
        elif self.difficulty == 2:
            if dist < 0.005 * self.pd.AE:
                victory = True
        elif self.difficulty == 3:
            if dist <= 3.0e9 and vel_dist <= 1.0e3:
                victory = True
                print("Orbit achieved!")

        if victory == True:
            # display information
            # time, energy, dist, delta_v
            self.text_vel_mars.set_text('')
            self.text_vel_rocket.set_text('')

            days = self.Ts[self.myframe] / (60.0 * 60.0 * 24.0)
            dist = dist / 1000.0
            energy = 0.0
            for k in self.commands.keys():
                if self.commands[k] is not None:
                    energy += self.commands[k][1] * self.commands[k][3]**2
            text = 'Mars erreicht!\n\n Zeit (d): {:6.2f} \n Abstand (km): {:6.2f} \n Delta v (m/s): {:6.2f} \n ' \
                   'Treibstoffverbrauch: {:6.2f}'.format(days, dist, vel_dist, energy)
            self.victory_text.set_text(text)

            self.anim_running = False
            #self.redraw = True
            #self.anim.event_source.stop()

        else:
            self.victory_text.set_text('')

    def submit_command(self, i, text):
        # TODO check text
        text = text.replace(',', '.')
        data = np.fromstring(text, sep=' ')
        if self.check_data(data, i) == True:
            print("good data")
            print("data = {}".format(data))
            self.commands[i] = data
        else:
            print("invalid data")
            self.commands[i] = None

    def check_data(self, data, i):
        if len(data) != 4:
            return False
        if data[0] < 0 or data[0] > self.tf or data[
                1] <= 0.0 or data[0] + data[1] > self.tf:
            return False
        # check if time point is too early
        for j in range(0, i):
            if self.commands[j] is not None:
                if self.commands[j][0] + self.commands[j][1] > data[0]:
                    return False
        # check if duration is too long
        for j in range(i + 1, len(self.commands.keys())):
            if self.commands[j] is not None:
                if data[0] + data[1] > self.commands[j][0]:
                    return False
        return True

    def submit_delta_t_mars(self, text):
        # TODO check text
        text = text.replace(',', '.')
        self.delta_t_mars = float(text)

    def callback_button_run(self, event):
        self.reset()
        print("Button pressed -> rerun simulation")

    def onClick(self, event):
        print("Click Event!")

    def handleKeys(self, event):
        if event.key == 'down':
            if self.anim_running:
                self.anim_running = False
            else:
                self.anim_running = True

        difficulty_old = self.difficulty

        # control simulation speed
        if event.key == '-':
            self.speed -= 1
            self.speed = max(self.speed, 1)
            print("speed = {}".format(self.speed))
        elif event.key == '+':
            self.speed += 1
            print("speed = {}".format(self.speed))
        elif event.key == 'ctrl+l':
            print("autosolve")
            self.auto_solve()
        elif event.key == 'ctrl+1':
            self.difficulty = 1
        elif event.key == 'ctrl+2':
            self.difficulty = 2
        elif event.key == 'ctrl+3':
            self.difficulty = 3

        difficulty_changed = (self.difficulty != difficulty_old)
        if difficulty_changed:
            if self.difficulty == 1:
                self.mars.width = 0.1 * self.pd.AE
                self.mars.height = 0.1 * self.pd.AE
                self.earth.width = 0.1 * self.pd.AE
                self.earth.height = 0.1 * self.pd.AE
            elif self.difficulty == 2:
                self.mars.width = 0.01 * self.pd.AE
                self.mars.height = 0.01 * self.pd.AE
                self.earth.width = 0.01 * self.pd.AE
                self.earth.height = 0.01 * self.pd.AE
            elif self.difficulty > 2:
                self.mars.width = 6800.0e3
                self.mars.height = 6800.0e3
                self.earth.width = 12742.0e3
                self.earth.height = 12742.0e3

    def auto_solve(self):
        # reset to get a clean state
        if self.commands[0] is not None:
            for i in range(1, len(self.commands.keys())):
                self.commands[i] = None
            self.delta_t_mars = 0.0
            self.reset()

        # TODO set correct bounds
        samples_r = self.Xs[2000:-1:5000, 0:2]
        samples_m = self.Xs[2000:-1:5000, 8:10]

        scaling = np.max([np.abs(samples_r), np.abs(samples_m)])
        samples_r_scaled = samples_r / scaling
        samples_m_scaled = samples_m / scaling

        # ellipse equation: a x^2 + b xy + c y^2 + d x + e y + f = 0
        er_params_scaled, er_center_scaled, er_angle_scaled, er_axis_scaled = ellipse_helpers.compute_ellipse_params(
            samples_r_scaled)
        em_params_scaled, em_center_scaled, em_angle_scaled, em_axis_scaled = ellipse_helpers.compute_ellipse_params(
            samples_m_scaled)

        sol_scaled = ellipse_helpers.ellipse_intersection(
            er_params_scaled, em_params_scaled, self.Xs[0, 0:2] / scaling)
        sol = sol_scaled * scaling

        # find out intersection time of rocket with point
        T_intersect_rocket_index = np.argmin(
            np.linalg.norm(self.Xs[:, 0:2] - sol, axis=1))
        T_intersect_rocket = self.Ts[T_intersect_rocket_index]

        # find out intersection time of rocket with point
        T_intersect_mars_index = np.argmin(
            np.linalg.norm(self.Xs[:, 8:10] - sol, axis=1))
        T_intersect_mars = self.Ts[T_intersect_mars_index]

        self.delta_t_mars = T_intersect_mars - T_intersect_rocket

        vel_rocket = self.Xs[T_intersect_rocket_index, 2:4]
        vel_mars = self.Xs[T_intersect_mars_index, 10:12]
        delta_v = vel_mars - vel_rocket
        delta_v_norm = delta_v / np.linalg.norm(delta_v)
        e1 = np.array([1.0, 0.0])
        w_des = np.arccos(np.dot(delta_v_norm, e1))
        if delta_v_norm[1] < 0.0:
            # if vector points down in the y-component we have to adjust the angle such that it is mathematically positive
            w_des = 2.0 * np.pi - w_des

        a_des = delta_v / 1200.0
        u_des = a_des[0] / np.cos(w_des)
        w_des = w_des * 360.0 / (2.0 * np.pi)

        self.commands[1] = np.array([T_intersect_rocket, 1200.0, w_des, u_des])

        new_text = "{:6.0f} {:6.2f} {:6.2f} {:6.2f}".format(
            self.commands[1][0], self.commands[1][1], self.commands[1][2],
            self.commands[1][3])
        self.command_text_boxes[1].set_val(new_text)

        new_time_mars = "{:6.0f} ".format(self.delta_t_mars)
        self.delta_t_mars_text_box.set_val(new_time_mars)

    def reset(self):
        if self.anim_running == True:
            self.anim.event_source.stop()

        self.rocket_x = []
        self.rocket_y = []

        self.mars_x = []
        self.mars_y = []

        self.earth_x = []
        self.earth_y = []

        if self.delta_t_mars != 0.0:
            x_temp = self.simulator.run_simulation_planets(self.delta_t_mars)
            self.simulator.set_mars_position(x_temp[4:8])
        else:
            self.simulator.reset_mars_position()

        commands_clean = self.clean_commands()
        self.Ts, self.Xs = self.simulator.run_simulation(
            commands_clean, self.tf)

        self.myframe = 0
        self.anim_running = True
        self.anim.event_source.start()

    def clean_commands(self):
        commands_clean = None
        for i in range(0, len(self.commands.keys())):
            if self.commands[i] is not None:
                c = np.copy(self.commands[i])
                c[2] = c[2] / 360.0 * 2.0 * np.pi  # convert to rad

                if commands_clean is None:
                    commands_clean = np.array([c])
                else:
                    commands_clean = np.vstack((commands_clean, c))
        return commands_clean

    def main_loop(self):
        commands_clean = self.clean_commands()
        self.Ts, self.Xs = self.simulator.run_simulation(
            commands_clean, self.tf)

        self.anim_running = True
        self.anim = animation.FuncAnimation(self.fig,
                                            self.update_func,
                                            frames=100000000000000,
                                            interval=10,
                                            blit=True,
                                            init_func=self.init_func)
        plt.show()
Esempio n. 18
0
def __spincam_gui():

    # Get figure
    fig = plt.figure()

    # Set position params
    padding = 0.01
    options_height = 0.02
    num_options = 6
    cam_plot_height_offset = num_options * options_height + num_options * padding
    cam_plot_width = 0.75
    cam_plot_height = 1 - cam_plot_height_offset

    #cid = fig.canvas.mpl_connect('button_press_event', onclick)

    # Display Camera Image
    display_pos = [0, cam_plot_height_offset, cam_plot_width, cam_plot_height]
    display_dict = __cam_plot(fig, display_pos, 'Camera', options_height,
                              padding)
    # Set initial values
    # Set callbacks
    display_dict['find_and_init_button'].on_clicked(__find_and_init_cam)

    stage_pos = [cam_plot_width, cam_plot_height_offset, 0.25, cam_plot_height]

    # Creates stage controls
    but_width = options_height * 2
    but_height = options_height * 3

    red_but_pos = [
        display_pos[0] + display_pos[3] - 4 * padding,
        display_pos[1] + display_pos[3] - 2 * padding - but_height, but_width,
        options_height * 2
    ]
    red_but_axes = fig.add_axes(red_but_pos)
    red_but = Button(red_but_axes, 'R')
    red_but.label.set_fontsize(7)

    yellow_but_pos = [
        red_but_pos[0] + padding + but_width, red_but_pos[1], but_width,
        options_height * 2
    ]
    yellow_but_axes = fig.add_axes(yellow_but_pos)
    yellow_but = Button(yellow_but_axes, 'Y')
    yellow_but.label.set_fontsize(7)

    green_but_pos = [
        yellow_but_pos[0] + padding + but_width, yellow_but_pos[1], but_width,
        options_height * 2
    ]
    green_but_axes = fig.add_axes(green_but_pos)
    green_but = Button(green_but_axes, 'G')
    green_but.label.set_fontsize(7)

    blue_but_pos = [
        green_but_pos[0] + padding + but_width, green_but_pos[1], but_width,
        options_height * 2
    ]
    blue_but_axes = fig.add_axes(blue_but_pos)
    blue_but = Button(blue_but_axes, 'B')
    blue_but.label.set_fontsize(7)

    b_text_pos = [
        red_but_pos[0], display_pos[3] - padding - but_height, 0.1,
        options_height * 2
    ]
    b_text_axes = fig.add_axes(b_text_pos)
    b_text = TextBox(b_text_axes, 'bval')
    b_text.label.set_fontsize(7)
    b_text.set_val(1)

    g_text_pos = [
        red_but_pos[0], display_pos[3] - 10 * padding - but_height, 0.1,
        options_height * 2
    ]
    g_text_axes = fig.add_axes(g_text_pos)
    g_text = TextBox(g_text_axes, 'gval')
    g_text.label.set_fontsize(7)
    g_text.set_val(1)

    red_but.on_clicked(__ledr)
    yellow_but.on_clicked(__ledy)
    blue_but.on_clicked(__ledb)
    green_but.on_clicked(__ledg)
    b_text.on_submit(__b_text)
    g_text.on_submit(__g_text)

    # Start stream
    start_stream_button_pos = [
        padding, display_pos[1] - options_height, 0.5 - 2 * padding,
        options_height
    ]
    start_stream_button_axes = fig.add_axes(start_stream_button_pos)
    start_stream_button = Button(start_stream_button_axes, 'Start Stream')
    start_stream_button.label.set_fontsize(7)

    # Set callback
    start_stream_button.on_clicked(__start_stream)

    # Stop stream
    stop_stream_button_pos = [
        start_stream_button_pos[0] + start_stream_button_pos[2] + 2 * padding,
        display_pos[1] - options_height, 0.5 - 2 * padding, options_height
    ]
    stop_stream_button_axes = fig.add_axes(stop_stream_button_pos)
    stop_stream_button = Button(stop_stream_button_axes, 'Stop Stream')
    stop_stream_button.label.set_fontsize(7)

    # Set callback
    stop_stream_button.on_clicked(__stop_stream)

    # fps
    fps_pos = [
        0, start_stream_button_pos[1] - options_height - padding, 1,
        options_height
    ]
    (fps_slider, fps_text) = __slider_with_text(fig, fps_pos, 'FPS', __FPS_MIN,
                                                __FPS_MAX, __FPS_MIN, padding)
    # Set callbacks
    fps_slider.on_changed(__fps_slider)
    fps_text.on_submit(__fps_text)

    # Exposure
    exposure_pos = [
        0, fps_pos[1] - options_height - padding, 1, options_height
    ]
    (exposure_slider,
     exposure_text) = __slider_with_text(fig, exposure_pos, 'Exposure',
                                         __EXPOSURE_MIN, __EXPOSURE_MAX,
                                         __EXPOSURE_MIN, padding)
    # Set callbacks
    exposure_slider.on_changed(__exposure_slider)
    exposure_text.on_submit(__exposure_text)

    #Set default directory to current
    directory_pos = [
        padding, exposure_pos[1] - options_height - padding,
        0.75 - 2 * padding, options_height
    ]
    directory_axes = fig.add_axes(directory_pos)
    directory_text = TextBox(directory_axes, 'Directory')
    directory_text.label.set_fontsize(7)
    directory_text.set_val('')

    directory_button_pos = [
        directory_pos[0] + directory_pos[2] + padding, directory_pos[1],
        0.25 - 2 * padding, options_height
    ]
    directory_button_axes = fig.add_axes(directory_button_pos)
    directory_button = Button(directory_button_axes, 'Choose Directory')
    directory_button.label.set_fontsize(7)

    directory_button.on_clicked(__choose_directory)

    # Set name format
    name_format_pos = [(0.5 - 2 * padding) * 0.1875 + 2 * padding,
                       directory_pos[1] - options_height - padding,
                       (0.5 - 2 * padding) * 0.8125 - padding, options_height]
    name_format_axes = fig.add_axes(name_format_pos)
    name_format_text = TextBox(name_format_axes, 'Name format')
    name_format_text.label.set_fontsize(7)
    name_format_text.set_val('test_{date}')

    # Set save primary button
    save_button_pos = [
        padding, name_format_pos[1] - options_height - padding,
        (0.5 - 4 * padding) / 3, options_height
    ]
    save_button_axes = fig.add_axes(save_button_pos)
    save_button = Button(save_button_axes, 'Start Acquisition')
    save_button.label.set_fontsize(7)
    # Set callback
    save_button.on_clicked(__save_images)

    # Set num images text
    num_images_text_pos = [
        cam_plot_width - 20 * padding, padding, 0.1 - 2 * padding,
        options_height
    ]
    num_images_text_axes = fig.add_axes(num_images_text_pos)
    num_images_text = TextBox(num_images_text_axes, '# to Acquire')
    num_images_text.label.set_fontsize(7)
    num_images_text.set_val(1)

    # Set num images text
    time_images_text_pos = [
        0.75, directory_pos[1] - options_height - padding, 0.125,
        options_height
    ]
    time_images_text_axes = fig.add_axes(time_images_text_pos)
    time_images_text = TextBox(time_images_text_axes,
                               'Time between frames (s)')
    time_images_text.label.set_fontsize(7)
    time_images_text.set_val(0)

    # Set num images text
    avg_images_text_pos = [
        save_button_pos[0] + save_button_pos[2] + padding +
        (0.5 - 2 * padding) * 0.1875 + 2 * padding,
        name_format_pos[1] - options_height - padding,
        (0.2 - 2 * padding) * 0.8125 - padding, options_height
    ]
    avg_images_text_axes = fig.add_axes(avg_images_text_pos)
    avg_images_text = TextBox(avg_images_text_axes, '# to Avg')
    avg_images_text.label.set_fontsize(7)
    avg_images_text.set_val(10)

    # Set save primary button
    bulk_button_pos = [
        num_images_text_pos[0] + num_images_text_pos[2] + padding,
        name_format_pos[1] - options_height - padding,
        (0.2 - 2 * padding) * 0.8125 - padding, options_height
    ]
    bulk_button_axes = fig.add_axes(bulk_button_pos)
    bulk_button = Button(bulk_button_axes, 'Zero Bulk')
    bulk_button.label.set_fontsize(7)
    # Set callback
    bulk_button.on_clicked(__bulk_save)

    return {
        'fig': fig,
        'display_dict': display_dict,
        'start_stream_button': start_stream_button,
        'stop_stream_button': stop_stream_button,
        'save_button': save_button,
        'name_format_text': name_format_text,
        'num_images_text': num_images_text,
        'avg_images_text': avg_images_text,
        'fps_slider': fps_slider,
        'fps_text': fps_text,
        'exposure_slider': exposure_slider,
        'exposure_text': exposure_text,
        'time_images_text': time_images_text,
        'directory_text': directory_text,
        'directory_button': directory_button,
        'bulk_button': bulk_button,
        'red_but': red_but,
        'yellow_but': yellow_but,
        'green_but': green_but,
        'blue_but': blue_but,
        'b_text': b_text,
        'g_text': g_text
    }
def __stage_gui(fig2):

    # Creates stage controls
    options_height = 0.02
    padding = 0.01
    but_width = options_height * 2
    but_height = options_height * 3

    pos = [0, 0, 1, 1]

    up_button_pos1 = [
        pos[0] + 0.125 - options_height,
        pos[1] + pos[3] - 2 * padding - but_height, but_width, but_height
    ]
    up_button_axes1 = fig2.add_axes(up_button_pos1)
    up_button1 = Button(up_button_axes1, '++y')
    up_button1.label.set_fontsize(7)
    up_button1.on_clicked(__go_up_plus)

    up_button_pos2 = [
        pos[0] + 0.125 - options_height, up_button_pos1[1] - but_height,
        but_width, but_height
    ]
    up_button_axes2 = fig2.add_axes(up_button_pos2)
    up_button2 = Button(up_button_axes2, '+y')
    up_button2.label.set_fontsize(7)
    up_button2.on_clicked(__go_up)

    down_button_pos1 = [
        pos[0] + 0.125 - options_height, up_button_pos2[1] - 2 * but_height,
        but_width, but_height
    ]
    down_button_axes1 = fig2.add_axes(down_button_pos1)
    down_button1 = Button(down_button_axes1, '-y')
    down_button1.label.set_fontsize(7)
    down_button1.on_clicked(__go_down)

    down_button_pos2 = [
        pos[0] + 0.125 - options_height, down_button_pos1[1] - but_height,
        but_width, but_height
    ]
    down_button_axes2 = fig2.add_axes(down_button_pos2)
    down_button2 = Button(down_button_axes2, '--y')
    down_button2.label.set_fontsize(7)
    down_button2.on_clicked(__go_down_plus)

    left_button_pos1 = [
        pos[0] + 0.125 - options_height - but_width,
        down_button_pos1[1] + but_height, but_width, but_height
    ]
    left_button_axes1 = fig2.add_axes(left_button_pos1)
    left_button1 = Button(left_button_axes1, '-x')
    left_button1.label.set_fontsize(7)
    left_button1.on_clicked(__go_left)

    left_button_pos2 = [
        pos[0] + 0.125 - options_height - 2 * but_width,
        down_button_pos1[1] + but_height, but_width, but_height
    ]
    left_button_axes2 = fig2.add_axes(left_button_pos2)
    left_button2 = Button(left_button_axes2, '--x')
    left_button2.label.set_fontsize(7)
    left_button2.on_clicked(__go_left_plus)

    right_button_pos1 = [
        pos[0] + 0.125 - options_height + but_width, left_button_pos1[1],
        but_width, but_height
    ]
    right_button_axes1 = fig2.add_axes(right_button_pos1)
    right_button1 = Button(right_button_axes1, '+x')
    right_button1.label.set_fontsize(7)
    right_button1.on_clicked(__go_right)

    right_button_pos2 = [
        pos[0] + 0.125 - options_height + 2 * but_width, left_button_pos1[1],
        but_width, but_height
    ]
    right_button_axes2 = fig2.add_axes(right_button_pos2)
    right_button2 = Button(right_button_axes2, '++x')
    right_button2.label.set_fontsize(7)
    right_button2.on_clicked(__go_right_plus)

    # current position
    x_pos_but_pos = [
        up_button_pos1[0] + 6 * padding,
        down_button_pos2[1] - 2 * padding - options_height * 2,
        0.1 - 2 * padding, options_height * 2
    ]
    x_pos_but_axes = fig2.add_axes(x_pos_but_pos)
    x_pos_but = TextBox(x_pos_but_axes, 'current x pos.')
    x_pos_but.label.set_fontsize(7)
    x_pos_but.set_val(1)
    x_pos_but.on_submit(__update_pos_x)

    # current position
    y_pos_but_pos = [
        up_button_pos1[0] + 6 * padding,
        x_pos_but_pos[1] - 2 * padding - options_height * 2, 0.1 - 2 * padding,
        options_height * 2
    ]
    y_pos_but_axes = fig2.add_axes(y_pos_but_pos)
    y_pos_but = TextBox(y_pos_but_axes, 'current y pos.')
    y_pos_but.label.set_fontsize(7)
    y_pos_but.set_val(1)
    y_pos_but.on_submit(__update_pos_y)

    # Set x-y step size
    xy_step_text_pos1 = [
        up_button_pos1[0] + 6 * padding,
        y_pos_but_pos[1] - 2 * padding - options_height * 2, 0.1 - 2 * padding,
        options_height * 2
    ]
    xy_step_text_axes1 = fig2.add_axes(xy_step_text_pos1)
    xy_step_text1 = TextBox(xy_step_text_axes1, '+ xy step size (um)')
    xy_step_text1.label.set_fontsize(7)
    xy_step_text1.set_val(__XY_STEP)
    xy_step_text1.on_submit(__xy_step)

    # Set x-y step size
    xy_step_text_pos2 = [
        up_button_pos1[0] + 6 * padding,
        xy_step_text_pos1[1] - 2 * padding - options_height * 2,
        0.1 - 2 * padding, options_height * 2
    ]
    xy_step_text_axes2 = fig2.add_axes(xy_step_text_pos2)
    xy_step_text2 = TextBox(xy_step_text_axes2, '++ xy step size (um)')
    xy_step_text2.label.set_fontsize(7)
    xy_step_text2.set_val(__XY_STEP_PLUS)
    xy_step_text2.on_submit(__xy_step_plus)

    z_up_button_pos1 = [
        up_button_pos1[0] + 8 * but_width, up_button_pos1[1], but_width,
        but_height
    ]
    z_up_button_axes1 = fig2.add_axes(z_up_button_pos1)
    z_up_button1 = Button(z_up_button_axes1, '++z')
    z_up_button1.label.set_fontsize(7)
    z_up_button1.on_clicked(__go_defocus_up_plus)

    z_up_button_pos2 = [
        z_up_button_pos1[0], up_button_pos2[1], but_width, but_height
    ]
    z_up_button_axes2 = fig2.add_axes(z_up_button_pos2)
    z_up_button2 = Button(z_up_button_axes2, '+ z')
    z_up_button2.label.set_fontsize(7)
    z_up_button2.on_clicked(__go_defocus_up)

    z_down_button_pos1 = [
        z_up_button_pos2[0], z_up_button_pos2[1] - 2 * but_height, but_width,
        but_height
    ]
    z_down_button_axes1 = fig2.add_axes(z_down_button_pos1)
    z_down_button1 = Button(z_down_button_axes1, '- z')
    z_down_button1.label.set_fontsize(7)
    z_down_button1.on_clicked(__go_defocus_down)

    z_down_button_pos2 = [
        z_up_button_pos2[0], z_down_button_pos1[1] - but_height, but_width,
        but_height
    ]
    z_down_button_axes2 = fig2.add_axes(z_down_button_pos2)
    z_down_button2 = Button(z_down_button_axes2, '-- z')
    z_down_button2.label.set_fontsize(7)
    z_down_button2.on_clicked(__go_defocus_down_plus)

    # current position
    z_pos_but_pos = [
        z_down_button_pos2[0] + but_width * 2,
        z_down_button_pos2[1] - 2 * padding - options_height * 2,
        0.1 - 2 * padding, options_height * 2
    ]
    z_pos_but_axes = fig2.add_axes(z_pos_but_pos)
    z_pos_but = TextBox(z_pos_but_axes, 'current z pos.')
    z_pos_but.label.set_fontsize(7)
    z_pos_but.set_val(1)
    z_pos_but.on_submit(__update_pos_z)

    # Set z step size
    z_step_text_pos1 = [
        z_pos_but_pos[0], z_pos_but_pos[1] - 2 * padding - options_height * 2,
        0.1 - 2 * padding, options_height * 2
    ]
    z_step_text_axes1 = fig2.add_axes(z_step_text_pos1)
    z_step_text1 = TextBox(z_step_text_axes1, '+ z step size (um)')
    z_step_text1.label.set_fontsize(7)
    z_step_text1.set_val(__Z_STEP)
    z_step_text1.on_submit(__z_step)

    # Set z step size
    z_step_text_pos2 = [
        z_pos_but_pos[0],
        z_step_text_pos1[1] - 2 * padding - options_height * 2,
        0.1 - 2 * padding, options_height * 2
    ]
    z_step_text_axes2 = fig2.add_axes(z_step_text_pos2)
    z_step_text2 = TextBox(z_step_text_axes2, '++ z step size (um)')
    z_step_text2.label.set_fontsize(7)
    z_step_text2.set_val(__Z_STEP_PLUS)
    z_step_text2.on_submit(__z_step_plus)

    # num of steps
    step_num_text_pos = [
        z_pos_but_pos[0],
        z_step_text_pos2[1] - 2 * padding - options_height * 2,
        0.1 - 2 * padding, options_height * 2
    ]
    step_num_text_axes = fig2.add_axes(step_num_text_pos)
    step_num_text = TextBox(step_num_text_axes, '# of steps (radius)')
    step_num_text.label.set_fontsize(7)
    step_num_text.set_val(1)
    step_num_text.on_submit(__number_defocus)

    # z interval
    z_interval_text_pos = [
        z_pos_but_pos[0],
        step_num_text_pos[1] - 2 * padding - options_height * 2,
        0.1 - 2 * padding, options_height * 2
    ]
    z_interval_text_axes = fig2.add_axes(z_interval_text_pos)
    z_interval_text = TextBox(z_interval_text_axes, 'defocus interval (um)')
    z_interval_text.label.set_fontsize(7)
    z_interval_text.set_val(1)
    z_interval_text.on_submit(__test)

    # time btwn z stacks
    time_btwn_z_text_pos = [
        z_pos_but_pos[0],
        z_interval_text_pos[1] - 2 * padding - options_height * 2,
        0.1 - 2 * padding, options_height * 2
    ]
    time_btwn_z_text_axes = fig2.add_axes(time_btwn_z_text_pos)
    time_btwn_z_text = TextBox(time_btwn_z_text_axes, 'time between z stacks')
    time_btwn_z_text.label.set_fontsize(7)
    time_btwn_z_text.set_val(30)
    time_btwn_z_text.on_submit(__time_int_def)

    z_acquire_but_pos = [
        pos[0] + 3 * padding,
        time_btwn_z_text_pos[1] - 2 * padding - options_height * 2, 0.55,
        options_height * 2
    ]
    z_acquire_but_axes = fig2.add_axes(z_acquire_but_pos)
    z_acquire_but = Button(z_acquire_but_axes, 'Start defocus acquisition(s)')
    z_acquire_but.label.set_fontsize(7)
    z_acquire_but.on_clicked(__defocus_acquisition)

    led_but_width = but_width * 2

    red_but_pos = [
        pos[0] + 4 * padding,
        z_acquire_but_pos[1] - 2 * padding - options_height * 2, led_but_width,
        options_height * 2
    ]
    red_but_axes = fig2.add_axes(red_but_pos)
    red_but = Button(red_but_axes, 'R')
    red_but.label.set_fontsize(7)
    red_but.on_clicked(__ledr)

    yellow_but_pos = [
        red_but_pos[0] + 7 * padding + but_width, red_but_pos[1],
        led_but_width, options_height * 2
    ]
    yellow_but_axes = fig2.add_axes(yellow_but_pos)
    yellow_but = Button(yellow_but_axes, 'Y')
    yellow_but.label.set_fontsize(7)
    yellow_but.on_clicked(__ledy)

    green_but_pos = [
        yellow_but_pos[0] + 7 * padding + but_width, yellow_but_pos[1],
        led_but_width, options_height * 2
    ]
    green_but_axes = fig2.add_axes(green_but_pos)
    green_but = Button(green_but_axes, 'G')
    green_but.label.set_fontsize(7)
    green_but.on_clicked(__ledg)

    blue_but_pos = [
        green_but_pos[0] + 7 * padding + but_width, green_but_pos[1],
        led_but_width, options_height * 2
    ]
    blue_but_axes = fig2.add_axes(blue_but_pos)
    blue_but = Button(blue_but_axes, 'B')
    blue_but.label.set_fontsize(7)
    blue_but.on_clicked(__ledb)

    off_but_pos = [
        blue_but_pos[0] + 7 * padding + but_width, blue_but_pos[1],
        led_but_width, options_height * 2
    ]
    off_but_axes = fig2.add_axes(off_but_pos)
    off_but = Button(off_but_axes, 'OFF')
    off_but.label.set_fontsize(7)
    off_but.on_clicked(__ledc)

    return {
        'fig2': fig2,
        'up_button1': up_button1,
        'down_button1': down_button1,
        'left_button1': left_button1,
        'right_button1': right_button1,
        'up_button2': up_button2,
        'down_button2': down_button2,
        'left_button2': left_button2,
        'right_button2': right_button2,
        'z_up_button1': z_up_button1,
        'z_down_button1': z_down_button1,
        'z_up_button2': z_up_button2,
        'z_down_button2': z_down_button2,
        'x_pos_but': x_pos_but,
        'y_pos_but': y_pos_but,
        'z_pos_but': z_pos_but,
        'xy_step_text1': xy_step_text1,
        'xy_step_text2': xy_step_text2,
        'z_step_text1': z_step_text1,
        'z_step_text2': z_step_text2,
        'step_num_text': step_num_text,
        'z_interval_text': z_interval_text,
        'time_btwn_z_text': time_btwn_z_text,
        'z_acquire_but': z_acquire_but,
        'red_but': red_but,
        'yellow_but': yellow_but,
        'green_but': green_but,
        'blue_but': blue_but,
        'off_but': off_but
    }
Esempio n. 20
0
class GUI():
    def __init__(self):
        self.axcolor = 'lightgrey'
        self.fig = plt.figure(figsize=(8, 6))
        self.updating_status = False
        self.main()

    def main(self):
        self.calc_infos()
        self.init_figure()
        self.init_control_zone()
        self.init_result_zone()
        self.add_events()
        plt.show()

    def calc_infos(self, algorithm=0):
        self.t_r2, self.s, self.Q, self.x_bias, self.y_bias, self.RMSE, self.W_p, self.rac_u_p, self.s_p, self.t_r2_p, self.T, self.S = run_AutoFit(
            algorithm)

    def init_figure(self):
        ######## Plot Zone ########
        ax = self.fig.add_subplot(1, 1, 1)
        plt.subplots_adjust(bottom=0.42, left=0.18, right=0.65)

        rec_u, W_std = W_u_std(1e-8, 10, 0.01)
        self.l, = plt.plot(self.t_r2 + self.x_bias,
                           self.s + self.y_bias,
                           's',
                           color='maroon',
                           markersize=5,
                           label='measurement data')
        plt.plot(rec_u,
                 W_std,
                 color='k',
                 linewidth=0.85,
                 label='theis type-curve')
        plt.xlabel(r'lg$(\frac{1}{u})$ ', fontsize=10)
        plt.ylabel(r'lg$(W)$', fontsize=10)
        plt.xlim(
            np.min(self.t_r2 + self.x_bias) - 1,
            np.max(self.t_r2 + self.x_bias) + 1)
        plt.ylim(
            np.min(self.s + self.y_bias) - 1,
            np.max(self.s + self.y_bias) + 0.5)
        plt.grid(True, ls='--', lw=.5, c='k', alpha=0.6)
        plt.legend(fontsize=8)
        plt.suptitle("Theis Type-curve Fitting")

    def init_control_zone(self):
        ######## Control Zone ########
        contrl_ax = plt.axes([0.05, 0.05, 0.90, 0.27])
        plt.text(0.035, 0.85, 'Control Zone')
        contrl_ax.set_xticks([])
        contrl_ax.set_yticks([])

        # slider
        ax_xbias = plt.axes([0.14, 0.21, 0.35, 0.03], facecolor=self.axcolor)
        ax_ybias = plt.axes([0.14, 0.16, 0.35, 0.03], facecolor=self.axcolor)

        self.s_xbias = Slider(ax_xbias, 'x_bias', 0.0, 5, valinit=self.x_bias)
        self.s_ybias = Slider(ax_ybias, 'y_bias', 0.0, 5, valinit=self.y_bias)

        # buttons
        aftax = plt.axes([0.8, 0.06, 0.1, 0.04])
        self.reset_button = Button(aftax,
                                   'RESET',
                                   color=self.axcolor,
                                   hovercolor='mistyrose')

        x_bias_dec_tax = plt.axes([0.57, 0.21, 0.03, 0.03])
        self.x_bias_dec_button = Button(x_bias_dec_tax,
                                        '-',
                                        color=self.axcolor,
                                        hovercolor='mistyrose')

        x_bias_inc_tax = plt.axes([0.72, 0.21, 0.03, 0.03])
        self.x_bias_inc_button = Button(x_bias_inc_tax,
                                        '+',
                                        color=self.axcolor,
                                        hovercolor='mistyrose')

        y_bias_dec_tax = plt.axes([0.57, 0.16, 0.03, 0.03])
        self.y_bias_dec_button = Button(y_bias_dec_tax,
                                        '-',
                                        color=self.axcolor,
                                        hovercolor='mistyrose')

        y_bias_inc_tax = plt.axes([0.72, 0.16, 0.03, 0.03])
        self.y_bias_inc_button = Button(y_bias_inc_tax,
                                        '+',
                                        color=self.axcolor,
                                        hovercolor='mistyrose')

        # textbox
        xtextax = plt.axes([0.61, 0.21, 0.1, 0.03])
        ytextax = plt.axes([0.61, 0.16, 0.1, 0.03])
        self.t_xbias = TextBox(xtextax, ' ', str(float('%.2f' % self.x_bias)))
        self.t_ybias = TextBox(ytextax, ' ', str(float('%.2f' % self.y_bias)))

        # radio button
        rax = plt.axes([0.78, 0.12, 0.15, 0.17], facecolor=self.axcolor)
        plt.title('AutoFit Algorithms', fontsize=8)
        self.algos = np.array(['Traverse', 'Mass Center', 'Slope'])
        self.radio = RadioButtons(rax, self.algos, active=0)

    def init_result_zone(self, ):
        ######## Result Zone ########
        re_ax = plt.axes([0.70, 0.37, 0.20, 0.50])
        plt.text(0.035, 0.95, 'Results Zone')
        re_ax.set_xticks([])
        re_ax.set_yticks([])

        self.W_l = plt.text(0.2, 0.85, r'$W: %.2f $' % (self.W_p))
        self.u_l = plt.text(0.2, 0.75, r'$1/u: %.2f $' % (self.rac_u_p))
        self.s_l = plt.text(0.2, 0.65, r'$s: %.2f $' % (self.s_p))
        self.tr2_l = plt.text(0.2, 0.55, r'$t/r^2: %.4f $' % (self.t_r2_p))
        self.T_l = plt.text(0.2, 0.45, r'$T: %.2f m^3/d$' % (self.T))
        self.S_l = plt.text(0.2, 0.35, r'$S: %.6f $' % (self.S))
        plt.text(0.035, 0.2, 'Statistics of Fitting')
        self.RMSE_l = plt.text(0.2, 0.1, r'$RMSE: %.4f$' % (self.RMSE))

    def add_events(self):
        self.s_xbias.on_changed(self.update_x)
        self.s_ybias.on_changed(self.update_y)
        self.reset_button.on_clicked(self.reset)
        self.x_bias_dec_button.on_clicked(self.dec_x_bias)
        self.x_bias_inc_button.on_clicked(self.inc_x_bias)
        self.y_bias_dec_button.on_clicked(self.dec_y_bias)
        self.y_bias_inc_button.on_clicked(self.inc_y_bias)
        self.t_xbias.on_submit(self.submit_x)
        self.t_ybias.on_submit(self.submit_y)
        self.radio.on_clicked(self.chg_algorithm)

    def chg_result(self, t_r2, s, x_bias, y_bias):
        """ change the results in the results zone """
        self.W_p, self.rac_u_p, self.s_p, self.t_r2_p, self.T, self.S = calResult(
            self.t_r2, self.s, self.Q, self.x_bias, self.y_bias, num=2)
        self.W_bias = (W(1 / (10**(t_r2 + float('%2f' % x_bias)))))
        self.RMSE = np.sqrt(
            np.mean((self.W_bias - 10**(s + float('%.2f' % y_bias)))**2))

        self.W_l.set_text(r'$W: %.2f $' % (self.W_p))
        self.u_l.set_text(r'$1/u: %.2f $' % (self.rac_u_p))
        self.s_l.set_text(r'$s: %.2f $' % (self.s_p))
        self.tr2_l.set_text(r'$t/r^2: %.4f $' % (self.t_r2_p))
        self.T_l.set_text(r'$T: %.2f m^3/d$' % (self.T))
        self.S_l.set_text(r'$S: %.6f $' % (self.S))
        self.RMSE_l.set_text(r'$RMSE: %.4f$' % (self.RMSE))

    def update_x(self, x_bias):
        """update all widgets with new x_bias"""
        # 防抖
        if self.updating_status:
            return

        x_bias = float('%.2f' % x_bias)
        if x_bias == self.x_bias:
            return

        self.updating_status = True
        self.x_bias = x_bias
        self.s_xbias.set_val(float('%.2f' % self.x_bias))
        self.t_xbias.set_val(float('%.2f' % self.x_bias))
        self.l.set_xdata(self.t_r2 + self.x_bias)

        self.fig.canvas.draw_idle()
        self.chg_result(self.t_r2, self.s, self.x_bias, self.y_bias)
        self.updating_status = False

    def update_y(self, y_bias):
        """update all widgets with new y_bias"""
        # 防抖
        if self.updating_status:
            return

        y_bias = float('%.2f' % y_bias)
        if y_bias == self.y_bias:
            return

        self.updating_status = True
        self.y_bias = y_bias
        self.s_ybias.set_val(float('%.2f' % self.y_bias))
        self.t_ybias.set_val(float('%.2f' % self.y_bias))
        self.l.set_ydata(self.s + self.y_bias)

        self.fig.canvas.draw_idle()
        self.chg_result(self.t_r2, self.s, self.x_bias, self.y_bias)
        self.updating_status = False

    def reset(self, event):
        """ reset the figure """
        self.radio.set_active(0)

    def dec_x_bias(self, event):
        """ decrease the x_bias using '-' button """
        self.update_x(self.x_bias - 0.01)

    def inc_x_bias(self, event):
        """ increase the x_bias using '+' button """
        self.update_x(self.x_bias + 0.01)

    def dec_y_bias(self, event):
        """ decrease the y_bias using '-' button """
        self.update_y(self.y_bias - 0.01)

    def inc_y_bias(self, event):
        """ increase the y_bias using '+' button """
        self.update_y(self.y_bias + 0.01)

    def submit_x(self, text):
        """ updates the figure using textbox (x_bias)"""
        self.update_x(float(text))

    def submit_y(self, text):
        """ updates the figure using textbox (y_bias)"""
        self.update_y(float(text))

    def chg_algorithm(self, label):
        algorithm = np.argwhere(self.algos == label)[0][0]
        # t_r2, s, Q, x_bias, y_bias, RMSE, W_p, rac_u_p, s_p, t_r2_p, T, S = run_AutoFit(algorithm)
        self.calc_infos(algorithm)
        self.update_x(self.x_bias)
        self.update_y(self.y_bias)
Esempio n. 21
0
class Lantern_Cscan_vizualiser(object):
    def __init__(self, fig1, Cscan_LP01, Cscan_LP11):
        self.fig1 = fig1
        self.dCscan_LP01 = np.array(10 * np.log(Cscan_LP01))
        self.dCscan_LP11 = np.array(10 * np.log(Cscan_LP11))

    def update_intensity(self, event):

        self.l_LP11.set_clim(vmin=self.SVmin.val, vmax=self.SVmax.val)
        self.l_LP01.set_clim(vmin=self.SVmin.val, vmax=self.SVmax.val)

        self.fig.canvas.draw_idle()

    def submit(self, text):
        self.N_plot = eval(text)
        self.dBscan = self.dCscan_LP01[:, :, self.N_plot].T

        self.l_LP01.set_data(self.dBscan)
        self.l_LP11.set_data(self.dBscan)

        self.normalize_image()

        self.textbox.set_val(self.N_plot)
        self.fig.canvas.draw_idle()

    def next(self, event):
        self.N_plot += 1

        self.dBscan = self.dCscan_LP01[:, :, self.N_plot].T

        self.normalize_image()

        self.l_LP01.set_data(self.dBscan - np.mean(self.dBscan))
        self.l_LP11.set_data(self.dBscan - np.mean(self.dBscan))
        self.textbox.set_val(self.N_plot)
        self.fig.canvas.draw_idle()

    def normalize_image(self):

        self.dBscan -= np.mean(self.dBscan) - 255 / 2

        self.ax3.cla()
        self.ax3.hist(self.dBscan.ravel(), 255)

        range = max(np.abs(np.max(self.dBscan) - 255 / 2),
                    np.abs(np.min(self.dBscan) - 255 / 2))
        std_range = 3 * np.std(self.dBscan)
        range = 5 * std_range
        print(std_range)

        self.ax3.set_xlim(255 / 2 - range, 255 / 2 + range)

        self.SVmin.valmin = 255 / 2 - range
        self.SVmin.valmax = 255 / 2 + range
        self.SVmax.valmin = 255 / 2 - range
        self.SVmax.valmax = 255 / 2 + range

        self.SVmin.ax.set_xlim(self.SVmin.valmin, self.SVmin.valmax)

        self.SVmax.ax.set_xlim(self.SVmax.valmin, self.SVmax.valmax)

        self.SVmin.val = 255 / 2 - std_range
        self.SVmax.val = 255 / 2 + std_range
        self.SVmax.set_value = 1

        self.l_LP01.set_clim(vmin=255 / 2 - std_range,
                             vmax=255 / 2 + std_range)

        self.l_LP11.set_clim(vmin=255 / 2 - std_range,
                             vmax=255 / 2 + std_range)

    def previous(self, event):
        self.N_plot -= 1

        self.dBscan = self.dCscan_LP01[:, :, self.N_plot].T

        self.normalize_image()

        self.l_LP01.set_data(self.dBscan)
        self.l_LP11.set_data(self.dBscan)

        self.textbox.set_val(self.N_plot)
        self.fig.canvas.draw_idle()

    def save_LP11(self, event):
        save_dir = "results/"
        extent = self.ax2.get_window_extent().transformed(
            self.fig.dpi_scale_trans.inverted())
        plt.savefig(save_dir + "figure_" + 'LP11', bbox_inches=extent)

    def save_LP01(self, event):
        save_dir = "results/"
        extent = self.ax1.get_window_extent().transformed(
            self.fig.dpi_scale_trans.inverted())
        plt.savefig(save_dir + "figure_" + 'LP01', bbox_inches=extent)

    def Bscan_lanterne_plots(self):

        self.fig = plt.figure(figsize=(16, 10))
        gs = gridspec.GridSpec(5, 5)

        self.N_plot = 0
        self.dBscan = self.dCscan_LP11[:, :, self.N_plot].T

        self.ax3 = self.fig.add_subplot(gs[4, 0:5])
        self.l_hist = self.ax3.hist(self.dBscan.ravel(), 256)

        axVmin_intensity = plt.axes([0.1, 0.01, 0.8, 0.03])
        axVmax_intensity = plt.axes([0.1, 0.05, 0.8, 0.03])

        axsave_LP11 = plt.axes([0.8, 0.79, 0.1, 0.075])
        axsave_LP01 = plt.axes([0.8, 0.9, 0.1, 0.075])

        axnext = plt.axes([0.8, 0.3, 0.1, 0.075])
        axprevious = plt.axes([0.8, 0.41, 0.1, 0.075])

        Min_LP11, Max_LP11 = np.min(self.dBscan) * 1, np.max(self.dBscan) * 1.
        Min_LP01, Max_LP01 = np.min(self.dBscan) * 1, np.max(self.dBscan) * 1.

        Nstep_LP11 = (Max_LP11 - Min_LP11) / 200
        Nstep_LP01 = (Max_LP01 - Min_LP01) / 200

        self.SVmin = Slider(axVmin_intensity,
                            'Vmin',
                            0,
                            255,
                            valinit=Min_LP11,
                            valstep=Nstep_LP11)
        self.SVmax = Slider(axVmax_intensity,
                            'Vmax',
                            0,
                            255,
                            valinit=Max_LP11,
                            valstep=Nstep_LP11)

        temp_descr = 'wow'
        axLabel = plt.axes([0.5, 0.9, 0.11, 0.075])
        self.textbox = TextBox(axLabel, '# Scan: ', temp_descr)

        self.textbox.set_val(self.N_plot)

        bsave_LP11 = Button(axsave_LP11, 'Save Bscan')

        bsave_LP01 = Button(axsave_LP01, 'Save Bscan')

        self.Bnext = Button(axnext, 'Next')
        self.Bprevious = Button(axprevious, 'Previous')

        self.ax1 = self.fig.add_subplot(gs[1:4, 0:2])
        print(np.shape(self.dBscan))
        self.l_LP01 = self.ax1.imshow(self.dBscan[:, :],
                                      cmap="gray",
                                      vmin=None,
                                      vmax=None)
        self.ax1.invert_yaxis()

        self.ax1.set_title("Processed Bscan LP01")

        self.ax2 = self.fig.add_subplot(gs[1:4, 2:4])
        self.l_LP11 = self.ax2.imshow(self.dBscan[:, :],
                                      cmap="gray",
                                      vmin=None,
                                      vmax=None)
        self.ax2.invert_yaxis()
        self.ax2.set_title("Processed Bscan LP11")

        self.SVmin.on_changed(self.update_intensity)
        self.SVmax.on_changed(self.update_intensity)

        self.textbox.on_submit(self.submit)

        bsave_LP11.on_clicked(self.save_LP11)
        bsave_LP01.on_clicked(self.save_LP01)

        self.Bnext.on_clicked(self.next)
        self.Bprevious.on_clicked(self.previous)

        plt.show()
Esempio n. 22
0
class GUIDisplay(object):
    """Display 2d arrays with interactive parameters:
                - Contrast
                - Colormap
                - Axis label
                - Legend
                - Calibration
                - Scalebar
                - Line profile
                - Export"""
    def __init__(self, data_to_display, cal=None):
        # 2D array to display with calibration cal in nm/pixel
        self.image_data = data_to_display
        # Window for image display + matplotlib parameters
        self.fig_image = plt.figure(figsize=(10, 7), dpi=100)
        # Layout figure
        self.gs_fig_image = gridspec.GridSpec(8, 8)

        # Make buttons and assign function calls
        buttons = (ButtonParams('Refresh', 0, 0, self.test),
                   ButtonParams('Set\nColourmap', 1, 0, self.colourmap_button),
                   ButtonParams('Calibration', 2, 0, self.test),
                   ButtonParams('Scale bar', 3, 0, self.update_scalebar),
                   ButtonParams('Line profile', 4, 0, self.line_profile),
                   ButtonParams('Rot 90 CCW', 5, 0, self.rotate_90),
                   ButtonParams('Num 6', 6, 0, self.test),
                   ButtonParams('Export', 7, 0, self.export_data))
        self.fig_image_parameter = []

        # Assign button to subplot in figure
        for ii in buttons:
            button = Button(plt.subplot(self.gs_fig_image[ii.x, ii.y]),
                            ii.text)
            button.on_clicked(ii.functioncall)
            self.fig_image_parameter.append(button)

        # Define image axis
        self.ax_image = plt.subplot(self.gs_fig_image[1:-1, 1:6])
        self.ax_image.set_axis_off()
        self.cmap = 'bwr'
        self.image = self.ax_image.imshow(self.image_data,
                                          cmap=self.cmap,
                                          vmin=-0.02,
                                          vmax=0.02)

        # Contrast histogram display and span selector
        self.ax_contrast = plt.subplot(self.gs_fig_image[0, 1:6])
        self.contrastbins = 256
        self.cmin = -0.02
        self.cmax = 0.02
        self.imhist, self.imbins = np.histogram(self.image_data,
                                                bins=self.contrastbins)
        self.ax_contrast_span = None
        self.plot_contrast_histogram()

        # Colormaps
        self.maps = sorted([m for m in plt.cm.datad if not m.endswith("_r")])
        self.cmapfig = None
        self.cmapaxes = None
        # (https://scipy.github.io/old-wiki/pages/Cookbook/Matplotlib/Show_colormaps)

        # Colourbar
        self.ax_colourbar = plt.subplot(self.gs_fig_image[1:-1, 7])
        self.colourbar = Colorbar(self.ax_colourbar, self.image)

        # Textbox for colormap
        self.ax_cmin = plt.axes([0.8, 0.85, 0.1, 0.05])
        self.ax_cmax = plt.axes([0.8, 0.8, 0.1, 0.05])
        self.text_cmin = TextBox(self.ax_cmin,
                                 label='min',
                                 initial="%.4f" % self.cmin,
                                 label_pad=0.25)
        self.text_cmax = TextBox(self.ax_cmax,
                                 label='max',
                                 initial="%.4f" % self.cmax,
                                 label_pad=0.25)
        self.text_cmin.on_submit(self.update_cmin)
        self.text_cmax.on_submit(self.update_cmax)

        # Calibration textbox
        self.cal = cal
        self.ax_cal = plt.axes([0.5, 0.1, 0.1, 0.05])
        if self.cal is None:
            self.text_cal = TextBox(self.ax_cal,
                                    label='Calibration (nm/pixel)',
                                    initial='',
                                    label_pad=0.25)
        else:
            self.text_cal = TextBox(self.ax_cal,
                                    label='Calibration (nm/pixel)',
                                    initial=self.cal,
                                    label_pad=0.25)
        self.text_cal.on_submit(self.update_calibration)

        # Scalebar
        self.state_scalebar = 0
        self.scalebar = None

        # Line profile
        self.line_prof = None
        self.line_prof_edit = 0
        self.fig_line_prof = None
        self.ax_fig_line_prof = None
        self.profile = None

        # Show the display window
        plt.show()

    @staticmethod
    def test(event):
        print(event)

    # Button to open colourmap selection window
    def colourmap_button(self, event):
        if event.inaxes == self.fig_image_parameter[1].ax:
            nummaps = len(self.maps)
            self.cmapfig = plt.figure('Colourmap options, pick one!',
                                      figsize=(5, 2 * nummaps))
            self.cmapaxes = {}
            gradient = np.linspace(0, 1, 100) * np.ones((3, 100))

            for mm in range(nummaps):
                corners = [0., mm / float(nummaps), 0.75, 1. / nummaps]
                self.cmapaxes[mm] = plt.axes(corners)
                self.cmapaxes[mm].annotate(self.maps[mm],
                                           xy=(0.77,
                                               (mm + 0.2) / float(nummaps)),
                                           xycoords='figure fraction',
                                           fontsize=11)
                self.cmapaxes[mm].set_axis_off()
                self.cmapaxes[mm].imshow(gradient,
                                         cmap=plt.get_cmap(self.maps[mm]))

            self.cmapfig.canvas.mpl_connect('button_press_event',
                                            self.colourmap_axis_select)

            plt.show()

    # Set colourmap based on clicking on an axis in the colourmap window
    def colourmap_axis_select(self, event):
        for aa in self.cmapaxes:
            if event.inaxes == self.cmapaxes[aa]:
                self.cmap = self.maps[aa]
                self.image.set_cmap(plt.get_cmap(self.cmap))
                self.update_colourmap()
                self.fig_image.canvas.draw()

    def line_profile(self, event):
        if event.inaxes == self.fig_image_parameter[4].ax:
            if self.line_prof_edit == 0:
                if self.line_prof is None:
                    print('create line')
                    self.line_prof_edit = 1
                    self.line_prof = guilinemanager.LineDraw(self.ax_image)
                    self.line_prof.ConnectDraw()
                else:
                    print('edit line')
                    self.line_prof_edit = 1
                    self.line_prof.ConnectMove()
            elif self.line_prof_edit == 1:
                print('disconect')
                self.line_prof_edit = 0
                self.line_prof.DisconnectDraw()
                self.line_prof.DisconnectMove()
                self.fig_line_prof = plt.figure()
                self.ax_fig_line_prof = self.fig_line_prof.add_subplot(1, 1, 1)
                print(self.line_prof.WidthData)
                first_postion = (self.line_prof.LineCoords[0][1],
                                 self.line_prof.LineCoords[0][0])
                second_postion = (self.line_prof.LineCoords[1][1],
                                  self.line_prof.LineCoords[1][0])
                self.profile = skimage.measure.profile_line(
                    self.image_data,
                    first_postion,
                    second_postion,
                    linewidth=int(self.line_prof.WidthData))
                self.ax_fig_line_prof.plot(self.profile)
                plt.show()
            else:
                return

    # Function to update image after changing it
    def update_image(self):
        self.image.set_clim(vmin=self.cmin, vmax=self.cmax)

    def update_colourmap(self):
        self.colourbar.update_bruteforce(self.image)

    def update_cm_textbox(self):
        self.text_cmin.set_val("%.4f" % self.cmin)
        self.text_cmax.set_val("%.4f" % self.cmax)

    def update_cmin(self, event):
        self.cmin = float(event)
        self.contrast_span(self.cmin, self.cmax)

    def update_cmax(self, event):
        self.cmax = float(event)
        self.contrast_span(self.cmin, self.cmax)

    # Calculates and plots image histogram and connects interactive spanselector
    def plot_contrast_histogram(self):
        self.ax_contrast.cla()
        self.ax_contrast.plot(self.imbins[:-1], self.imhist, color='k')
        self.ax_contrast.set_axis_off()
        self.ax_contrast_span = SpanSelector(self.ax_contrast,
                                             self.contrast_span,
                                             'horizontal',
                                             span_stays=True,
                                             rectprops=dict(alpha=0.5,
                                                            facecolor='green'))

    # Function for interactive spanselector for contrast histogram
    def contrast_span(self, cmin, cmax):
        self.cmin = cmin
        self.cmax = cmax
        self.update_image()
        self.update_colourmap()
        self.update_cm_textbox()

    def update_calibration(self, event):
        self.cal = float(event)

    def update_scalebar(self, event):
        if event.inaxes == self.fig_image_parameter[3].ax:
            if self.state_scalebar == 0:
                if self.cal is not None:
                    self.state_scalebar = 1
                    self.scalebar = self.ax_image.add_artist(
                        ScaleBar(self.cal * 10**-9))
                    self.fig_image.canvas.draw()
            elif self.state_scalebar == 1:
                if self.cal is not None:
                    self.state_scalebar = 0
                    self.scalebar.remove()
                    self.fig_image.canvas.draw()
            else:
                raise Exception("Invalid parameter for scalebar")

    def rotate_90(self, event):
        if event.inaxes == self.fig_image_parameter[5].ax:
            self.image_data = np.rot90(self.image_data)
            self.image.set_array(self.image_data)
            self.fig_image.canvas.draw()

    def export_data(self, event):
        if event.inaxes == self.fig_image_parameter[7].ax:
            print('export')
            #'''Save image respecting the number of pixels of the origin image'''
            #imsave('image_array.png', self.image_data)
            #'''Save image without respecting the number of pixels of the origin image'''
            plt.ioff()
            fig_export = plt.figure(figsize=(10, 7), dpi=100)
            ax_fig_export = fig_export.add_subplot(1, 1, 1)
            image_fig_export = ax_fig_export.imshow(self.image_data,
                                                    cmap=self.cmap,
                                                    vmin=self.cmin,
                                                    vmax=self.cmax)
            ax_fig_export.set_axis_off()
            if self.state_scalebar == 1:
                ax_fig_export.add_artist(ScaleBar(self.cal * 10**-9))
                fig_export.canvas.draw()
            if self.line_prof is not None:
                np.savetxt('line_profile', self.profile)
            fig_export.colorbar(image_fig_export)
            fig_export.savefig('image.png')
            print('Image saved')
            status_export_raw = 1
            if status_export_raw == 1:
                np.savetxt('image_raw', self.image_data, delimiter=',')
                print('Raw data extracted')
            plt.close(fig_export)
Esempio n. 23
0
def submit(expression):
    """
    Update the plotted function to the new math *expression*.

    *expression* is a string using "t" as its independent variable, e.g.
    "t ** 3".
    """
    ydata = eval(expression)
    l.set_ydata(ydata)
    ax.relim()
    ax.autoscale_view()
    plt.draw()


axbox = fig.add_axes([0.1, 0.05, 0.8, 0.075])
text_box = TextBox(axbox, "Evaluate")
text_box.on_submit(submit)
text_box.set_val("t ** 2")  # Trigger `submit` with the initial string.

plt.show()

#############################################################################
#
# .. admonition:: References
#
#    The use of the following functions, methods, classes and modules is shown
#    in this example:
#
#    - `matplotlib.widgets.TextBox`
Esempio n. 24
0
    class EventSelector():
        def __init__(self, parent=None):
            self.parent = parent

            self.fig = plt.figure()

            self.run_ax = plt.axes([0.3, 0.9, 0.5, 0.1])
            self.run_selection = TextBox(self.run_ax,
                                         'Run',
                                         initial=str(self.parent.run),
                                         color='white',
                                         hovercolor='lightgrey')
            self.run_selection.on_submit(self.submit_run)

            self.entry_ax = plt.axes([0.3, 0.8, 0.5, 0.1])
            self.entry_selection = TextBox(self.entry_ax,
                                           'Entry',
                                           initial=str(self.parent.entry),
                                           color='white',
                                           hovercolor='lightgrey')
            self.entry_selection.on_submit(self.submit_entry)

            self.event_ax = plt.axes([0.3, 0.7, 0.5, 0.1])
            self.event_selection = TextBox(
                self.event_ax,
                'Event',
                initial=str(self.parent.event_analyzer.header.event_number),
                color='white',
                hovercolor='lightgrey')
            #self.event_selection.on_submit(self.parent.set_event)
            self.event_selection.on_submit(self.submit_event)

            self.set_values()

            plt.ion()
            self.fig.show()

        def submit_event(self, event):
            try:
                self.parent.set_event(event)
                self.set_values()
            except:
                self.event_selection.color = 'red'
                pass

        def submit_entry(self, entry):
            try:
                self.parent.set_entry(entry)
                self.set_values()
            except:
                self.entry_selection.color = 'red'

        def submit_run(self, run):
            try:
                self.parent.set_run(run)
                self.set_values()
            except:
                self.run_selection.color = 'red'

        def set_values(self):
            self.run_selection.set_val(str(self.parent.run))
            self.entry_selection.set_val(str(self.parent.entry))
            self.event_selection.set_val(
                str(self.parent.event_analyzer.header.event_number))

            for selection in [
                    self.run_selection, self.entry_selection,
                    self.event_selection
            ]:
                selection.color = 'white'
Esempio n. 25
0
class Visualization:
    """Visualize embedding with its infrastructure and overlay"""
    def __init__(self, embedding: PartialEmbedding):
        self.embedding = embedding

        shape = (2, 3)
        self.infra_ax = plt.subplot2grid(shape=shape, loc=(0, 0))
        self.overlay_ax = plt.subplot2grid(shape=shape, loc=(1, 0))
        self.embedding_ax = plt.subplot2grid(shape=shape,
                                             loc=(0, 1),
                                             rowspan=2,
                                             colspan=2)
        plt.subplots_adjust(bottom=0.2)
        input_text_ax = plt.axes([0.1, 0.05, 0.6,
                                  0.075]  # left  # bottom  # width  # height
                                 )
        input_btn_ax = plt.axes([0.7, 0.05, 0.2,
                                 0.075]  # left  # bottom  # width  # height
                                )

        self.update_infra()
        self.update_overlay()
        self.update_embedding()

        pa = mpatches.Patch
        plt.gcf().legend(handles=[
            pa(color=COLORS["sources_color"], label="source"),
            pa(color=COLORS["sink_color"], label="sink"),
            pa(color=COLORS["intermediates_color"], label="intermediate"),
        ])

        random = get_random_action(self.embedding, rand=np.random)
        self.text_box_val = str(random)
        self.text_box = TextBox(input_text_ax,
                                "Action",
                                initial=self.text_box_val)

        def _update_textbox_val(new_val):
            self.text_box_val = new_val

        self.text_box.on_text_change(_update_textbox_val)

        self.submit_btn = Button(input_btn_ax, "Take action")

        def _on_clicked(_):
            self._take_action(self._parse_textbox())

        self.submit_btn.on_clicked(_on_clicked)

    def _parse_textbox(self):
        action = self.text_box_val
        possibilities = self.embedding.possibilities()
        for possibility in possibilities:
            if str(possibility) == action:
                return possibility
        return None

    def _update_textbox(self):
        next_random = get_random_action(self.embedding, rand=np.random)
        self.text_box.set_val(
            str(next_random) if next_random is not None else "")

    def _take_action(self, action):
        if action is None:
            print("Action could not be parsed")
            return
        print(f"Taking action: {action}")
        success = self.embedding.take_action(*action)
        if not success:
            print("Action is not valid. The possibilities are:")
        self.update_embedding()
        self._update_textbox()
        plt.draw()

    def update_infra(self):
        """Redraws the infrastructure"""
        plt.sca(self.infra_ax)
        plt.cla()
        self.infra_ax.set_title("Infrastructure")
        draw_infra(self.embedding.infra, **COLORS)

    def update_overlay(self):
        """Redraws the overlay"""
        plt.sca(self.overlay_ax)
        plt.cla()
        self.overlay_ax.set_title("Overlay")
        draw_overlay(self.embedding.overlay, **COLORS)

    def update_embedding(self):
        """Redraws the embedding"""
        plt.sca(self.embedding_ax)
        plt.cla()
        self.embedding_ax.set_title("Embedding")
        draw_embedding(self.embedding, **COLORS)
Esempio n. 26
0
def main():
    global gc_args, g_curve_x, g_curve_y, gc_fig, gc_ax

    gc_args = retrieve_args()

    g_curve_x = np.linspace(g_left_x, g_right_x, gc_sl_n)
    g_curve_y = np.array([g_sl_valinit] * gc_sl_n)

    gc_fig = plt.figure(figsize=(12, 12))
    gc_ax = gc_fig.add_subplot(111)

    axis_color, hover_color = 'lightgoldenrodyellow', '0.975'
    sl_hstep, sl_x, sl_y, sl_w, sl_h = 0.163, 0.23, 0.05, 0.02, 0.4
    btn_h, btn_top, btn_vstep = 0.04, 0.62, 0.06
    lp_x, lp_w = 0.025, 0.15
    txt_top, txt_w, txt_h, txt_hstep = 0.91, 0.279, 0.029, 0.298
    txt_label_color = 'brown'

    # * * Create widgets * *

    # Adjust the subplots region to leave some space for the sliders and buttons
    gc_fig.subplots_adjust(left=sl_x, bottom=0.50)

    for i, slider in enumerate(gc_sl):
        sl_ax = gc_fig.add_axes([sl_x + i * sl_hstep, sl_y, sl_w, sl_h],
                                facecolor=axis_color)
        gc_sl[i] = i, VertSlider(sl_ax,
                                 f"S{i}:",
                                 g_bottom_y,
                                 g_top_y,
                                 valinit=g_sl_valinit)

    # Draw the initial plot
    plot_curve()

    for slider in gc_sl:
        i, s = slider
        s.on_changed(sliders_on_changed)

    tp = TextBox(gc_fig.add_axes([lp_x, txt_top + 0.035, 0.875, txt_h]),
                 '',
                 initial=Path.cwd())  # Current directory.
    tp.label.set_color(txt_label_color)

    ti = TextBox(gc_fig.add_axes([lp_x, txt_top, txt_w, txt_h]),
                 'I',
                 initial=g_inc)  # Include target directory.
    ti.on_text_change(inc_textbox_on_text_change)
    ti.label.set_color(txt_label_color)

    ts = TextBox(gc_fig.add_axes([lp_x + txt_hstep, txt_top, txt_w, txt_h]),
                 'S',
                 initial=g_src)  # Source target directory.
    ts.on_text_change(src_textbox_on_text_change)
    ts.label.set_color(txt_label_color)

    tn = TextBox(gc_fig.add_axes([lp_x + txt_hstep * 2, txt_top, txt_w,
                                  txt_h]),
                 'N',
                 initial=g_name)  # File and function name stem.
    tn.on_text_change(name_textbox_on_text_change)
    tn.label.set_color(txt_label_color)
    tn.text_disp.set_color('black')

    if gc_args.function_name:
        tn.set_val(Path(gc_args.function_name).resolve().stem)

    tr = TextBox(gc_fig.add_axes([lp_x, 0.852, lp_w, txt_h]),
                 'R',
                 initial=str(g_range))  # Function range.
    tr.on_text_change(range_textbox_on_text_change)
    tr.label.set_color(txt_label_color)

    br = Button(gc_fig.add_axes([lp_x, btn_top - btn_vstep * 2, lp_w, btn_h]),
                'Reset',
                color=axis_color,
                hovercolor=hover_color)
    br.on_clicked(reset_button_on_clicked)

    be = Button(gc_fig.add_axes([lp_x, btn_top, lp_w, btn_h]),
                'Export',
                color=axis_color,
                hovercolor=hover_color)
    be.on_clicked(export_button_on_clicked)

    bi = Button(gc_fig.add_axes([lp_x, btn_top - btn_vstep, lp_w, btn_h]),
                'Import',
                color=axis_color,
                hovercolor=hover_color)
    bi.on_clicked(import_button_on_clicked)

    rbd = RadioButtons(gc_fig.add_axes([lp_x, 0.68, lp_w, 0.15],
                                       facecolor=axis_color),
                       ('128', '256', '512', '1024'),
                       active=0)
    rbd.on_clicked(domain_radios_on_clicked)

    # * * Run the show * *
    plt.show()
Esempio n. 27
0
class AtlasEditor(plot_support.ImageSyncMixin):
    """Graphical interface to view an atlas in multiple orthogonal 
    dimensions and edit atlas labels.
    
    :attr:`plot_eds` are dictionaries of keys specified by one of
    :const:`magmap.config.PLANE` plane orientations to Plot Editors.
    
    Attributes:
        image5d: Numpy image array in t,z,y,x,[c] format.
        labels_img: Numpy image array in z,y,x format.
        channel: Channel of the image to display.
        offset: Index of plane at which to start viewing in x,y,z (user) 
            order.
        fn_close_listener: Handle figure close events.
        borders_img: Numpy image array in z,y,x,[c] format to show label 
            borders, such as that generated during label smoothing. 
            Defaults to None. If this image has a different number of 
            labels than that of ``labels_img``, a new colormap will 
            be generated.
        fn_show_label_3d: Function to call to show a label in a 
            3D viewer. Defaults to None.
        title (str): Window title; defaults to None.
        fn_refresh_atlas_eds (func): Callback for refreshing other
            Atlas Editors to synchronize them; defaults to None.
            Typically takes one argument, this ``AtlasEditor`` object
            to refreshing it. Defaults to None.
        alpha_slider: Matplotlib alpha slider control.
        alpha_reset_btn: Maplotlib button for resetting alpha transparency.
        alpha_last: Float specifying the previous alpha value.
        interp_planes: Current :class:`InterpolatePlanes` object.
        interp_btn: Matplotlib button to initiate plane interpolation.
        save_btn: Matplotlib button to save the atlas.
        fn_status_bar (func): Function to call during status bar updates
            in :class:`pixel_display.PixelDisplay`; defaults to None.
        fn_update_coords (func): Handler for coordinate updates, which
            takes coordinates in z-plane orientation; defaults to None.
    """

    _EDIT_BTN_LBLS = ("Edit", "Editing")

    def __init__(self,
                 image5d,
                 labels_img,
                 channel,
                 offset,
                 fn_close_listener,
                 borders_img=None,
                 fn_show_label_3d=None,
                 title=None,
                 fn_refresh_atlas_eds=None,
                 fig=None,
                 fn_status_bar=None):
        """Plot ROI as sequence of z-planes containing only the ROI itself."""
        super().__init__()
        self.image5d = image5d
        self.labels_img = labels_img
        self.channel = channel
        self.offset = offset
        self.fn_close_listener = fn_close_listener
        self.borders_img = borders_img
        self.fn_show_label_3d = fn_show_label_3d
        self.title = title
        self.fn_refresh_atlas_eds = fn_refresh_atlas_eds
        self.fig = fig
        self.fn_status_bar = fn_status_bar

        self.alpha_slider = None
        self.alpha_reset_btn = None
        self.alpha_last = None
        self.interp_planes = None
        self.interp_btn = None
        self.save_btn = None
        self.edit_btn = None
        self.color_picker_box = None
        self.fn_update_coords = None

        self._labels_img_sitk = None  # for saving labels image

    def show_atlas(self):
        """Set up the atlas display with multiple orthogonal views."""
        # set up the figure
        if self.fig is None:
            fig = figure.Figure(self.title)
            self.fig = fig
        else:
            fig = self.fig
        fig.clear()
        gs = gridspec.GridSpec(2,
                               1,
                               wspace=0.1,
                               hspace=0.1,
                               height_ratios=(20, 1),
                               figure=fig,
                               left=0.06,
                               right=0.94,
                               bottom=0.02,
                               top=0.98)
        gs_viewers = gridspec.GridSpecFromSubplotSpec(2,
                                                      2,
                                                      subplot_spec=gs[0, 0])

        # set up a colormap for the borders image if present
        cmap_borders = colormaps.get_borders_colormap(self.borders_img,
                                                      self.labels_img,
                                                      config.cmap_labels)
        coord = list(self.offset[::-1])

        # editor controls, split into a slider sub-spec to allow greater
        # spacing for labels on either side and a separate sub-spec for
        # buttons and other fields
        gs_controls = gridspec.GridSpecFromSubplotSpec(1,
                                                       2,
                                                       subplot_spec=gs[1, 0],
                                                       width_ratios=(1, 1),
                                                       wspace=0.15)
        self.alpha_slider = Slider(
            fig.add_subplot(gs_controls[0, 0]),
            "Opacity",
            0.0,
            1.0,
            valinit=plot_editor.PlotEditor.ALPHA_DEFAULT)
        gs_controls_btns = gridspec.GridSpecFromSubplotSpec(
            1, 5, subplot_spec=gs_controls[0, 1], wspace=0.1)
        self.alpha_reset_btn = Button(fig.add_subplot(gs_controls_btns[0, 0]),
                                      "Reset")
        self.interp_btn = Button(fig.add_subplot(gs_controls_btns[0, 1]),
                                 "Fill Label")
        self.interp_planes = InterpolatePlanes(self.interp_btn)
        self.interp_planes.update_btn()
        self.save_btn = Button(fig.add_subplot(gs_controls_btns[0, 2]), "Save")
        self.edit_btn = Button(fig.add_subplot(gs_controls_btns[0, 3]), "Edit")
        self.color_picker_box = TextBox(
            fig.add_subplot(gs_controls_btns[0, 4]), None)

        # adjust button colors based on theme and enabled status; note
        # that colors do not appear to refresh until fig mouseover
        for btn in (self.alpha_reset_btn, self.edit_btn):
            enable_btn(btn)
        enable_btn(self.save_btn, False)
        enable_btn(self.color_picker_box, color=config.widget_color + 0.1)

        def setup_plot_ed(axis, gs_spec):
            # set up a PlotEditor for the given axis

            # subplot grid, with larger height preference for plot for
            # each increased row to make sliders of approx equal size and
            # align top borders of top images
            rows_cols = gs_spec.get_rows_columns()
            extra_rows = rows_cols[3] - rows_cols[2]
            gs_plot = gridspec.GridSpecFromSubplotSpec(
                2,
                1,
                subplot_spec=gs_spec,
                height_ratios=(1, 10 + 14 * extra_rows),
                hspace=0.1 / (extra_rows * 1.4 + 1))

            # transform arrays to the given orthogonal direction
            ax = fig.add_subplot(gs_plot[1, 0])
            plot_support.hide_axes(ax)
            plane = config.PLANE[axis]
            arrs_3d, aspect, origin, scaling = \
                plot_support.setup_images_for_plane(
                    plane,
                    (self.image5d[0], self.labels_img, self.borders_img))
            img3d_tr, labels_img_tr, borders_img_tr = arrs_3d

            # slider through image planes
            ax_scroll = fig.add_subplot(gs_plot[0, 0])
            plane_slider = Slider(ax_scroll,
                                  plot_support.get_plane_axis(plane),
                                  0,
                                  len(img3d_tr) - 1,
                                  valfmt="%d",
                                  valinit=0,
                                  valstep=1)

            # plot editor
            max_size = max_sizes[axis] if max_sizes else None
            plot_ed = plot_editor.PlotEditor(
                ax,
                img3d_tr,
                labels_img_tr,
                config.cmap_labels,
                plane,
                aspect,
                origin,
                self.update_coords,
                self.refresh_images,
                scaling,
                plane_slider,
                img3d_borders=borders_img_tr,
                cmap_borders=cmap_borders,
                fn_show_label_3d=self.fn_show_label_3d,
                interp_planes=self.interp_planes,
                fn_update_intensity=self.update_color_picker,
                max_size=max_size,
                fn_status_bar=self.fn_status_bar)
            return plot_ed

        # setup plot editors for all 3 orthogonal directions
        max_sizes = plot_support.get_downsample_max_sizes()
        for i, gs_viewer in enumerate(
            (gs_viewers[:2, 0], gs_viewers[0, 1], gs_viewers[1, 1])):
            self.plot_eds[config.PLANE[i]] = setup_plot_ed(i, gs_viewer)
        self.set_show_crosslines(True)

        # attach listeners
        fig.canvas.mpl_connect("scroll_event", self.scroll_overview)
        fig.canvas.mpl_connect("key_press_event", self.on_key_press)
        fig.canvas.mpl_connect("close_event", self._close)
        fig.canvas.mpl_connect("axes_leave_event", self.axes_exit)

        self.alpha_slider.on_changed(self.alpha_update)
        self.alpha_reset_btn.on_clicked(self.alpha_reset)
        self.interp_btn.on_clicked(self.interpolate)
        self.save_btn.on_clicked(self.save_atlas)
        self.edit_btn.on_clicked(self.toggle_edit_mode)
        self.color_picker_box.on_text_change(self.color_picker_changed)

        # initialize and show planes in all plot editors
        if self._max_intens_proj is not None:
            self.update_max_intens_proj(self._max_intens_proj)
        self.update_coords(coord, config.PLANE[0])

        plt.ion()  # avoid the need for draw calls

    def _close(self, evt):
        """Handle figure close events by calling :attr:`fn_close_listener`
        with this object.

        Args:
            evt (:obj:`matplotlib.backend_bases.CloseEvent`): Close event.

        """
        self.fn_close_listener(evt, self)

    def on_key_press(self, event):
        """Respond to key press events.
        """
        if event.key == "a":
            # toggle between current and 0 opacity
            if self.alpha_slider.val == 0:
                # return to saved alpha if available and reset
                if self.alpha_last is not None:
                    self.alpha_slider.set_val(self.alpha_last)
                self.alpha_last = None
            else:
                # make translucent, saving alpha if not already saved
                # during a halve-opacity event
                if self.alpha_last is None:
                    self.alpha_last = self.alpha_slider.val
                self.alpha_slider.set_val(0)
        elif event.key == "A":
            # halve opacity, only saving alpha on first halving to allow
            # further halving or manual movements while still returning to
            # originally saved alpha
            if self.alpha_last is None:
                self.alpha_last = self.alpha_slider.val
            self.alpha_slider.set_val(self.alpha_slider.val / 2)
        elif event.key == "up" or event.key == "down":
            # up/down arrow for scrolling planes
            self.scroll_overview(event)
        elif event.key == "w":
            # shortcut to toggle editing mode
            self.toggle_edit_mode(event)
        elif event.key == "ctrl+s" or event.key == "cmd+s":
            # support default save shortcuts on multiple platforms;
            # ctrl-s will bring up save dialog from fig, but cmd/win-S
            # will bypass
            self.save_fig(self.get_save_path())

    def update_coords(self, coord, plane_src=config.PLANE[0]):
        """Update all plot editors with given coordinates.
        
        Args:
            coord: Coordinate at which to center images, in z,y,x order.
            plane_src: One of :const:`magmap.config.PLANE` to specify the 
                orientation from which the coordinates were given; defaults 
                to the first element of :const:`magmap.config.PLANE`.
        """
        coord_rev = libmag.transpose_1d_rev(list(coord), plane_src)
        for i, plane in enumerate(config.PLANE):
            coord_transposed = libmag.transpose_1d(list(coord_rev), plane)
            if i == 0:
                self.offset = coord_transposed[::-1]
                if self.fn_update_coords:
                    # update offset based on xy plane, without centering
                    # planes are centered on the offset as-is
                    self.fn_update_coords(coord_transposed, False)
            self.plot_eds[plane].update_coord(coord_transposed)

    def view_subimg(self, offset, shape):
        """Zoom all Plot Editors to the given sub-image.

        Args:
            offset: Sub-image coordinates in ``z,y,x`` order.
            shape: Sub-image shape in ``z,y,x`` order.
        
        """
        for i, plane in enumerate(config.PLANE):
            offset_tr = libmag.transpose_1d(list(offset), plane)
            shape_tr = libmag.transpose_1d(list(shape), plane)
            self.plot_eds[plane].view_subimg(offset_tr[1:], shape_tr[1:])
        self.fig.canvas.draw_idle()

    def refresh_images(self, plot_ed=None, update_atlas_eds=False):
        """Refresh images in a plot editor, such as after editing one
        editor and updating the displayed image in the other editors.
        
        Args:
            plot_ed (:obj:`magmap.plot_editor.PlotEditor`): Editor that
                does not need updating, typically the editor that originally
                changed. Defaults to None.
            update_atlas_eds (bool): True to update other ``AtlasEditor``s;
                defaults to False.
        """
        for key in self.plot_eds:
            ed = self.plot_eds[key]
            if ed != plot_ed: ed.refresh_img3d_labels()
            if ed.edited:
                # display save button as enabled if any editor has been edited
                enable_btn(self.save_btn)
        if update_atlas_eds and self.fn_refresh_atlas_eds is not None:
            # callback to synchronize other Atlas Editors
            self.fn_refresh_atlas_eds(self)

    def scroll_overview(self, event):
        """Scroll images and crosshairs in all plot editors
        
        Args:
            event: Scroll event.
        """
        for key in self.plot_eds:
            self.plot_eds[key].scroll_overview(event)

    def alpha_update(self, event):
        """Update the alpha transparency in all plot editors.
        
        Args:
            event: Slider event.
        """
        for key in self.plot_eds:
            self.plot_eds[key].alpha_updater(event)

    def alpha_reset(self, event):
        """Reset the alpha transparency in all plot editors.
        
        Args:
            event: Button event, currently ignored.
        """
        self.alpha_slider.reset()

    def axes_exit(self, event):
        """Trigger axes exit for all plot editors.
        
        Args:
            event: Axes exit event.
        """
        for key in self.plot_eds:
            self.plot_eds[key].on_axes_exit(event)

    def interpolate(self, event):
        """Interpolate planes using :attr:`interp_planes`.
        
        Args:
            event: Button event, currently ignored.
        """
        try:
            self.interp_planes.interpolate(self.labels_img)
            # flag Plot Editors as edited so labels can be saved
            for ed in self.plot_eds.values():
                ed.edited = True
            self.refresh_images(None, True)
        except ValueError as e:
            print(e)

    def save_atlas(self, event):
        """Save atlas labels using the registered image suffix given by
        :attr:`config.reg_suffixes[config.RegSuffixes.ANNOTATION]`.
        
        Args:
            event: Button event, currently not used.
        
        """
        # only save if at least one editor has been edited
        if not any([ed.edited for ed in self.plot_eds.values()]): return

        # save to the labels reg suffix; use sitk Image if loaded and store
        # any Image loaded during saving
        reg_name = config.reg_suffixes[config.RegSuffixes.ANNOTATION]
        if self._labels_img_sitk is None:
            self._labels_img_sitk = config.labels_img_sitk
        self._labels_img_sitk = sitk_io.write_registered_image(
            self.labels_img,
            config.filename,
            reg_name,
            self._labels_img_sitk,
            overwrite=True)

        # reset edited flag in all editors and show save button as disabled
        for ed in self.plot_eds.values():
            ed.edited = False
        enable_btn(self.save_btn, False)
        print("Saved labels image at {}".format(datetime.datetime.now()))

    def get_save_path(self):
        """Get figure save path based on filename, ROI, and overview plane
         shown.
        
        Returns:
            str: Figure save path.

        """
        ext = config.savefig if config.savefig else config.DEFAULT_SAVEFIG
        return "{}.{}".format(
            naming.get_roi_path(os.path.basename(self.title), self.offset),
            ext)

    def toggle_edit_mode(self, event):
        """Toggle editing mode, determining the current state from the
        first :class:`magmap.plot_editor.PlotEditor` and switching to the 
        opposite value for all plot editors.

        Args:
            event: Button event, currently not used.
        """
        edit_mode = False
        for i, ed in enumerate(self.plot_eds.values()):
            if i == 0:
                # change edit mode based on current mode in first plot editor
                edit_mode = not ed.edit_mode
                toggle_btn(self.edit_btn, edit_mode, text=self._EDIT_BTN_LBLS)
            ed.edit_mode = edit_mode
        if not edit_mode:
            # reset the color picker text box when turning off editing
            self.color_picker_box.set_val("")

    def update_color_picker(self, val):
        """Update the color picker :class:`TextBox` with the given value.

        Args:
            val (str): Color value. If None, only :meth:`color_picker_changed`
                will be triggered.
        """
        if val is None:
            # updated picked color directly
            self.color_picker_changed(val)
        else:
            # update text box, which triggers color_picker_changed
            self.color_picker_box.set_val(val)

    def color_picker_changed(self, text):
        """Respond to color picker :class:`TextBox` changes by updating
        the specified intensity value in all plot editors.

        Args:
            text (str): String of text box value. Converted to an int if
                non-empty.
        """
        intensity = text
        if text:
            if not libmag.is_number(intensity): return
            intensity = int(intensity)
        print("updating specified color to", intensity)
        for i, ed in enumerate(self.plot_eds.values()):
            ed.intensity_spec = intensity
Esempio n. 28
0
    an.append(expression)
    func(a0[len(a0) - 1], expression, bn[len(bn) - 1])
    ax.relim


def submit2(expression):
    bn.append(expression)
    func(a0[len(a0) - 1], an[len(an) - 1], expression)
    ax.relim


def submit3(expression):
    a0.append(expression)
    func(expression, an[len(an) - 1], bn[len(bn) - 1])
    ax.relim


axbox3 = fig.add_axes([0.1, 0.4, 0.2, 0.055], xlabel='D (m)')
text_box3 = TextBox(axbox3, "")
text_box3.on_submit(submit3)
text_box3.set_val('17.4')

axbox = fig.add_axes([0.4, 0.4, 0.2, 0.055], xlabel='$\lambda$ (nm)')
text_box = TextBox(axbox, "")
text_box.on_submit(submit)
text_box.set_val('584')

axbox2 = fig.add_axes([0.7, 0.4, 0.2, 0.055], xlabel='d (m)')
text_box2 = TextBox(axbox2, "")
text_box2.on_submit(submit2)
text_box2.set_val("9.6e-4")
Esempio n. 29
0
class Viewer:
    def __init__(self, gui_params, params):

        self.curation_data = utils.load_manual_curation(
            params['curation_csvpath'])
        self.males_list = utils.load_male_list(params['male_listpath'])
        self.induction_dates = utils.load_induction_data(
            params['induction_csvpath'])
        self.season_data = utils.load_pond_season_data(
            params['pond_season_csvpath'])
        self.early_release = utils.load_release_data(
            params['early_release_csvpath'])
        self.late_release = utils.load_release_data(
            params['late_release_csvpath'])
        self.duplicate_data = utils.load_duplicate_data(
            params['duplicate_csvpath'])
        self.experimenter_data, self.inducer_data = utils.load_experimenter_data(
            params['experimenter_csvpath'])

        self.gui_params = gui_params
        self.params = params
        self.params.update(self.gui_params)
        self.auto_save_count = 0

        file_list = []
        metadata_list = []
        print "Reading in image file list"

        with open(self.params["image_list_filepath"], "rb") as f:
            line = f.readline().strip()
            while line:
                file_list.append(line)
                line = f.readline().strip()

        print "Reading in analysis file"

        self.data = utils.csv_to_df(self.params["input_analysis_file"])

        try:
            saved_data = utils.csv_to_df(self.params["output_analysis_file"])

            for row in saved_data.iterrows():
                i = np.where(self.data['filebase'] == row[1]['filebase'])
                for k, v in row[1].iteritems():
                    self.data.loc[i[0], k] = v

        except IOError:
            pass

        if not hasattr(self.data, 'accepted'):
            self.data['accepted'] = np.zeros(len(self.data))

        self.shape_data = utils.read_shape_long(
            self.params["input_shape_file"])

        try:
            saved_shape_data = utils.read_shape_long(
                self.params["output_shape_file"])
            fbs = np.unique(saved_shape_data['filebase'])
            self.shape_data = self.shape_data.drop(
                self.shape_data[self.shape_data['filebase'].isin(fbs)].index)
            self.shape_data = self.shape_data.append(saved_shape_data)
        except IOError:
            pass

        try:
            self.masked_regions = utils.read_masked_regions_long(
                self.params["masked_regions_output"])
        except IOError:
            self.masked_regions = {}

        all_clone_list = []

        for f in file_list:
            try:
                fileparts = f.split("/")
                clone = utils.dfrow_to_clone(
                    self.data,
                    np.where(self.data.filebase == fileparts[-1])[0][0],
                    self.params)
                clone.filepath = f
                all_clone_list.append(clone)

            except IndexError:
                print "No entry found in datafile for " + str(f)

        for i in xrange(len(all_clone_list)):
            index = (self.shape_data.filebase == all_clone_list[i].filebase)
            all_clone_list[i].dorsal_edge = np.transpose(
                np.vstack((np.transpose(self.shape_data.loc[index].x),
                           np.transpose(self.shape_data.loc[index].y))))
            all_clone_list[i].q = np.array(self.shape_data.loc[index].q)
            all_clone_list[i].qi = np.array(self.shape_data.loc[index].qi)
            idx = self.shape_data.loc[index].checkpoint == 1
            all_clone_list[i].checkpoints = all_clone_list[i].dorsal_edge[
                idx, :]

        clone_list = []
        for clone in all_clone_list:
            if len(clone.dorsal_edge) > 0:
                if not (int(self.params['skip_accepted']) and clone.accepted):
                    clone_list.append(clone)
            else:
                print "No shape data found for " + clone.filebase

        if len(clone_list) == 0:
            print "Either image list is empty or they have all been 'accepted'"
            return

        self.all_clone_list = all_clone_list
        self.clone_list = clone_list

        self.curr_idx = 0
        self.clone = self.clone_list[self.curr_idx]

        self.saving = 0
        self.fig = plt.figure(figsize=(15, 10))
        self.fig.patch.set_facecolor("lightgrey")
        self.display = self.fig.add_subplot(111)
        self.display.axis('off')

        try:
            self.obj = PointFixer(self.clone, self.display)

            try:
                self.obj.masked_regions = self.masked_regions[
                    self.clone.filebase]
                self.mask_all_regions()
            except (AttributeError, KeyError):
                pass

        except IOError:

            try:
                self.clone.modification_notes += " Image file not found."
            except TypeError:
                self.clone.modification_notes = "Image file not found."

            if self.curr_idx < len(self.clone_list) - 1:
                self.next_button_press(1)

        self.obj.clone.modifier = self.gui_params["default_modifier"]
        self.populate_figure()
        self.add_checkpoint = False

        return

    def populate_figure(self):

        self.display.clear()

        button_color = [0.792156862745098, 0.8823529411764706, 1.0]

        if self.saving == 1:
            self.saving_text = self.fig.text(0.875,
                                             0.879,
                                             'Saving',
                                             fontsize=10,
                                             fontweight='bold',
                                             color=[0.933, 0.463, 0])
        else:
            try:
                self.saving_text.remove()
            except (ValueError, AttributeError):
                pass

        self.notes_text = self.fig.text(0.852,
                                        0.575,
                                        'Notes',
                                        fontsize=10,
                                        color="black")

        axmodnotes = plt.axes([0.852, 0.45, 0.125, 0.12])

        initial_modnotes = str(self.obj.clone.modification_notes)
        if initial_modnotes == "nan":
            initial_modnotes = ""

        self.notestextbox = TextBox(axmodnotes, '', initial=initial_modnotes)
        self.notestextbox.on_submit(self.set_notes)

        axmodifier = plt.axes([0.875, 0.37, 0.1, 0.035])
        self.modifiertextbox = TextBox(axmodifier,
                                       'Initials',
                                       initial=str(
                                           self.params['default_modifier']))
        self.modifiertextbox.on_submit(self.change_default_modifier)

        axflip = plt.axes([0.50, 0.01, 0.1, 0.075])
        self.flipbutton = Button(axflip,
                                 'Flip',
                                 color=button_color,
                                 hovercolor=button_color)
        self.flipbutton.on_clicked(self.obj.flip_button_press)

        axedges = plt.axes([0.60, 0.01, 0.1, 0.075])
        self.edgebutton = Button(axedges,
                                 'Toggle Edges',
                                 color=button_color,
                                 hovercolor=button_color)
        self.edgebutton.on_clicked(self.obj.edge_button_press)

        axtogdorsal = plt.axes([0.70, 0.01, 0.1, 0.075])
        self.togdorsalbutton = Button(axtogdorsal,
                                      'Toggle Dorsal Fit',
                                      color=button_color,
                                      hovercolor=button_color)
        self.togdorsalbutton.on_clicked(self.obj.toggle_dorsal_button_press)

        axdel = plt.axes([0.025, 0.01, 0.1, 0.075])
        self.delcheckbutton = Button(axdel,
                                     'Delete Checkpoint',
                                     color=button_color,
                                     hovercolor=button_color)
        self.delcheckbutton.on_clicked(self.obj.delete_selected_checkpoint)

        axsave = plt.axes([0.875, 0.8, 0.1, 0.075])
        self.savebutton = Button(axsave,
                                 'Save',
                                 color=button_color,
                                 hovercolor=button_color)
        self.savebutton.on_clicked(self.save)

        axblur = plt.axes([0.25, 0.01, 0.1, 0.035])
        self.blurtextbox = TextBox(axblur,
                                   'Gaussian Blur StDev',
                                   initial=str(self.obj.edge_blur))
        self.blurtextbox.on_submit(self.set_edge_blur)

        axreset = plt.axes([0.40, 0.01, 0.1, 0.075])
        self.resetbutton = Button(axreset,
                                  'Reset',
                                  color=button_color,
                                  hovercolor=button_color)
        self.resetbutton.on_clicked(self.reset_button_press)

        if self.curr_idx + 1 < len(self.clone_list):
            axnext = plt.axes([0.875, 0.01, 0.1, 0.075])
            self.nextbutton = Button(axnext,
                                     'Next',
                                     color=button_color,
                                     hovercolor=button_color)
            self.nextbutton.on_clicked(self.next_button_press)

        if self.curr_idx > 0:
            axprev = plt.axes([0.875, 0.085, 0.1, 0.075])
            self.prevbutton = Button(axprev,
                                     'Previous',
                                     color=button_color,
                                     hovercolor=button_color)
            self.prevbutton.on_clicked(self.prev_button_press)

        self.obj.draw()

    def set_notes(self, text):

        try:
            self.obj.clone.modification_notes = str(text)
            self.obj.draw()
        except ValueError:
            print "Invalid value for notes"

    def set_edge_blur(self, text):

        try:
            self.obj.edge_blur = float(text)
        except ValueError:
            print "Invalid value for gaussian blur sigma"

        self.obj.clone.initialize_dorsal_edge(
            self.obj.original_image, dorsal_edge_blur=self.obj.edge_blur)
        self.obj.clone.fit_dorsal_edge(self.obj.original_image,
                                       dorsal_edge_blur=self.obj.edge_blur)
        self.obj.de = self.obj.clone.interpolate(self.obj.clone.dorsal_edge)
        self.obj.edge_image = self.obj.clone.edges

        self.mask_all_regions()

        self.obj.checkpoints = self.obj.clone.checkpoints

        self.obj.edges = False
        self.obj.edge_button_press(1)

        self.obj.clone.dorsal_edge_blur = self.obj.edge_blur

        self.obj.draw()

    def mask_all_regions(self):

        try:
            for region_id in xrange(len(self.obj.masked_regions.keys())):
                region = self.obj.masked_regions[region_id]
                if region[0] == "u":
                    self.obj.lasso_then_unmask(region[1],
                                               add_to_metadata=False)
                elif region[0] == "m":
                    self.obj.lasso_then_mask(region[1], add_to_metadata=False)

        except AttributeError:
            pass

    def change_default_modifier(self, text):

        self.gui_params['default_modifier'] = str(text)

        with open("gui_params.txt", "w+") as f:
            for k, v in gui_params.items():
                f.write(str(k) + ", " + str(v) + "\n")

        self.obj.clone.modifier = self.gui_params["default_modifier"]

    def prev_button_press(self, event):

        self.clone_list[self.curr_idx] = self.obj.clone
        self.masked_regions[self.obj.clone.filebase] = self.obj.masked_regions

        self.curr_idx -= 1
        self.clone = self.clone_list[self.curr_idx]

        self.fig.clear()

        self.display = self.fig.add_subplot(111)
        self.display.axis('off')

        self.obj = PointFixer(self.clone, self.display)
        self.obj.clone.modifier = self.gui_params["default_modifier"]

        try:
            self.obj.masked_regions = self.masked_regions[
                self.obj.clone.filebase]
            self.mask_all_regions()

        except KeyError:
            pass

        self.populate_figure()

        return

    def next_button_press(self, event):

        try:
            self.clone_list[self.curr_idx] = self.obj.clone
            self.masked_regions[
                self.obj.clone.filebase] = self.obj.masked_regions
        except AttributeError:
            self.clone_list[self.curr_idx] = self.clone

        self.auto_save_count += 1
        if self.gui_params["auto_save"]:
            if self.auto_save_count == self.gui_params["auto_save_number"]:
                self.save(1)
                self.auto_save_count = 0

        self.curr_idx += 1

        try:

            self.clone = self.clone_list[self.curr_idx]

            if os.path.isfile(self.clone.filepath):

                self.fig.clear()
                self.display = self.fig.add_subplot(111)
                self.display.axis('off')
                self.obj.clone.modifier = self.gui_params["default_modifier"]

                self.obj = PointFixer(self.clone, self.display)

                try:
                    self.obj.masked_regions = self.masked_regions[
                        self.obj.clone.filebase]
                    self.mask_all_regions()
                except KeyError:
                    pass

            else:
                print "Image " + self.clone.filepath + " not found. Check your image filepath."
                raise IOError

        except IOError:

            try:
                self.clone.modification_notes += " Image file not found."
            except TypeError:
                self.clone.modification_notes = "Image file not found."
            if self.curr_idx < len(self.clone_list) - 1:
                self.next_button_press(event)
            else:
                self.curr_idx -= 1
                self.clone = self.clone_list[self.curr_idx]

        self.populate_figure()

    def reset_button_press(self, event):

        if self.obj.clone.flip:
            self.obj.clone.flip = not self.obj.clone.flip

        self.obj.clone.find_features(self.obj.original_image,
                                     **self.obj.params)
        self.obj.clone.get_orientation_vectors()
        self.obj.clone.find_head(self.obj.original_image, **self.obj.params)
        self.obj.edge_blur = 1.0
        self.blurtextbox.set_val('1.0')
        self.obj.clone.dorsal_blur = 1.0
        self.obj.edge_image = self.obj.original_edge_image.copy()
        if self.obj.edges:
            self.obj.image = self.obj.edge_image
        self.obj.clone.initialize_dorsal_edge(self.obj.original_image,
                                              edges=self.obj.edge_image,
                                              **self.obj.params)
        self.obj.clone.fit_dorsal_edge(self.obj.original_image,
                                       **self.obj.params)
        self.obj.clone.find_tail(self.obj.original_image)
        self.obj.masked_regions = {}
        self.obj.clone.remove_tail_spine()
        self.obj.de = self.obj.clone.interpolate(self.obj.clone.dorsal_edge)
        self.obj.selected = None
        self.obj.checkpoints = self.obj.clone.checkpoints

        self.obj.draw()

    def save(self, event):

        print "Saving..."

        self.clone_list[self.curr_idx] = self.obj.clone
        self.masked_regions[self.obj.clone.filebase] = self.obj.masked_regions

        for all_c in xrange(len(self.all_clone_list)):
            for c in xrange(len(self.clone_list)):
                if self.all_clone_list[all_c].filebase == self.clone_list[
                        c].filebase:
                    self.all_clone_list[all_c] = self.clone_list[c]
        self.saving = 1
        self.populate_figure()

        with open(self.params["input_analysis_file"],
                  "rb") as analysis_file_in, open(
                      self.params["output_analysis_file"],
                      "wb") as analysis_file_out:

            # read/write header and save column names
            line = analysis_file_in.readline()
            analysis_file_out.write(line)
            line = line.strip()
            DATA_COLS = line.split("\t")

            line = analysis_file_in.readline()
            while line:
                written = False
                for clone in self.all_clone_list:
                    if (line.split("\t")[0]
                            == clone.filebase) and clone.accepted:

                        analysis_file_out.write(
                            utils.clone_to_line(clone, DATA_COLS) + "\n")
                        written = True

                if (not written) and (not self.params['truncate_output']):
                    analysis_file_out.write(line)

                line = analysis_file_in.readline()

        with open(self.params["output_shape_file"], "wb") as shape_file_out:

            # read/write header
            line = "\t".join(
                ["filebase", "i", "x", "y", "qi", "q", "checkpoint"]) + "\n"
            shape_file_out.write(line)

            clone = None

            for c in self.all_clone_list:
                if c.accepted:
                    clone = c
                if clone is not None:

                    for i in np.arange(len(clone.dorsal_edge)):
                        if len(
                                np.where((clone.checkpoints
                                          == clone.dorsal_edge[i, :]).all(
                                              axis=1))[0]) > 0:
                            checkpoint = 1
                        else:
                            checkpoint = 0
                        shape_file_out.write('\t'.join([
                            clone.filebase,
                            str(i),
                            str(clone.dorsal_edge[i, 0]),
                            str(clone.dorsal_edge[i, 1]),
                            str(clone.qi[i]),
                            str(clone.q[i]),
                            str(checkpoint)
                        ]) + "\n")

                clone = None

        self.saving = 0
        self.populate_figure()

        with open(self.params["input_analysis_metadata_file"],
                  "rb") as analysis_file_in, open(
                      self.params["output_analysis_metadata_file"],
                      "wb") as analysis_file_out:

            line = analysis_file_in.readline()
            analysis_file_out.write(line)

            line = analysis_file_in.readline()

            while line:
                written = False
                for clone in self.all_clone_list:
                    if (line.split("\t")[0]
                            == clone.filebase) and clone.accepted:

                        metadata = [clone.filebase] + [
                            str(getattr(clone, mf))
                            for mf in ANALYSIS_METADATA_FIELDS
                        ]
                        analysis_file_out.write("\t".join(metadata + ["\n"]))
                        written = True

                if (not written) and (not self.params['truncate_output']):
                    analysis_file_out.write(line)

                line = analysis_file_in.readline()

        with open(self.params["masked_regions_output"], "wb") as file_out:

            file_out.write("\t".join(
                ["filebase", "i", "x", "y", "masking_or_unmasking"]) + "\n")

            for clone in self.all_clone_list:
                if clone.accepted:
                    try:
                        masked_regions = self.masked_regions[clone.filebase]
                        for i in xrange(len(masked_regions.keys())):
                            m_or_u, region = masked_regions[i]
                            for j in xrange(region.shape[0]):
                                file_out.write("\t".join([
                                    clone.filebase,
                                    str(i),
                                    str(region[j][0]),
                                    str(region[j][1]), m_or_u
                                ]) + "\n")
                    except KeyError:
                        continue
        print "Saving done."
Esempio n. 30
0
File: main.py Progetto: gametwix/mai

ax = fig.add_subplot(111)
p, = ax.plot(x, y)
d, = ax.plot(listx, listy, "o")


def submit_fn_x0(value):
    update_function("x0", float(value))
    plt.draw()


axbox_x0 = fig.add_axes([0.75, 0.93, 0.1, 0.05])
text_box_x0 = TextBox(axbox_x0, "x1 ")
text_box_x0.on_submit(submit_fn_x0)
text_box_x0.set_val(listx[0])


def submit_fn_y0(value):
    update_function("y0", float(value))
    plt.draw()


axbox_y0 = fig.add_axes([0.89, 0.93, 0.1, 0.05])
text_box_y0 = TextBox(axbox_y0, "y1 ")
text_box_y0.on_submit(submit_fn_y0)
text_box_y0.set_val(listy[0])


def submit_fn_x1(value):
    update_function("x1", float(value))