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()
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)
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)
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
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()