예제 #1
0
    def _add_spectrum(self):
        """Adds the spectrum to the plot, makes the points pickable."""
        color = None
        if self._single_color:
            color = self.color
        for ds in self.data:
            spectrum_point = self.ax.scatter(
                ds.eigenvalues.real * self.x_scaling,
                ds.eigenvalues.imag * self.y_scaling,
                marker=self.marker,
                s=6 * self.markersize,
                c=color,
                alpha=self.alpha,
                label=ds.datfile.stem,
                **self.plot_props,
            )
            setattr(spectrum_point, "dataset", ds)
            add_pickradius_to_item(item=spectrum_point, pickradius=10)
            self.leg_handle.add(spectrum_point)
        self.ax.axhline(y=0, linestyle="dotted", color="grey", alpha=0.3)
        self.ax.axvline(x=0, linestyle="dotted", color="grey", alpha=0.3)
        self.ax.set_xlabel(r"Re($\omega$)")
        self.ax.set_ylabel(r"Im($\omega$)")

        if self._use_legend:
            self.leg_handle.legend = self.ax.legend(loc="best")
            self.leg_handle._make_visible_by_default = True
        self.fig.tight_layout()
예제 #2
0
 def _add_spectrum(self):
     """Adds the spectrum to the plot, makes the points pickable."""
     (spectrum_point, ) = self.ax.plot(
         self.w_real * self.x_scaling,
         self.w_imag * self.y_scaling,
         marker=self.marker,
         color=self.color,
         markersize=self.markersize,
         alpha=self.alpha,
         linestyle="None",
         **self.plot_props,
     )
     # set dataset associated with this line of points
     setattr(spectrum_point, "dataset", self.dataset)
     add_pickradius_to_item(item=spectrum_point, pickradius=10)
     self.ax.axhline(y=0, linestyle="dotted", color="grey", alpha=0.3)
     self.ax.axvline(x=0, linestyle="dotted", color="grey", alpha=0.3)
     self.ax.set_xlabel(r"Re($\omega$)")
     self.ax.set_ylabel(r"Im($\omega$)")
     self.ax.set_title(self.dataset.eq_type)
예제 #3
0
 def _add_spectrum(self):
     """
     Draw method, creates the spectrum.
     """
     for i, ds in enumerate(self.dataseries):
         (spectrum_point, ) = self.ax.plot(
             self.xdata[i] * np.ones_like(self.ydata[i], dtype=float) *
             self.x_scaling[i],
             self.ydata[i] * self.y_scaling[i],
             marker=self.marker,
             color=self.color,
             markersize=self.markersize,
             alpha=self.alpha,
             linestyle="None",
             **self.plot_props,
         )
         add_pickradius_to_item(item=spectrum_point, pickradius=10)
         # set dataset associated with this line of points
         setattr(spectrum_point, "dataset", ds)
     self.ax.axhline(y=0, linestyle="dotted", color="grey", alpha=0.3)
     self.ax.axvline(x=0, linestyle="dotted", color="grey", alpha=0.3)
예제 #4
0
 def make_legend_pickable(self):
     """
     Makes the legend pickable, only used if interactive.
     """
     legend_handles = self.legend.legendHandles
     handle_labels = [handle.get_label() for handle in legend_handles]
     # we need a mapping of the legend item to the actual item that was drawn
     for i, drawn_item in enumerate(self._drawn_items):
         # TODO: for some reason fill_between returns empty handles such that
         #       the code below errors out. The try-except clause is an attempt
         #       to fix it and _should_ work. This relies on the ordening of the
         #       legend items when they are drawn, but should be thorougly tested.
         try:
             idx = handle_labels.index(drawn_item.get_label())
             legend_item = self.legend.legendHandles[idx]
         except ValueError:
             idx = i
             legend_item = self.legend.legendHandles[idx]
             # fix empty label
             legend_item.set_label(drawn_item.get_label())
         if not drawn_item.get_label() == legend_item.get_label():
             raise ValueError(
                 f"something went wrong in mapping legend items to drawn items. \n"
                 f"Tried to map {legend_item} (label '{legend_item.get_label()}')"
                 f" to {drawn_item} (label '{drawn_item.get_label()}') \n"
             )
         add_pickradius_to_item(item=legend_item, pickradius=self.pickradius)
         # add an attribute to this artist to tell it's from a legend
         setattr(legend_item, "is_legend_item", True)
         # we make the regions invisible until clicked, or set visible as default
         if self._make_visible_by_default:
             legend_item.set_alpha(self.alpha_point)
         else:
             legend_item.set_alpha(self.alpha_hidden)
         drawn_item.set_visible(self._make_visible_by_default)
         self._legend_mapping[legend_item] = drawn_item
예제 #5
0
    def on_point_pick(self, event):
        """
        Determines what happens when a pickable artist is selected.

        Parameters
        ----------
        event : ~matplotlib.backend_bases.PickEvent
            The pick event.
        """
        # comparing spectra: prevents double event triggering
        if hasattr(self, "associated_ds_ax"):
            if not event.mouseevent.inaxes == self.associated_ds_ax:
                return
        artist = event.artist
        # if artist is a legend item, return (this attribute has been set manually)
        if hasattr(artist, "is_legend_item"):
            return
        # retrieve figure and axis for this artist, save limits to prevent zoom reset
        fig, ax = artist.figure, artist.axes
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()
        # Retrieves the dataset associated with the current points.
        # This attribute has been set when the spectrum was added to the plot.
        if not hasattr(artist, "dataset"):
            return
        associated_ds = artist.dataset
        # This retrieves the indices of the clicked points. Multiple indices are
        # possible depending on an overlapping pickradius. Look which point corresponds
        # to the smallest distance to the mouse click.
        idxs = event.ind
        if isinstance(artist, PathCollection):
            # this is done for points drawn using scatter instead of plot
            xdata, ydata = np.split(artist.get_offsets(), [-1], axis=1)
            xdata = xdata.squeeze()
            ydata = ydata.squeeze()
        else:
            xdata = artist.get_xdata()
            ydata = artist.get_ydata()
        if len(idxs) == 1:
            idx = idxs[0]
        else:
            mouse_x = event.mouseevent.xdata
            mouse_y = event.mouseevent.ydata
            distances = (mouse_x - xdata[idxs])**2 + (mouse_y - ydata[idxs])**2
            idx = idxs[distances.argmin()]
        xdata = xdata[idx]
        ydata = ydata[idx]

        # if the selected point has no eigenfunctions, do nothing
        if not associated_ds.efs_written:
            pylboLogger.warn(
                f"the selected point at ({xdata: 3.2e}, {ydata: 3.2e}) "
                f"has no eigenfunctions associated with it. "
                f"(corresponding dataset: {associated_ds.datfile.stem})")
            return

        # handle left clicking
        if event.mouseevent.button == 1:
            # skip if point index is already in list
            if str(idx) in self._selected_idxs.get(associated_ds, {}).keys():
                return
            (marked_point, ) = ax.plot(
                xdata,
                ydata,
                "x",
                markersize=8,
                label="marked_point",
                alpha=0.7,
                markeredgewidth=3,
            )
            add_pickradius_to_item(item=marked_point, pickradius=1)
            # get items corresponding to this ds
            items = self._selected_idxs.get(associated_ds, {})
            items.update({f"{idx}": marked_point})
            self._selected_idxs.update({associated_ds: items})

        # handle right clicking
        elif event.mouseevent.button == 3:
            # remove selected index from list
            selected_artist = self._selected_idxs.get(associated_ds,
                                                      {}).pop(str(idx), None)
            if selected_artist is not None:
                selected_artist.remove()
                # if no items remaining for this ds, remove key
                if len(self._selected_idxs[associated_ds]) == 0:
                    self._selected_idxs.pop(associated_ds)

        # this fixes a zoom reset when picking the figure
        ax.set_xlim(xlim)
        ax.set_ylim(ylim)
        fig.canvas.draw()