Beispiel #1
0
def test_selector_clear_method(selector):
    ax = get_ax()

    def onselect(*args):
        pass

    if selector == 'span':
        tool = widgets.SpanSelector(ax, onselect, 'horizontal',
                                    interactive=True,
                                    ignore_event_outside=True)
    else:
        tool = widgets.RectangleSelector(ax, onselect, interactive=True)
    click_and_drag(tool, start=(10, 10), end=(100, 120))
    assert tool._selection_completed
    assert tool.visible
    if selector == 'span':
        assert tool.extents == (10, 100)

    tool.clear()
    assert not tool._selection_completed
    assert not tool.visible

    # Do another cycle of events to make sure we can
    click_and_drag(tool, start=(10, 10), end=(50, 120))
    assert tool._selection_completed
    assert tool.visible
    if selector == 'span':
        assert tool.extents == (10, 50)
Beispiel #2
0
def check_span(*args, **kwargs):
    fig, ax = plt.subplots(1, 1)
    ax.plot([0, 200], [0, 200])
    ax.figure.canvas.draw()

    def onselect(vmin, vmax):
        ax._got_onselect = True
        assert vmin == 100
        assert vmax == 150

    def onmove(vmin, vmax):
        assert vmin == 100
        assert vmax == 125
        ax._got_on_move = True

    if 'onmove_callback' in kwargs:
        kwargs['onmove_callback'] = onmove

    tool = widgets.SpanSelector(ax, onselect, *args, **kwargs)
    event = get_event(ax, xdata=100, ydata=100, button=1)
    tool.press(event)

    event = get_event(ax, xdata=125, ydata=125, button=1)
    tool.onmove(event)

    event = get_event(ax, xdata=150, ydata=150, button=1)
    tool.release(event)

    assert ax._got_onselect

    if 'onmove_callback' in kwargs:
        assert ax._got_on_move
Beispiel #3
0
def test_span_selector_onselect(interactive):
    # check when press and release events take place at the same position
    ax = get_ax()

    def onselect(vmin, vmax):
        ax._got_onselect = True

    tool = widgets.SpanSelector(ax,
                                onselect,
                                'horizontal',
                                interactive=interactive)
    do_event(tool, 'press', xdata=100, ydata=100, button=1)
    # move outside of axis
    do_event(tool, 'onmove', xdata=150, ydata=100, button=1)
    do_event(tool, 'release', xdata=150, ydata=100, button=1)

    assert tool.ax._got_onselect
    assert tool.extents == (100, 150)

    # Reset tool.ax._got_onselect
    tool.ax._got_onselect = False

    do_event(tool, 'press', xdata=10, ydata=100, button=1)
    do_event(tool, 'release', xdata=10, ydata=100, button=1)

    assert tool.ax._got_onselect
 def span_selection_init(self):
     self.span = mwidgets.SpanSelector(self.axes,
                                       self.on_select_span,
                                       'horizontal',
                                       useblit=True,
                                       rectprops=dict(alpha=0.5,
                                                      facecolor='red'))
Beispiel #5
0
def test_span_selector_drag(drag_from_anywhere):
    ax = get_ax()

    def onselect(*args):
        pass

    # Create span
    tool = widgets.SpanSelector(ax, onselect, 'horizontal', interactive=True,
                                drag_from_anywhere=drag_from_anywhere)
    click_and_drag(tool, start=(10, 10), end=(100, 120))
    assert tool.extents == (10, 100)
    # Drag inside span
    #
    # If drag_from_anywhere == True, this will move the span by 10,
    # giving new value extents = 20, 110
    #
    # If drag_from_anywhere == False, this will create a new span with
    # value extents = 25, 35
    click_and_drag(tool, start=(25, 15), end=(35, 25))
    if drag_from_anywhere:
        assert tool.extents == (20, 110)
    else:
        assert tool.extents == (25, 35)

    # Check that in both cases, dragging outside the span draws a new span
    click_and_drag(tool, start=(175, 185), end=(185, 195))
    assert tool.extents == (175, 185)
Beispiel #6
0
def test_span_selector_set_props_handle_props():
    ax = get_ax()

    def onselect(epress, erelease):
        pass

    tool = widgets.SpanSelector(ax,
                                onselect,
                                'horizontal',
                                interactive=True,
                                props=dict(facecolor='b', alpha=0.2),
                                handle_props=dict(alpha=0.5))
    # Create rectangle
    do_event(tool, 'press', xdata=0, ydata=10, button=1)
    do_event(tool, 'onmove', xdata=100, ydata=120, button=1)
    do_event(tool, 'release', xdata=100, ydata=120, button=1)

    artist = tool._selection_artist
    assert artist.get_facecolor() == mcolors.to_rgba('b', alpha=0.2)
    tool.set_props(facecolor='r', alpha=0.3)
    assert artist.get_facecolor() == mcolors.to_rgba('r', alpha=0.3)

    for artist in tool._handles_artists:
        assert artist.get_color() == 'b'
        assert artist.get_alpha() == 0.5
    tool.set_handle_props(color='r', alpha=0.3)
    for artist in tool._handles_artists:
        assert artist.get_color() == 'r'
        assert artist.get_alpha() == 0.3
Beispiel #7
0
def test_span_selector_ignore_outside(ignore_event_outside):
    ax = get_ax()
    def onselect(vmin, vmax):
        ax._got_onselect = True

    def onmove(vmin, vmax):
        ax._got_on_move = True

    tool = widgets.SpanSelector(ax, onselect, 'horizontal',
                                onmove_callback=onmove,
                                ignore_event_outside=ignore_event_outside)
    click_and_drag(tool, start=(100, 100), end=(125, 125))
    assert ax._got_onselect
    assert ax._got_on_move
    assert tool.extents == (100, 125)

    # Reset
    ax._got_onselect = False
    ax._got_on_move = False
    # Trigger event outside of span
    click_and_drag(tool, start=(150, 150), end=(160, 160))
    if ignore_event_outside:
        # event have been ignored and span haven't changed.
        assert not ax._got_onselect
        assert not ax._got_on_move
        assert tool.extents == (100, 125)
    else:
        # A new shape is created
        assert ax._got_onselect
        assert ax._got_on_move
        assert tool.extents == (150, 160)
Beispiel #8
0
def test_span_selector_ignore_outside(ignore_event_outside):
    ax = get_ax()
    def onselect(vmin, vmax):
        ax._got_onselect = True

    def onmove(vmin, vmax):
        ax._got_on_move = True

    tool = widgets.SpanSelector(ax, onselect, 'horizontal',
                                onmove_callback=onmove,
                                ignore_event_outside=ignore_event_outside)
    do_event(tool, 'press', xdata=100, ydata=100, button=1)
    do_event(tool, 'onmove', xdata=125, ydata=125, button=1)
    do_event(tool, 'release', xdata=125, ydata=125, button=1)
    assert ax._got_onselect
    assert ax._got_on_move
    assert tool.extents == (100, 125)

    # Reset
    ax._got_onselect = False
    ax._got_on_move = False
    # Trigger event outside of span
    do_event(tool, 'press', xdata=150, ydata=150, button=1)
    do_event(tool, 'onmove', xdata=160, ydata=160, button=1)
    do_event(tool, 'release', xdata=160, ydata=160, button=1)
    if ignore_event_outside:
        # event have been ignored and span haven't changed.
        assert not ax._got_onselect
        assert not ax._got_on_move
        assert tool.extents == (100, 125)
    else:
        # A new shape is created
        assert ax._got_onselect
        assert ax._got_on_move
        assert tool.extents == (150, 160)
Beispiel #9
0
def test_span_selector_drag(drag_from_anywhere):
    ax = get_ax()

    def onselect(*args):
        pass

    # Create span
    tool = widgets.SpanSelector(ax, onselect, 'horizontal', interactive=True,
                                drag_from_anywhere=drag_from_anywhere)
    do_event(tool, 'press', xdata=10, ydata=10, button=1)
    do_event(tool, 'onmove', xdata=100, ydata=120, button=1)
    do_event(tool, 'release', xdata=100, ydata=120, button=1)
    assert tool.extents == (10, 100)
    # Drag inside span
    #
    # If drag_from_anywhere == True, this will move the span by 10,
    # giving new value extents = 20, 110
    #
    # If drag_from_anywhere == False, this will create a new span with
    # value extents = 25, 35
    do_event(tool, 'press', xdata=25, ydata=15, button=1)
    do_event(tool, 'onmove', xdata=35, ydata=25, button=1)
    do_event(tool, 'release', xdata=35, ydata=25, button=1)
    if drag_from_anywhere:
        assert tool.extents == (20, 110)
    else:
        assert tool.extents == (25, 35)

    # Check that in both cases, dragging outside the span draws a new span
    do_event(tool, 'press', xdata=175, ydata=185, button=1)
    do_event(tool, 'onmove', xdata=185, ydata=195, button=1)
    do_event(tool, 'release', xdata=185, ydata=195, button=1)
    assert tool.extents == (175, 185)
Beispiel #10
0
def test_span_selector_bound(direction):
    fig, ax = plt.subplots(1, 1)
    ax.plot([10, 20], [10, 30])
    ax.figure.canvas.draw()
    x_bound = ax.get_xbound()
    y_bound = ax.get_ybound()

    tool = widgets.SpanSelector(ax, print, direction, interactive=True)
    assert ax.get_xbound() == x_bound
    assert ax.get_ybound() == y_bound

    bound = x_bound if direction == 'horizontal' else y_bound
    assert tool._edge_handles.positions == list(bound)

    press_data = [10.5, 11.5]
    move_data = [11, 13]  # Updating selector is done in onmove
    release_data = move_data
    do_event(tool, 'press', xdata=press_data[0], ydata=press_data[1], button=1)
    do_event(tool, 'onmove', xdata=move_data[0], ydata=move_data[1], button=1)

    assert ax.get_xbound() == x_bound
    assert ax.get_ybound() == y_bound

    index = 0 if direction == 'horizontal' else 1
    handle_positions = [press_data[index], release_data[index]]
    assert tool._edge_handles.positions == handle_positions
Beispiel #11
0
def test_selector_clear_method(selector):
    ax = get_ax()

    def onselect(*args):
        pass

    if selector == 'span':
        tool = widgets.SpanSelector(ax,
                                    onselect,
                                    'horizontal',
                                    interactive=True,
                                    ignore_event_outside=True)
    else:
        tool = widgets.RectangleSelector(ax, onselect, interactive=True)
    do_event(tool, 'press', xdata=10, ydata=10, button=1)
    do_event(tool, 'onmove', xdata=100, ydata=120, button=1)
    do_event(tool, 'release', xdata=100, ydata=120, button=1)
    assert tool._selection_completed
    assert tool.visible
    if selector == 'span':
        assert tool.extents == (10, 100)

    tool.clear()
    assert not tool._selection_completed
    assert not tool.visible

    # Do another cycle of events to make sure we can
    do_event(tool, 'press', xdata=10, ydata=10, button=1)
    do_event(tool, 'onmove', xdata=50, ydata=120, button=1)
    do_event(tool, 'release', xdata=50, ydata=120, button=1)
    assert tool._selection_completed
    assert tool.visible
    if selector == 'span':
        assert tool.extents == (10, 50)
def check_span(*args, **kwargs):
    ax = get_ax()

    def onselect(vmin, vmax):
        ax._got_onselect = True
        assert vmin == 100
        assert vmax == 150

    def onmove(vmin, vmax):
        assert vmin == 100
        assert vmax == 125
        ax._got_on_move = True

    if 'onmove_callback' in kwargs:
        kwargs['onmove_callback'] = onmove

    tool = widgets.SpanSelector(ax, onselect, *args, **kwargs)
    do_event(tool, 'press', xdata=100, ydata=100, button=1)
    do_event(tool, 'onmove', xdata=125, ydata=125, button=1)
    do_event(tool, 'release', xdata=150, ydata=150, button=1)

    assert ax._got_onselect

    if 'onmove_callback' in kwargs:
        assert ax._got_on_move
Beispiel #13
0
def test_span_selector_direction():
    ax = get_ax()

    def onselect(*args):
        pass

    tool = widgets.SpanSelector(ax, onselect, 'horizontal', interactive=True)
    assert tool.direction == 'horizontal'
    assert tool._edge_handles.direction == 'horizontal'

    with pytest.raises(ValueError):
        tool = widgets.SpanSelector(ax, onselect, 'invalid_direction')

    tool.direction = 'vertical'
    assert tool.direction == 'vertical'
    assert tool._edge_handles.direction == 'vertical'

    with pytest.raises(ValueError):
        tool.direction = 'invalid_string'
Beispiel #14
0
    def add_widgets(self):
        rect_props = dict(facecolor='blue', alpha=0.5)
        self.span = mwidgets.SpanSelector(self.plot_ax,
                                          self._on_interval_select,
                                          'horizontal',
                                          rectprops=rect_props,
                                          useblit=True)

        all_lr, _ = list(zip(*sorted(self.values[-1][0])))
        init_lr_min = all_lr[0]
        init_lr_max = self.init_lr_max or all_lr[-1]
        init_wd = self.values[-1][1]

        # add the plot controls
        self.plot_lr_min_text: str = ''
        self.plot_lr_max_text: str = ''
        self.plot_lr_min_text = str(init_lr_min)
        self.plot_lr_max_text = str(init_lr_max)
        self.plot_wd_text = str(init_wd)
        self.rerun_wd = init_wd

        self.rerun_lr_min_box = mwidgets.TextBox(self.plot_lr_min_ax,
                                                 label='LR min',
                                                 initial=str(init_lr_min))
        self.rerun_lr_max_box = mwidgets.TextBox(self.plot_lr_max_ax,
                                                 label='LR max',
                                                 initial=str(init_lr_max))
        self.rerun_wd_box = mwidgets.TextBox(self.plot_wd_ax,
                                             label='Weight decay',
                                             initial=str(init_wd))
        self.rerun_btn = mwidgets.Button(self.plot_btn_ax, label='PLOT')

        # add event handling
        self.rerun_lr_min_box.on_text_change(self._on_plot_lr_min_change)
        self.rerun_lr_max_box.on_text_change(self._on_plot_lr_max_change)
        self.rerun_wd_box.on_text_change(self._on_plot_wd_change)
        self.rerun_btn.on_clicked(self._on_rerun_click)

        # add the value input controls
        self.lr_min_text = ''
        self.lr_max_text = ''
        self.wd_text = str(init_wd)

        self.lr_min_box = mwidgets.TextBox(self.lr_min_ax, label='LR min')
        self.lr_max_box = mwidgets.TextBox(self.lr_max_ax, label='LR max')
        self.wd_box = mwidgets.TextBox(self.wd_ax,
                                       label='Weight decay',
                                       initial=str(init_wd))
        self.save_btn = mwidgets.Button(self.btn_ax, label='SAVE')

        # add event handling
        self.rerun_lr_min_box.on_text_change(self._on_lr_min_change)
        self.rerun_lr_max_box.on_text_change(self._on_lr_max_change)
        self.rerun_wd_box.on_text_change(self._on_wd_change)
        self.save_btn.on_clicked(self._on_save_click)
Beispiel #15
0
    def add_zoomed_axes(self,
                        from_ax_nr=1,
                        to_ax_nr=2,
                        rect_props=dict(alpha=0.5, facecolor='red')):

        self.ax[from_ax_nr]['span'] = widgets.SpanSelector(
            self.ax[from_ax_nr][1],
            lambda xmin, xmax, from_ax=from_ax_nr, to_ax=to_ax_nr: self.
            _on_span_select(xmin, xmax, from_ax, to_ax),
            'horizontal',
            useblit=True,
            rectprops=rect_props)
def subplot():
    fig, ax = plt.subplots()
    ax.plot([1, 2, 3], [10, 50, 100])
    span = mwidgets.SpanSelector(ax,
                                 onselect_span,
                                 "horizontal",
                                 rectprops=dict(alpha=1, facecolor='red'),
                                 span_stays=True)
    # choosing span_stays = True will make the selected area stay on the image.
    # lasso = mwidgets.LassoSelector(ax, onselect=onselect_lasso)

    plt.show()
Beispiel #17
0
def Plot(filename=None, dataset=None, timemarks=None, 
    events=None, eventfile=None,
    ylim=None, columns=1, battery="DREA160",
    autoscale=True):
  """Plot from ipython.

  Args:
    filename (string): name of a data file to plot. This will be loaded
    into a DataSet object.

    dataset (DataSet): pre-existing dataset to plot. Mutually exclusive
    with filename parameter.

    timemarks (string): a time spec indicating a span of time to slice.

    eventfile (string): name of data file containing event marks.

    events (DataSet): A pre-existing event dataset. 

    ylim (tuple of (min, max): minimum and maximum Y values to plot.

    columns (int, or sequence of ints): The column number, or numbers,
    starting from zero that will be extracted out (vertical slice).

    battery (string): Name of battery model. Default is "DREA160"

    autoscale (bool): If True, automatically fit graph scale to data.
    False means use a fixed scale (2.5 amp max).

  """
  if filename is not None:
    dataset = analyze.DataSet(filename=filename, timespec=timemarks)
  if eventfile is not None:
    events = analyze.DataSet(filename=eventfile)
  if dataset is None:
    print "You should supply a filename or a dataset."
    return
  analyze.MakeCharts(dataset, ylim=ylim, events=events,
      columns=columns, autoscale=autoscale, interactive=True)
  pylab.gcf().set_size_inches((9,7))
  plotaxes = pylab.gca()
  pylab.subplots_adjust(bottom=0.15)
  capacity = analyze.BATTERIES[battery][0]
  reporter = DataSampleReporter(plotaxes, dataset, capacity)
  span = widgets.SpanSelector(plotaxes, reporter.StatSelected, "horizontal")
  capaxes = pylab.axes([0.20, 0.025, 0.65, 0.03])
  capslider = widgets.Slider(capaxes, "Batt (mA-h)", 800, 1350, capacity.inUnitsOf("mA*h").value)
  capslider.on_changed(reporter.SetCapacity)
  pylab.ion()
  pylab.show()
Beispiel #18
0
def test_span_selector_add_state():
    ax = get_ax()

    def onselect(*args):
        pass

    tool = widgets.SpanSelector(ax, onselect, 'horizontal', interactive=True)

    with pytest.raises(ValueError):
        tool.add_state('unsupported_state')
    with pytest.raises(ValueError):
        tool.add_state('center')
    with pytest.raises(ValueError):
        tool.add_state('square')

    tool.add_state('move')
Beispiel #19
0
def test_span_selector_onselect(interactive):
    # check when press and release events take place at the same position
    ax = get_ax()

    def onselect(vmin, vmax):
        ax._got_onselect = True

    tool = widgets.SpanSelector(ax, onselect, 'horizontal',
                                interactive=interactive)
    # move outside of axis
    click_and_drag(tool, start=(100, 100), end=(150, 100))
    assert tool.ax._got_onselect
    assert tool.extents == (100, 150)

    # Reset tool.ax._got_onselect
    tool.ax._got_onselect = False
    click_and_drag(tool, start=(10, 100), end=(10, 100))
    assert tool.ax._got_onselect
    def __init__(self, dataframe, xfield, yfield, ax=None, **kwargs):
        """
        make a plot of xfield vs yfield in pandas dataframe

        kwargs are passed on to pyplot.plot
        """
        self.xfield = xfield
        self.yfield = yfield
        self.dataframe = dataframe

        # create an axes if none is provided
        if ax is None:
            import matplotlib.pyplot as plt
            fig, ax = plt.subplots(1)
        self.fig = ax.figure
        self.ax = ax

        self.line, = ax.plot(self.dataframe[self.xfield],
                             self.dataframe[self.yfield], **kwargs)

        # set useblit True on gtkagg for enhanced performance
        import matplotlib.widgets as widgets
        self.span = widgets.SpanSelector(ax,
                                         self.on_select,
                                         'horizontal',
                                         useblit=True,
                                         rectprops=dict(alpha=0.5,
                                                        facecolor='red'))

        x = self.dataframe[self.xfield]
        # mpl converts dates to floats runder the hood so we'll have
        # to special case some stuff below if dates are involved
        self._is_xdate = (isinstance(x[0], datetime.date)
                          or isinstance(x[0], datetime.datetime))

        if self._is_xdate:
            # this func rotates the x tick labels to make some room
            # for long date labels
            self.fig.autofmt_xdate()

        self.fig.tight_layout()
Beispiel #21
0
    def show_data(self, filename):
        self.ax_data_1.clear()
        self.ax_data_2.clear()

        self.ax_data_2.grid()

        self.df = analyse_igc(read_igc(filename))

        self.df[["vs_smooth"]].plot(ax=self.ax_data_1)
        self.df[["RPM"]].plot(ax=self.ax_data_2, color="green", linewidth=1)

        self.span = mwidgets.SpanSelector(self.ax_data_2,
                                          self.onselect,
                                          'horizontal',
                                          rectprops=dict(facecolor='blue',
                                                         alpha=0.5),
                                          useblit=True)
        # print(df[df.isna().any(axis=1)].head(50))

        # plt.show()
        self.fig_canvas.draw()
Beispiel #22
0
def test_span_selector_set_props_handle_props():
    ax = get_ax()

    def onselect(epress, erelease):
        pass

    tool = widgets.SpanSelector(ax, onselect, 'horizontal', interactive=True,
                                props=dict(facecolor='b', alpha=0.2),
                                handle_props=dict(alpha=0.5))
    # Create rectangle
    click_and_drag(tool, start=(0, 10), end=(100, 120))

    artist = tool._selection_artist
    assert artist.get_facecolor() == mcolors.to_rgba('b', alpha=0.2)
    tool.set_props(facecolor='r', alpha=0.3)
    assert artist.get_facecolor() == mcolors.to_rgba('r', alpha=0.3)

    for artist in tool._handles_artists:
        assert artist.get_color() == 'b'
        assert artist.get_alpha() == 0.5
    tool.set_handle_props(color='r', alpha=0.3)
    for artist in tool._handles_artists:
        assert artist.get_color() == 'r'
        assert artist.get_alpha() == 0.3
Beispiel #23
0
#---- Find files within root folder according to log files ".log"
pv.FilesList = pv.FindAndOrganize_dazer(pv.Pattern_PlotFiles,
                                        pv.Catalogue_Folder,
                                        unpack=True,
                                        CheckComputer=False)

#---- Generate Initial Frame
pv.FigConf('night')
pv.Axis.text(0.95,
             0.05,
             'Initiating visualizer',
             verticalalignment='bottom',
             horizontalalignment='right',
             transform=pv.Axis.transAxes,
             fontsize=15)

GUI = Tk_GUI(PlottingVector=pv)

pv.FigCanvas.show()
pv.FigCanvas.mpl_connect('key_press_event', Key_Manager)
Span = widgets.SpanSelector(pv.Axis,
                            Span_Manager,
                            'horizontal',
                            useblit=False,
                            rectprops=dict(alpha=1, facecolor='Blue'))

GUI.mainloop()

print "Dazer Closed"
Beispiel #24
0
    def __init__(self, counts, positions, fig=None, pos_order=None, norm=None):

        if pos_order is None:
            pos_order = {"x": 0, "y": 1}
        # extract x/y data
        self.x_pos = xpos = positions[pos_order["x"]]
        self.y_pos = ypos = positions[pos_order["y"]]
        self.points = np.transpose((xpos.ravel(), ypos.ravel()))
        # sort ouf the normalization
        if norm is None:
            norm = np.ones_like(self.x_pos)

        norm = np.atleast_3d(norm[:])
        self.counts = counts[:] / norm

        # compute values we will use for extents below
        dx = np.diff(xpos.mean(axis=0)).mean()
        dy = np.diff(ypos.mean(axis=1)).mean()
        left = xpos[:, 0].mean() - dx / 2
        right = xpos[:, -1].mean() + dx / 2
        top = ypos[0].mean() - dy / 2
        bot = ypos[-1].mean() + dy / 2

        # create a figure if we must
        if fig is None:
            import matplotlib.pyplot as plt

            fig = plt.figure(tight_layout=True)
        else:
            # clear the figure
            fig.clf()
        # set the window title (look at the tool bar)
        fig.canvas.set_window_title("XRF map")
        self.fig = fig
        # set up the figure layout
        gs = gridspec.GridSpec(2, 1, height_ratios=[4, 1], figure=fig)

        # set up the top panel (the map)
        self.ax_im = fig.add_subplot(gs[0, 0], gid="imgmap")
        self.ax_im.set_xlabel("x [?]")
        self.ax_im.set_ylabel("y [?]")
        self.ax_im.set_title("shift-click to select pixel\n"
                             "alt-drag to draw region\n"
                             "right-click to reset")

        # set up the lower axes (the average spectrum of the ROI)
        self.ax_spec = fig.add_subplot(gs[1, 0], gid="spectrum")
        self.ax_spec.set_ylabel("counts [?]")
        self.ax_spec.set_xlabel("bin number")
        self.ax_spec.set_yscale("log")
        self.ax_spec.set_title("click-and-drag to select energy ROI")
        self._EROI_txt = self.ax_spec.annotate(
            "ROI: all",
            xy=(0, 1),
            xytext=(0, 5),
            xycoords="axes fraction",
            textcoords="offset points",
        )
        self._pixel_txt = self.ax_spec.annotate(
            "map average",
            xy=(1, 1),
            xytext=(0, -5),
            xycoords="axes fraction",
            textcoords="offset points",
            ha="right",
            va="top",
        )

        # show the initial image
        self.im = self.ax_im.imshow(
            self.counts[:, :, :].sum(axis=2),
            cmap="viridis",
            interpolation="nearest",
            extent=[left, right, bot, top],
        )
        # and colorbar
        self.cb = self.fig.colorbar(self.im, ax=self.ax_im)

        # and the ROI mask (overlay in red)
        self.mask = np.ones(self.x_pos.shape, dtype="bool")
        self.mask_im = self.ax_im.imshow(
            self._overlay_image,
            interpolation="nearest",
            extent=[left, right, bot, top],
            zorder=self.im.get_zorder(),
        )
        self.mask_im.mouseover = False  # do not consider for mouseover text
        (self.overlay_plot, ) = self.ax_im.plot(
            [],
            [],
            marker="o",
            markersize=5,
            markerfacecolor="none",
            markeredgecolor="red",
        )
        # set up the spectrum, to start average everything
        (self.spec, ) = self.ax_spec.plot(self.counts.mean(axis=(0, 1)), lw=2)

        # set up the selector widget for the specturm
        self.selector = mwidgets.SpanSelector(
            self.ax_spec,
            self._on_span,
            "horizontal",
            useblit=True,
            minspan=2,
            span_stays=True,
        )
        # placeholder for the lasso selector
        self.lasso = None
        # hook up the mouse events for the XRF map
        self.cid = self.fig.canvas.mpl_connect("button_press_event",
                                               self._on_click)
Beispiel #25
0
import matplotlib.pyplot as plt
import matplotlib.widgets as mwidgets
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [10, 50, 100])


def onselect(vmin, vmax):
    print(vmin, vmax)


rectprops = dict(facecolor='blue', alpha=0.5)
span = mwidgets.SpanSelector(ax, onselect, 'horizontal', rectprops=rectprops)
fig.show()
Beispiel #26
0
    def __init__(self,
                 inst,
                 controls=True,
                 xlim=None,
                 ylim=None,
                 zlim=None,
                 focus=None,
                 style='dark_background',
                 **kwargs):
        plt.style.use(style)

        self.inst = inst
        self.controls = controls
        self._populate_offset_dict()

        self.fig = plt.figure(**kwargs)
        self.ax_zx = self.fig.add_subplot(2, 2, 1)
        self.ax_zy = self.fig.add_subplot(2, 2, 2)
        self.ax_xy = self.fig.add_subplot(2, 2, 3)
        self.ax_or = self.fig.add_subplot(2, 2, 4, projection='3d')
        self._draw_labels()

        self.offset = [0, 0, 0]

        if self.controls:
            plt.subplots_adjust(left=0.05, right=0.7)

            rectprops = dict(facecolor='blue', alpha=0.5)
            self.xlim_span_ax = plt.axes([0.72, 0.3, 0.25, 0.03])
            self.xlim_span_ax.set_yticks([])
            self.xlim_span = wid.SpanSelector(self.xlim_span_ax,
                                              self._inst_xlim_change,
                                              'horizontal',
                                              rectprops=rectprops)
            xlim_span_label = self._create_text("xlim",
                                                [0.72, 0.25, 0.25, 0.03])

            self.ylim_span_ax = plt.axes([0.72, 0.2, 0.25, 0.03])
            self.ylim_span_ax.set_yticks([])
            self.ylim_span = wid.SpanSelector(self.ylim_span_ax,
                                              self._inst_ylim_change,
                                              'horizontal',
                                              rectprops=rectprops)
            ylim_span_label = self._create_text("ylim",
                                                [0.72, 0.15, 0.25, 0.03])

            self.zlim_span_ax = plt.axes([0.72, 0.1, 0.25, 0.03])
            self.zlim_span_ax.set_yticks([])
            self.zlim_span = wid.SpanSelector(self.zlim_span_ax,
                                              self._inst_zlim_change,
                                              'horizontal',
                                              rectprops=rectprops)
            zlim_span_label = self._create_text("zlim",
                                                [0.72, 0.05, 0.25, 0.03])

            self.comp_focus_textbox_ax = plt.axes([0.72, 0.35, 0.25, 0.63],
                                                  facecolor='grey')
            self.comp_focus_buttons = wid.RadioButtons(
                self.comp_focus_textbox_ax,
                tuple(kr.comp_name for kr in self.inst.kernel_refs))
            self.comp_focus_buttons.on_clicked(self._inst_comp_focus)
            #self.comp_focus_textbox = wid.TextBox(self.comp_focus_textbox_ax, "", color='.1', hovercolor='.15')
            #self.comp_focus_textbox.on_text_change(self._inst_comp_focus)
            #comp_focus_label = self._create_text("Focussed component", [0.72, 0.45, 0.25, 0.03]

        if focus:
            self._inst_comp_focus(focus)

        if xlim:
            self._inst_xlim_change(xlim[0], xlim[1])

        if ylim:
            self._inst_ylim_change(ylim[0], ylim[1])

        if zlim:
            self._inst_zlim_change(zlim[0], zlim[1])
Beispiel #27
0
    def __init__(self, counts, positions, fig=None, pos_order=None, norm=None):

        if pos_order is None:
            pos_order = {'x': 0, 'y': 1}
        # extract x/y data
        self.x_pos = xpos = positions[pos_order['x']]
        self.y_pos = ypos = positions[pos_order['y']]
        self.points = np.transpose((xpos.ravel(), ypos.ravel()))
        # sort ouf the normalization
        if norm is None:
            norm = np.ones_like(self.x_pos)

        norm = np.atleast_3d(norm[:])
        self.counts = counts[:] / norm

        # compute values we will use for extents below
        dx = np.diff(xpos.mean(axis=0)).mean()
        dy = np.diff(ypos.mean(axis=1)).mean()
        left = xpos[:, 0].mean() - dx / 2
        right = xpos[:, -1].mean() + dx / 2
        top = ypos[0].mean() - dy / 2
        bot = ypos[-1].mean() + dy / 2

        # create a figure if we must
        if fig is None:
            import matplotlib.pyplot as plt
            fig = plt.figure(tight_layout=True)
        # clear the figure
        fig.clf()
        # set the window title (look at the tool bar)
        fig.canvas.set_window_title('XRF map')
        self.fig = fig
        # set up the figure layout
        gs = gridspec.GridSpec(2, 1, height_ratios=[4, 1])

        # set up the top panel (the map)
        self.ax_im = fig.add_subplot(gs[0, 0], gid='imgmap')
        self.ax_im.set_xlabel('x [?]')
        self.ax_im.set_ylabel('y [?]')
        self.ax_im.set_title('shift-click to select pixel, '
                             'alt-drag to draw region, '
                             'right-click to reset')

        # set up the lower axes (the average spectrum of the ROI)
        self.ax_spec = fig.add_subplot(gs[1, 0], gid='spectrum')
        self.ax_spec.set_ylabel('counts [?]')
        self.ax_spec.set_xlabel('bin number')
        self.ax_spec.set_yscale('log')
        self.ax_spec.set_title('click-and-drag to select energy region')
        self._EROI_txt = self.ax_spec.annotate('ROI: all',
                                               xy=(0, 1),
                                               xytext=(0, 5),
                                               xycoords='axes fraction',
                                               textcoords='offset points')
        self._pixel_txt = self.ax_spec.annotate('map average',
                                                xy=(1, 1),
                                                xytext=(0, 5),
                                                xycoords='axes fraction',
                                                textcoords='offset points',
                                                ha='right')

        # show the initial image
        self.im = self.ax_im.imshow(self.counts[:, :, :].sum(axis=2),
                                    cmap='viridis',
                                    interpolation='nearest',
                                    extent=[left, right, bot, top])
        # and colorbar
        self.cb = self.fig.colorbar(self.im, ax=self.ax_im)

        # and the ROI mask (overlay in red)
        self.mask = np.ones(self.x_pos.shape, dtype='bool')
        self.mask_im = self.ax_im.imshow(self._overlay_image,
                                         interpolation='nearest',
                                         extent=[left, right, bot, top],
                                         zorder=self.im.get_zorder())
        self.mask_im.mouseover = False  # do not consider for mouseover text

        # set up the spectrum, to start average everything
        self.spec, = self.ax_spec.plot(self.counts.mean(axis=(0, 1)), lw=2)

        # set up the selector widget for the specturm
        self.selector = mwidgets.SpanSelector(self.ax_spec,
                                              self._on_span,
                                              'horizontal',
                                              useblit=True,
                                              minspan=2,
                                              span_stays=True)
        # placeholder for the lasso selector
        self.lasso = None
        # hook up the mouse events for the XRF map
        self.cid = self.fig.canvas.mpl_connect('button_press_event',
                                               self._on_click)
Beispiel #28
0
def polypatch(figure, axes, line2D, verbose=False):
    '''
    
    Description:

        Given a plot of Y vs X, select an interval of X and fit a polynomial to
        the data.

        Optionally, select a sub-interval of X to be ignored by the fit.

        IMPORTANT: The code forces the fit to pass through the two last and two
        first data point in the selected interval. This in order to achieve a 
        smoother mathing between the data and the fit. As a result, the degree 
        of the fit must be 3 or higher. This is done by means of Lagrange
        multipliers.

        The figure given as input can contain a legend, title, labels, etc.

    Inputs:

        figure:

            It refers to the figure object from Matplotlib.

        axes: 

            It refers to the axes object from Matplotlib.

        line2D:

            It refers to the line2D object from Matplotlib.

    Optional inputs:

        verbose:

            Print additional information on the terminal. Often useful for
            debugging.

    Output:

        The program returns a tupe where the first element is a mask which 
        contains the indices of the orifinal X corresponding to the fitted 
        interval. The second element are the new values of that interval.  

    Example:

        import numpy as np
        import matplotlib.pyplot as plt
        from polypatch import polypatch

        # Sample data
        x = np.arange(0.25,1.50,0.01) 
        sigma=0.05; mu=1
        gaussian = 1/(sigma*np.sqrt(2*np.pi))*np.exp(-(x-mu)**2/(2*sigma**2) )
        y = 1 + 0.5*x - x**2 + 0.5*x**3 + 0.1*gaussian 
        
        # Making a plot  
        figure = plt.figure()  
        axes = plt.axes()
        axes.set_title('Example')
        axes.set_ylabel('Y data')
        axes.set_xlabel('X data')
        line2d, = plt.plot(x,y) # Mind the comma!                                           
         
        # Fitting a polynomial interactively
        mask, fit = polypatch(figure, axes, line2d)

        # Integration of the fit values into the original data
        y_modified = y.copy()
        y_modified[mask] = fit

        # Plot original data and modified data
        figure = plt.figure()  
        axes = plt.axes()
        axes.set_title('Example')
        axes.set_ylabel('Y data')
        axes.set_xlabel('X data')
        plt.plot(x,y,label='original data', color='black')
        plt.plot(x,y_modified,label='modified data', color='red')
        plt.legend(loc='best')
        plt.show()

        


    '''
    def window_info(_):
        '''Display information about how to use'''
        # Text separators
        l1 = '--------------------------------------------------------------------------'
        l2 = '=========================================================================='
        # Info text
        title = 'Info'
        t0 = '>> To enable recognition of the left and right buttons, first hit enter <<'
        t1 = '> The left button selects the interval for the fit by dragging on the plot.'
        t2 = '> The right button selects an interval excluded to by excluded from the fit.'
        t3 = '> Press the button [Add fit] to generate the fit.'
        t4 = '> Mark the checkbox [Not refresh fit] to overplot different fits.'
        t5 = '> When closing plot, you will be asked whether to save the changes.'
        # Message to display
        message = ('\n\n' + '\n\n'.join(
            [l2, t0, l2, t1, l1, t2, l1, t3, l1, t4, l1, t5, l1]) + '\n\n')
        # Create blank windows
        window = tkinter.Tk()
        # Create title
        window.title(title)
        # Add content and organize its geometry
        tkinter.Label(window, text=message, justify='left').pack()
        # Modify canvas and organize its geometry
        tkinter.Canvas(window, width=600, height=0).pack()
        # Display the window
        window.mainloop()

    def window_error():
        '''Display information about how to use'''
        title = 'Error'
        text = 'Please input an integer equal or greater than 3.'
        message = ('\n\n' + text + '\n\n')
        window = tkinter.Tk()
        window.title(title)
        tkinter.Label(window, text=message, justify='center').pack()
        tkinter.Canvas(window, width=600, height=0).pack()
        window.mainloop()

    def read_keystroke(event):
        '''Get the pressed key over the axes during plot visualization'''
        ivar['keystroke'] = event.key
        if verbose:
            print("ivar['keystroke'] = {}".format(ivar['keystroke']))

    def read_button(event):
        '''Get the pressed button over the axes during plot visualization'''
        ivar['pressed_button'] = event.button
        if verbose:
            print("ivar['pressed_button']", ivar['pressed_button'])

    def read_polynomial_degree(text):
        '''Get the input text in the textbox during plot visualization'''
        if text.isdigit() and np.int(text) > 2:
            ivar['polynomial_degree'] = np.int(text)
        else:
            window_error()
            # Keep the previous value and display it on the check box.
            interface['textbox_polynomial_degree'].textbox.set_val(
                ivar['polynomial_degree'])
        if verbose:
            print("ivar['polynomial_degree'] = {}".format(
                ivar['polynomial_degree']))

    def button_add_fit(event):
        '''Add the fit to the plot'''
        nonlocal fit_function

        if fit_interval_ready:
            # If a previous fit, clear it
            clear_line2D(figure, lines2D['fit'], axes, redraw=False)
            if not ivar['not_refresh_flag']:
                clear_line2D(figure, lines2D['fit_denser'], axes, redraw=False)

            # Get current colors in the axis to not repeat them
            colors = [l.get_color() for l in axes.get_lines()]

            # Fit
            if mask['nonfit'] is not None:
                if interval['xmin_nonfit'] > interval['xmin_fit'] and interval[
                        'xmax_nonfit'] < interval['xmax_fit']:
                    mask_fit_minus_nonfit = np.logical_xor(
                        mask['fit'], mask['nonfit'])
                else:
                    print(
                        '**The non fit interval is outside the fit interval. It will be ignored.**'
                    )
                    mask_fit_minus_nonfit = mask['fit'].copy()
            else:
                mask_fit_minus_nonfit = mask['fit'].copy()

            xfit = x[mask_fit_minus_nonfit]
            yfit = y[mask_fit_minus_nonfit]

            # Force the fit to match the fist two data points and the last two data points to promote a smoother match with the original
            xfit_fixed = np.concatenate([[xfit[0]], [xfit[1]], [xfit[-2]],
                                         [xfit[-1]]])
            yfit_fixed = np.concatenate([[yfit[0]], [yfit[1]], [yfit[-2]],
                                         [yfit[-1]]])
            # Fit
            fit_function = np.poly1d(
                polyfit_with_fixed_points(ivar['polynomial_degree'], xfit,
                                          yfit, xfit_fixed, yfit_fixed))
            color = 'lime' if not 'lime' in colors else None
            lines2D['fit'], = axes.plot(x[mask['fit']],
                                        fit_function(x[mask['fit']]),
                                        linestyle='None',
                                        marker='o',
                                        color=color,
                                        markerfacecolor=color,
                                        markeredgecolor='None')

            # Plot a denser x to evidence possible wiggles between the original data
            points_in_between = np.arange(0.0, 1.0, 0.1)
            x_mask_diff = np.diff(x[mask['fit']])
            x_mask_denser = np.array([])
            for shift in points_in_between:
                x_mask_denser = np.concatenate(
                    [x_mask_denser, x[mask['fit']][:-1] + x_mask_diff * shift])
            # Add the last point
            x_mask_denser = np.concatenate(
                [x_mask_denser, np.array([x[mask['fit']][-1]])])
            x_mask_denser = np.sort(x_mask_denser)
            color = lines2D['fit'].get_color()
            lines2D['fit_denser'], = axes.plot(
                x_mask_denser,
                fit_function(x_mask_denser),
                linestyle='solid',
                marker=None,
                color=color,
                label='Polynomial fit n={}'.format(ivar['polynomial_degree']))
            list_fit_denser_line2D.append(lines2D['fit_denser'])

        # Redraw
        axes.legend(loc='best', ncol=1, framealpha=0.5, fontsize=10)
        figure.canvas.draw()

    def button_clear_fit(event):
        '''Clear the fits curves from the plot'''
        nonlocal list_fit_denser_line2D
        nonlocal fit_function
        clear_line2D(figure, lines2D['fit'], axes, redraw=True)
        for line2D in list_fit_denser_line2D:
            clear_line2D(figure, line2D, axes, redraw=True)
        fit_function = None

    def check_box_switch(label):
        '''Invert the flag of not refresh'''
        ivar['not_refresh_flag'] = not ivar['not_refresh_flag']
        interface['checkbox'].checkbox.rectangles[0].set_fill(
            ivar['not_refresh_flag'])
        figure.canvas.draw()

    def onselect(vmin, vmax):
        '''Select the interval for the fit and the interval to be excluded in the fit'''

        nonlocal fit_interval_ready

        # Interval to fit
        # Activate by pressing Enter and then using the left button
        if ivar['keystroke'] == 'enter' and ivar['pressed_button'] == 1:
            clear_line2D(figure, lines2D['fit_interval'], axes, redraw=False)
            # Store the values
            interval['xmin_fit'] = vmin
            interval['xmax_fit'] = vmax
            # Print the interval
            print('Interval for the fit:')
            print('xmin = {:.3},\t xmax = {:.3}\n'.format(vmin, vmax))
            # Get the indices of the values within the selected span
            condition1_fit = interval['xmin_fit'] < x
            condition2_fit = x < interval['xmax_fit']
            mask['fit'] = np.logical_and(condition1_fit, condition2_fit)
            # Plot in red the selected span as an aditional Line2D object in lines
            if interval['xmin_fit'] != interval['xmax_fit']:
                lines2D['fit_interval'], = axes.plot(x[mask['fit']],
                                                     y[mask['fit']],
                                                     linestyle='None',
                                                     marker='o',
                                                     markerfacecolor='red',
                                                     markeredgecolor='None',
                                                     label='Fit interval')
                fit_interval_ready = True
            else:
                fit_interval_ready = False

        # Interval to exclude
        # Activate by pressing Enter and then using the right button OR pressing Shift+Enter and the using left button
        if (ivar['keystroke'] == 'shift+enter' and ivar['pressed_button']
                == 1) or (ivar['keystroke'] == 'enter'
                          and ivar['pressed_button'] == 3):
            clear_line2D(figure, lines2D['v1'], axes, redraw=False)
            clear_line2D(figure, lines2D['v2'], axes, redraw=False)
            interval['xmin_nonfit'] = vmin
            interval['xmax_nonfit'] = vmax
            # Print the interval
            print('Interval to be excluded in the fit:')
            print('xmin = {:.3},\t xmax = {:.3}\n'.format(vmin, vmax))
            # Get the indices of the values within the selected span
            condition1_nonfit = interval['xmin_nonfit'] < x
            condition2_nonfit = x < interval['xmax_nonfit']
            mask['nonfit'] = np.logical_and(condition1_nonfit,
                                            condition2_nonfit)
            # Plot in black the selected span
            if interval['xmin_nonfit'] != interval['xmax_nonfit']:
                lines2D['v1'] = axes.axvline(interval['xmin_nonfit'],
                                             label='Nonfit interval',
                                             linestyle='dashed',
                                             color='black')
                lines2D['v2'] = axes.axvline(interval['xmax_nonfit'],
                                             linestyle='dashed',
                                             color='black')

        # Redraw
        axes.legend(loc='best', ncol=1, framealpha=0.5, fontsize=10)
        figure.canvas.draw()

    ### Initialize variables

    # Curves in the plot
    lines2D = {
        'fit': None,
        'fit_interval': None,
        'fit_denser': None,
        'v1': None,
        'v2': None
    }
    # Masks
    mask = {'fit': None, 'nonfit': None}
    # Variable to store the fit
    fit_function = None
    # Interval's extrema
    interval = {
        'xmin_fit': None,
        'xmax_fit': None,
        'xmin_nonfit': None,
        'xmax_nonfit': None
    }
    # Interactive variables
    ivar = {
        'keystroke': None,
        'pressed_button': None,
        'polynomial_degree': 3,
        'not_refresh_flag': False
    }
    # List where to store curves of different fits
    list_fit_denser_line2D = list()
    # Flags
    fit_interval_ready = False

    # Make space for the interface of buttons
    plt.subplots_adjust(bottom=0.2)

    # Get the data
    x = line2D.get_xdata()
    y = line2D.get_ydata()

    # Connect ID to the plot visualization
    cid_key = figure.canvas.mpl_connect('key_press_event', read_keystroke)
    cid_button = figure.canvas.mpl_connect('button_press_event', read_button)

    # Biuld interface: Buttons, checkbox and textbox
    height = 0.04
    width = 0.1
    position = [(0.65, 0.07)]
    button_addfit             = Button(  function=button_add_fit,\
                                         text='Add fit',\
                                         coords=[0.65, 0.07, width, height] )
    button_clearfit           = Button(  function=button_clear_fit,\
                                         text='Clear fit',\
                                         coords=[0.76, 0.07, width, height] )
    button_help               = Button(  function=window_info,\
                                         text='Help',\
                                         coords=[0.76, 0.02, width, height] )
    checkbox                  = Checkbox(function=check_box_switch,\
                                         label='Not refresh fit',\
                                         coords=[0.65, 0.02, width, 0.040],\
                                         type=2)
    textbox_polynomial_degree = Textbox( function=read_polynomial_degree,\
                                         prompt_text='Polynomial degree for the fit = ',\
                                         initial_text='{}'.format(ivar['polynomial_degree']),\
                                         coords=[0.45, 0.05, 0.05, 0.05])

    interface = {
        'button_addfit': button_addfit,
        'button_clearfit': button_clearfit,
        'button_help': button_help,
        'checkbox': checkbox,
        'textbox_polynomial_degree': textbox_polynomial_degree
    }

    # Properties of the rectangle-span area-selector
    rect_props = dict(facecolor='cyan', alpha=0.20)
    # Area selector
    span = mwidgets.SpanSelector(axes,
                                 onselect,
                                 'horizontal',
                                 rectprops=rect_props)

    # Display plot in a maximazed window
    mng = plt.get_current_fig_manager()
    mng.full_screen_toggle()
    plt.show()

    # Disconnect from the plot visuzlization
    for cid in [cid_key, cid_button]:
        figure.canvas.mpl_disconnect(cid)

    # Print the selected intervals
    print('\n')
    print('=========================================')
    print('Interval for the fit:')
    print('xmin = {:.3}, \txmax = {:.3}'.format(interval['xmin_fit'],
                                                interval['xmax_fit']))
    print('=========================================')
    print('Interval excluded from the fit:')
    print('xmin = {:.3}, \txmax = {:.3}'.format(interval['xmin_nonfit'],
                                                interval['xmax_nonfit']))
    print('=========================================')
    print('Polynomial degree of the fit = {}'.format(
        ivar['polynomial_degree']))
    print('=========================================')
    print('\n')

    # Return velues
    if fit_function != None:
        return mask['fit'], fit_function(x[mask['fit']])
    else:
        return None, None
Beispiel #29
0
    def __init__(self, counts, positions, fig=None, pos_order=None,
                 norm=None):

        if pos_order is None:
            pos_order = {'x': 0,
                         'y': 1}

        self.x_pos = xpos = positions[pos_order['x']]
        self.y_pos = ypos = positions[pos_order['y']]
        self.points = np.transpose((xpos.ravel(), ypos.ravel()))
        if norm is None:
            norm = np.ones_like(self.x_pos)

        norm = np.atleast_3d(norm[:])

        # TODO do not normalize up from?
        self.counts = counts[:] / norm

        dx = np.diff(xpos.mean(axis=0)).mean()
        dy = np.diff(ypos.mean(axis=1)).mean()

        left = xpos[:, 0].mean() - dx/2
        right = xpos[:, -1].mean() + dx/2

        top = ypos[0].mean() - dy/2
        bot = ypos[-1].mean() + dy/2

        if fig is None:
            import matplotlib.pyplot as plt
            fig = plt.figure(tight_layout=True)
        fig.clf()
        fig.canvas.set_window_title('XRF map')
        self.fig = fig
        gs = gridspec.GridSpec(2, 1, height_ratios=[4, 1])

        self.ax_im = fig.add_subplot(gs[0, 0], gid='imgmap')
        self.ax_im.set_xlabel('x [?]')
        self.ax_im.set_ylabel('y [?]')

        self.ax_spec = fig.add_subplot(gs[1, 0], gid='spectrum')
        self.ax_spec.set_ylabel('counts [?]')
        self.ax_spec.set_xlabel('bin number')
        self.ax_spec.set_yscale('log')

        self._EROI_txt = self.ax_spec.annotate('ROI: all',
                                               xy=(0, 1),
                                               xytext=(0, 5),
                                               xycoords='axes fraction',
                                               textcoords='offset points')
        self._pixel_txt = self.ax_spec.annotate('map average',
                                                xy=(1, 1),
                                                xytext=(0, 5),
                                                xycoords='axes fraction',
                                                textcoords='offset points',
                                                ha='right')

        self.im = self.ax_im.imshow(self.counts[:, :, :].sum(axis=2),
                                    cmap='viridis',
                                    interpolation='nearest',
                                    extent=[left, right, bot, top]
                                    )

        self.xy_plt = self.ax_im.plot(xpos.ravel(), ypos.ravel(), 'wo',
                                      visible=False)

        self.cb = self.fig.colorbar(self.im, ax=self.ax_im)

        self.mask = np.ones(self.x_pos.shape, dtype='bool')
        self.mask_im = self.ax_im.imshow(self._make_overlay,
                                         interpolation='nearest',
                                         extent=[left, right, bot, top],
                                         zorder=self.im.get_zorder())

        # do not consider for mouseover text
        self.mask_im.mouseover = False
        self.spec, = self.ax_spec.plot(
            self.counts.mean(axis=(0, 1)),
            lw=2)

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

        self.selector = mwidgets.SpanSelector(self.ax_spec,
                                              self._on_span,
                                              'horizontal',
                                              useblit=True, minspan=2,
                                              span_stays=True)
        self.lasso = None
Beispiel #30
0
    def analyze(self,
                norm: bool = True,
                portrait: bool = True,
                blit: bool = False):
        if self.freq_arr is None:
            raise RuntimeError
        if self.resp_arr is None:
            raise RuntimeError

        import matplotlib.pyplot as plt
        try:
            from resonator_tools import circuit
            import matplotlib.widgets as mwidgets
            _do_fit = True
        except ImportError:
            _do_fit = False

        nr_amps = len(self.amp_arr)
        self._AMP_IDX = nr_amps // 2

        if norm:
            resp_scaled = np.zeros_like(self.resp_arr)
            for jj in range(nr_amps):
                resp_scaled[jj] = self.resp_arr[jj] / self.amp_arr[jj]
        else:
            resp_scaled = self.resp_arr

        resp_dB = 20. * np.log10(np.abs(resp_scaled))
        amp_dBFS = 20 * np.log10(self.amp_arr / 1.0)

        # choose limits for colorbar
        cutoff = 1.  # %
        lowlim = np.percentile(resp_dB, cutoff)
        highlim = np.percentile(resp_dB, 100. - cutoff)

        # extent
        x_min = 1e-9 * self.freq_arr[0]
        x_max = 1e-9 * self.freq_arr[-1]
        dx = 1e-9 * (self.freq_arr[1] - self.freq_arr[0])
        y_min = amp_dBFS[0]
        y_max = amp_dBFS[-1]
        dy = amp_dBFS[1] - amp_dBFS[0]

        if portrait:
            fig1 = plt.figure(tight_layout=True, figsize=(6.4, 9.6))
            ax1 = fig1.add_subplot(2, 1, 1)
            # fig1 = plt.figure(tight_layout=True)
            # ax1 = fig1.add_subplot(1, 1, 1)
        else:
            fig1 = plt.figure(tight_layout=True, figsize=(12.8, 4.8))
            ax1 = fig1.add_subplot(1, 2, 1)
        im = ax1.imshow(
            resp_dB,
            origin='lower',
            aspect='auto',
            interpolation='none',
            extent=(x_min - dx / 2, x_max + dx / 2, y_min - dy / 2,
                    y_max + dy / 2),
            vmin=lowlim,
            vmax=highlim,
        )
        line_sel = ax1.axhline(amp_dBFS[self._AMP_IDX],
                               ls="--",
                               c="k",
                               lw=3,
                               animated=blit)
        # ax1.set_title(f"amp = {amp_arr[AMP_IDX]:.2e}")
        ax1.set_xlabel("Frequency [GHz]")
        ax1.set_ylabel("Drive amplitude [dBFS]")
        cb = fig1.colorbar(im)
        if portrait:
            cb.set_label("Response amplitude [dB]")
        else:
            ax1.set_title("Response amplitude [dB]")
        fig1.show()
        # return fig1

        if portrait:
            ax2 = fig1.add_subplot(4, 1, 3)
            ax3 = fig1.add_subplot(4, 1, 4, sharex=ax2)
        else:
            ax2 = fig1.add_subplot(2, 2, 2)
            ax3 = fig1.add_subplot(2, 2, 4, sharex=ax2)
            ax2.yaxis.set_label_position("right")
            ax2.yaxis.tick_right()
            ax3.yaxis.set_label_position("right")
            ax3.yaxis.tick_right()

        line_a, = ax2.plot(1e-9 * self.freq_arr,
                           resp_dB[self._AMP_IDX],
                           label="measured",
                           animated=blit)
        line_p, = ax3.plot(1e-9 * self.freq_arr,
                           np.angle(self.resp_arr[self._AMP_IDX]),
                           animated=blit)
        if _do_fit:
            line_fit_a, = ax2.plot(1e-9 * self.freq_arr,
                                   np.full_like(self.freq_arr, np.nan),
                                   ls="--",
                                   label="fit",
                                   animated=blit)
            line_fit_p, = ax3.plot(1e-9 * self.freq_arr,
                                   np.full_like(self.freq_arr, np.nan),
                                   ls="--",
                                   animated=blit)

        f_min = 1e-9 * self.freq_arr.min()
        f_max = 1e-9 * self.freq_arr.max()
        f_rng = f_max - f_min
        a_min = resp_dB.min()
        a_max = resp_dB.max()
        a_rng = a_max - a_min
        p_min = -np.pi
        p_max = np.pi
        p_rng = p_max - p_min
        ax2.set_xlim(f_min - 0.05 * f_rng, f_max + 0.05 * f_rng)
        ax2.set_ylim(a_min - 0.05 * a_rng, a_max + 0.05 * a_rng)
        ax3.set_xlim(f_min - 0.05 * f_rng, f_max + 0.05 * f_rng)
        ax3.set_ylim(p_min - 0.05 * p_rng, p_max + 0.05 * p_rng)

        ax3.set_xlabel("Frequency [GHz]")
        ax2.set_ylabel("Response amplitude [dB]")
        ax3.set_ylabel("Response phase [rad]")

        ax2.legend(loc="lower right")

        def onbuttonpress(event):
            if event.inaxes == ax1:
                self._AMP_IDX = np.argmin(np.abs(amp_dBFS - event.ydata))
                update()

        def onkeypress(event):
            if event.inaxes == ax1:
                if event.key == "up":
                    self._AMP_IDX += 1
                    if self._AMP_IDX >= len(amp_dBFS):
                        self._AMP_IDX = len(amp_dBFS) - 1
                    update()
                elif event.key == "down":
                    self._AMP_IDX -= 1
                    if self._AMP_IDX < 0:
                        self._AMP_IDX = 0
                    update()

        def update():
            line_sel.set_ydata(
                [amp_dBFS[self._AMP_IDX], amp_dBFS[self._AMP_IDX]])
            # ax1.set_title(f"amp = {amp_arr[AMP_IDX]:.2e}")
            print(
                f"drive amp {self._AMP_IDX:d}: {self.amp_arr[self._AMP_IDX]:.2e} FS = {amp_dBFS[self._AMP_IDX]:.1f} dBFS"
            )
            line_a.set_ydata(resp_dB[self._AMP_IDX])
            line_p.set_ydata(np.angle(self.resp_arr[self._AMP_IDX]))
            if _do_fit:
                line_fit_a.set_ydata(np.full_like(self.freq_arr, np.nan))
                line_fit_p.set_ydata(np.full_like(self.freq_arr, np.nan))
            # ax2.set_title("")
            if blit:
                fig1.canvas.restore_region(self._bg)
                ax1.draw_artist(line_sel)
                ax2.draw_artist(line_a)
                ax3.draw_artist(line_p)
                fig1.canvas.blit(fig1.bbox)
                fig1.canvas.flush_events()
            else:
                fig1.canvas.draw()

        if _do_fit:

            def onselect(xmin, xmax):
                port = circuit.notch_port(self.freq_arr,
                                          self.resp_arr[self._AMP_IDX])
                port.autofit(fcrop=(xmin * 1e9, xmax * 1e9))
                if norm:
                    line_fit_a.set_data(
                        1e-9 * port.f_data, 20 * np.log10(
                            np.abs(port.z_data_sim /
                                   self.amp_arr[self._AMP_IDX])))
                else:
                    line_fit_a.set_data(1e-9 * port.f_data,
                                        20 * np.log10(np.abs(port.z_data_sim)))
                line_fit_p.set_data(1e-9 * port.f_data,
                                    np.angle(port.z_data_sim))
                # print(port.fitresults)
                print("----------------")
                print(f"fr = {port.fitresults['fr']}")
                print(f"Qi = {port.fitresults['Qi_dia_corr']}")
                print(f"Qc = {port.fitresults['Qc_dia_corr']}")
                print(f"Ql = {port.fitresults['Ql']}")
                print(
                    f"kappa = {port.fitresults['fr'] / port.fitresults['Qc_dia_corr']}"
                )
                print("----------------")
                # ax2.set_title(
                #     f"fr = {1e-6*fr:.0f} MHz, Ql = {Ql:.0f}, Qi = {Qi:.0f}, Qc = {Qc:.0f}, kappa = {1e-3*kappa:.0f} kHz")
                if blit:
                    fig1.canvas.restore_region(self._bg)
                    ax1.draw_artist(line_sel)
                    ax2.draw_artist(line_a)
                    ax2.draw_artist(line_fit_a)
                    ax3.draw_artist(line_p)
                    ax3.draw_artist(line_fit_p)
                    fig1.canvas.blit(fig1.bbox)
                    fig1.canvas.flush_events()
                else:
                    fig1.canvas.draw()

            rectprops = dict(facecolor='tab:gray', alpha=0.5)
            fig1._span_a = mwidgets.SpanSelector(ax2,
                                                 onselect,
                                                 'horizontal',
                                                 rectprops=rectprops,
                                                 useblit=blit)
            fig1._span_p = mwidgets.SpanSelector(ax3,
                                                 onselect,
                                                 'horizontal',
                                                 rectprops=rectprops,
                                                 useblit=blit)

        fig1.canvas.mpl_connect('button_press_event', onbuttonpress)
        fig1.canvas.mpl_connect('key_press_event', onkeypress)
        fig1.show()
        if blit:
            fig1.canvas.draw()
            fig1.canvas.flush_events()
            self._bg = fig1.canvas.copy_from_bbox(fig1.bbox)
            ax1.draw_artist(line_sel)
            ax2.draw_artist(line_a)
            ax3.draw_artist(line_p)
            fig1.canvas.blit(fig1.bbox)

        return fig1