def plot_qe(self, Ei, label_text, hold=False): """ Plots the Q-E diagram """ from scipy import constants E2q, meV2J = (2. * constants.m_n / (constants.hbar**2), constants.e / 1000.) en = np.linspace(-Ei / 5., Ei, 100) q2 = [] if self.engine.name == 'HYSPEC': if abs(self.hyspecS2) <= 30: self.engine.detector.tthlims = [0, abs(self.hyspecS2) + 30] else: self.engine.detector.tthlims = [ abs(self.hyspecS2) - 30, abs(self.hyspecS2) + 30 ] label_text += '_S2={}'.format(self.hyspecS2) for tth in self.engine.detector.tthlims: q = np.sqrt(E2q * (2 * Ei - en - 2 * np.sqrt(Ei * (Ei - en)) * np.cos(np.deg2rad(tth))) * meV2J) / 1e10 q2.append(np.concatenate((np.flipud(q), q))) self._set_overplot(hold, 'qeaxes') self.qeaxes_xlim = max(np.max(q2), self.qeaxes_xlim) line, = self.qeaxes.plot( np.hstack(q2), np.concatenate((np.flipud(en), en)).tolist() * len(self.engine.detector.tthlims)) line.set_label(label_text) self.qeaxes.set_xlim([0, self.qeaxes_xlim]) legend_set_draggable(self.qeaxes.legend(), True) self.qeaxes.set_xlabel(r'$|Q| (\mathrm{\AA}^{-1})$') self.qeaxes.set_ylabel('Energy Transfer (meV)') self.qecanvas.draw()
def _plot_data_workbench(self, fig_window, data): external_axes = fig_window.axes for plot_info in data: external_axis = external_axes[plot_info.axis] external_axis.plot(plot_info.workspace, specNum=plot_info.specNume, distribution=not plot_info.normalised) legend_set_draggable(external_axis.legend(), True) fig_window.show()
def test_legend_set_draggable(self): legend = create_autospec(Legend) args = (None, False, 'loc') legend_set_draggable(legend, *args) if hasattr(Legend, 'set_draggable'): legend.set_draggable.assert_called_with(*args) else: legend.draggable.assert_called_with(*args)
def plot_flux_hz(self): """ Plots the flux vs freq in the middle tab """ inst = self.engine.instname chop = self.engine.getChopper() ei = float(self.widgets['EiEdit']['Edit'].text()) overplot = self.widgets['HoldCheck'].isChecked() # Do not recalculate if one of the plots has the same parametersc _, labels = self.frqaxes2.get_legend_handles_labels() searchStr = '([A-Z]+) "(.+)" Ei = ([0-9.-]+) meV' if labels and (overplot or len(labels) == 1): for prevtitle in labels: prevInst, prevChop, prevEi = re.search(searchStr, prevtitle).groups() if inst == prevInst and chop == prevChop and abs( ei - float(prevEi)) < 0.01: return freq0 = self.engine.getFrequency() rep = self.engine.moderator.source_rep maxfreq = self.engine.chopper_system.max_frequencies freqs = range( rep, (maxfreq[0] if hasattr(maxfreq, '__len__') else maxfreq) + 1, rep) flux = np.zeros(len(freqs)) elres = np.zeros(len(freqs)) for ie, freq in enumerate(freqs): if hasattr(freq0, '__len__'): self.setFreq(manual_freq=[freq] + freq0[1:]) else: self.setFreq(manual_freq=freq) with warnings.catch_warnings(record=True): warnings.simplefilter('always', UserWarning) flux[ie] = self.engine.getFlux(ei) elres[ie] = self.engine.getResolution(0., ei)[0] if overplot: if matplotlib.compare_versions('2.1.0', matplotlib.__version__): self.frqaxes1.hold(True) self.frqaxes2.hold(True) else: self.frqaxes1.clear() self.frqaxes2.clear() self.setFreq(manual_freq=freq0) self.frqaxes1.set_xlabel('Chopper Frequency (Hz)') self.frqaxes1.set_ylabel('Flux (n/cm$^2$/s)') line, = self.frqaxes1.plot(freqs, flux, 'o-') self.frqaxes1.set_xlim([0, np.max(freqs)]) self.frqaxes2.set_xlabel('Chopper Frequency (Hz)') self.frqaxes2.set_ylabel('Elastic Resolution FWHM (meV)') line, = self.frqaxes2.plot(freqs, elres, 'o-') line.set_label('%s "%s" Ei = %5.3f meV' % (inst, chop, ei)) lg = self.frqaxes2.legend() legend_set_draggable(lg, True) self.frqaxes2.set_xlim([0, np.max(freqs)]) self.frqcanvas.draw()
def _do_plot(self, selected_columns, selected_x, plot_type): if self._is_error_plot(plot_type): yerr = self.presenter.model.marked_columns.find_yerr( selected_columns) # remove the Y error columns if they are in the selection for plotting # this prevents them from being treated as Y columns for err_col in yerr.values(): try: selected_columns.remove(err_col) except ValueError: # the column is not contained within the selected one pass if len(yerr) != len(selected_columns): column_headers = self.presenter.model.original_column_headers() self.presenter.view.show_warning( self.NO_ASSOCIATED_YERR_FOR_EACH_Y_MESSAGE.format(",".join( [column_headers[col] for col in selected_columns]))) return x = self.presenter.model.get_column(selected_x) fig, ax = self.plot.subplots(subplot_kw={"projection": "mantid"}) if fig.canvas.manager is not None: fig.canvas.manager.set_window_title( self.presenter.model.get_name()) ax.set_xlabel(self.presenter.model.get_column_header(selected_x)) ax.wsName = self.presenter.model.get_name() plot_func = self._get_plot_function_from_type(ax, plot_type) kwargs = {} for column in selected_columns: # if the errors are being plotted, retrieve the data for the column if self._is_error_plot(plot_type): yerr_column = yerr[column] yerr_column_data = self.presenter.model.get_column(yerr_column) kwargs["yerr"] = yerr_column_data y = self.presenter.model.get_column(column) column_label = self.presenter.model.get_column_header(column) try: plot_func(x, y, label=self.COLUMN_DISPLAY_LABEL.format(column_label), **kwargs) except ValueError as e: error_message = self.PLOT_FUNCTION_ERROR_MESSAGE.format(e) logger.error(error_message) self.presenter.view.show_warning( error_message, self.INVALID_DATA_WINDOW_TITLE) return ax.set_ylabel(column_label) legend_set_draggable(ax.legend(), True) fig.show()
def create_legend(cls, props, ax): if not props: legend_set_draggable(ax.legend(), True) return if int(matplotlib.__version__[0]) >= 2: legend = ax.legend( ncol=props['columns'], prop={'size': props['entries_size']}, numpoints=props['markers'], markerfirst=props['marker_position'] == "Left of Entries", frameon=props['box_visible'], fancybox=props['round_edges'], shadow=props['shadow'], framealpha=props['transparency'], facecolor=props['background_color'], edgecolor=props['edge_color'], title=props['title'], borderpad=props['border_padding'], labelspacing=props['label_spacing'], handlelength=props['marker_size'], handletextpad=props['marker_label_padding'], columnspacing=props['column_spacing']) else: legend = ax.legend( ncol=props['columns'], prop={'size': props['entries_size']}, numpoints=props['markers'], markerfirst=props['marker_position'] == "Left of Entries", frameon=props['box_visible'], fancybox=props['round_edges'], shadow=props['shadow'], framealpha=props['transparency'], title=props['title'], borderpad=props['border_padding'], labelspacing=props['label_spacing'], handlelength=props['marker_size'], handletextpad=props['marker_label_padding'], columnspacing=props['column_spacing']) title = legend.get_title() title.set_fontname(props['title_font']) title.set_fontsize(props['title_size']) title.set_color(props['title_color']) for text in legend.get_texts(): text.set_fontname(props['entries_font']) text.set_fontsize(props['entries_size']) text.set_color(props['entries_color']) legend.set_visible(props['visible']) legend_set_draggable(legend, True)
def plot_res(self): """ Plots the resolution in the resolution tab """ overplot = self.widgets['HoldCheck'].isChecked() multiplot = self.widgets['MultiRepCheck'].isChecked() self._set_overplot(overplot, 'resaxes') self._set_overplot(overplot, 'qeaxes') inst = self.engine.instname freq = self.engine.getFrequency() if hasattr(freq, '__len__'): freq = freq[0] if multiplot: if matplotlib.compare_versions('2.1.0', matplotlib.__version__): self.resaxes.hold(True) for ie, Ei in enumerate(self.eis): en = np.linspace(0, 0.95 * Ei, 200) if any(self.res[ie]): if not self.flux[ie]: continue line, = self.resaxes.plot(en, self.res[ie]) label_text = '%s_%3.2fmeV_%dHz_Flux=%fn/cm2/s' % ( inst, Ei, freq, self.flux[ie]) line.set_label(label_text) if self.tabs.isTabEnabled(self.qetabID): self.plot_qe(Ei, label_text, hold=True) self.resaxes_xlim = max(Ei, self.resaxes_xlim) if matplotlib.compare_versions('2.1.0', matplotlib.__version__): self.resaxes.hold(False) else: ei = self.engine.getEi() en = np.linspace(0, 0.95 * ei, 200) line, = self.resaxes.plot(en, self.res) chopper = self.engine.getChopper() label_text = '%s_%s_%3.2fmeV_%dHz_Flux=%fn/cm2/s' % ( inst, chopper, ei, freq, self.flux) line.set_label(label_text) if self.tabs.isTabEnabled(self.qetabID): self.plot_qe(ei, label_text, overplot) self.resaxes_xlim = max(ei, self.resaxes_xlim) self.resaxes.set_xlim([0, self.resaxes_xlim]) legend_set_draggable(self.resaxes.legend(), True) self.resaxes.set_xlabel('Energy Transfer (meV)') self.resaxes.set_ylabel(r'$\Delta$E (meV FWHM)') self.rescanvas.draw()
def plot_flux_ei(self, **kwargs): """ Plots the flux vs Ei in the middle tab """ inst = self.engine.instname chop = self.engine.getChopper() freq = self.engine.getFrequency() overplot = self.widgets['HoldCheck'].isChecked() if hasattr(freq, '__len__'): freq = freq[0] update = kwargs['update'] if 'update' in kwargs.keys() else False # Do not recalculate if all relevant parameters still the same. _, labels = self.flxaxes2.get_legend_handles_labels() searchStr = '([A-Z]+) "(.+)" ([0-9]+) Hz' tmpinst = [] if (labels and (overplot or len(labels) == 1)) or update: for prevtitle in labels: prevInst, prevChop, prevFreq = re.search(searchStr, prevtitle).groups() if update: tmpinst.append(copy.deepcopy(Instrument(self.instruments[prevInst], prevChop, float(prevFreq)))) else: if inst == prevInst and chop == prevChop and freq == float(prevFreq): return ne = 25 mn = self.minE[inst] mx = (self.flxslder.val/100)*self.maxE[inst] eis = np.linspace(mn, mx, ne) flux = eis*0 elres = eis*0 if update: self.flxaxes1.clear() self.flxaxes2.clear() if matplotlib.compare_versions('2.1.0',matplotlib.__version__): self.flxaxes1.hold(True) self.flxaxes2.hold(True) for ii, instrument in enumerate(tmpinst): for ie, ei in enumerate(eis): with warnings.catch_warnings(record=True): warnings.simplefilter('always', UserWarning) flux[ie] = instrument.getFlux(ei) elres[ie] = instrument.getResolution(0., ei)[0] self.flxaxes1.plot(eis, flux) line, = self.flxaxes2.plot(eis, elres) line.set_label(labels[ii]) else: for ie, ei in enumerate(eis): with warnings.catch_warnings(record=True): warnings.simplefilter('always', UserWarning) flux[ie] = self.engine.getFlux(ei) elres[ie] = self.engine.getResolution(0., ei)[0] if overplot: if matplotlib.compare_versions('2.1.0',matplotlib.__version__): self.flxaxes1.hold(True) self.flxaxes2.hold(True) else: self.flxaxes1.clear() self.flxaxes2.clear() self.flxaxes1.plot(eis, flux) line, = self.flxaxes2.plot(eis, elres) line.set_label('%s "%s" %d Hz' % (inst, chop, freq)) self.flxaxes1.set_xlim([mn, mx]) self.flxaxes2.set_xlim([mn, mx]) self.flxaxes1.set_xlabel('Incident Energy (meV)') self.flxaxes1.set_ylabel('Flux (n/cm$^2$/s)') self.flxaxes1.set_xlabel('Incident Energy (meV)') self.flxaxes2.set_ylabel('Elastic Resolution FWHM (meV)') lg = self.flxaxes2.legend() legend_set_draggable(lg, True) self.flxcanvas.draw()
def create_legend(cls, props, ax): # Imported here to prevent circular import. from mantid.plots.datafunctions import get_legend_handles loc = ConfigService.getString('plots.legend.Location') font_size = float(ConfigService.getString('plots.legend.FontSize')) if not props: legend_set_draggable( ax.legend(handles=get_legend_handles(ax), loc=loc, prop={'size': font_size}), True) return if 'loc' in props.keys(): loc = props['loc'] if int(matplotlib.__version__[0]) >= 2: legend = ax.legend( handles=get_legend_handles(ax), ncol=props['columns'], prop={'size': props['entries_size']}, numpoints=props['markers'], markerfirst=props['marker_position'] == "Left of Entries", frameon=props['box_visible'], fancybox=props['round_edges'], shadow=props['shadow'], framealpha=props['transparency'], facecolor=props['background_color'], edgecolor=props['edge_color'], title=props['title'], borderpad=props['border_padding'], labelspacing=props['label_spacing'], handlelength=props['marker_size'], handletextpad=props['marker_label_padding'], columnspacing=props['column_spacing'], loc=loc) else: legend = ax.legend( handles=get_legend_handles(ax), ncol=props['columns'], prop={'size': props['entries_size']}, numpoints=props['markers'], markerfirst=props['marker_position'] == "Left of Entries", frameon=props['box_visible'], fancybox=props['round_edges'], shadow=props['shadow'], framealpha=props['transparency'], title=props['title'], borderpad=props['border_padding'], labelspacing=props['label_spacing'], handlelength=props['marker_size'], handletextpad=props['marker_label_padding'], columnspacing=props['column_spacing'], loc=loc) title = legend.get_title() title.set_fontname(props['title_font']) title.set_fontsize(props['title_size']) title.set_color(props['title_color']) for text in legend.get_texts(): text.set_fontname(props['entries_font']) text.set_fontsize(props['entries_size']) text.set_color(props['entries_color']) legend.set_visible(props['visible']) legend_set_draggable(legend, True)
def _update_plot(self): """ Update the plot. This function overplots the memorized data with the currently selected workspace and spectrum index. It keeps a memory of the last plot and removes it if is not part of the memorised data. """ selection = self._view.get_selection() current_spectrum_index = self._view.get_spectrum_slider_position() plotted_data = self._model.get_plotted_data() mode = self._view.get_mode() figure = self._canvas.figure axes = figure.gca() artists = axes.get_tracked_artists() # remove curves not in plotted_data for artist in artists: ws, sp = axes.get_artists_workspace_and_workspace_index(artist) ws_name = ws.name() if (ws_name, sp) not in plotted_data: axes.remove_artists_if(lambda a: a == artist) else: label = artist.get_label() try: color = artist.get_color() except: color = artist.lines[0].get_color() self._view.modify_spectrum_label(ws_name, sp, label, color) # add selection to plot for ws_name, spectra in selection.items(): if (current_spectrum_index not in spectra and not self._view.is_spectrum_selection_disabled()): spectra.append(current_spectrum_index) for sp in spectra: if sp == -1: continue if (ws_name, sp) not in plotted_data: ws = mtd[ws_name] kwargs = {} if mode == self.SPECTRUM_MODE_TEXT: kwargs["axis"] = MantidAxType.SPECTRUM kwargs["specNum"] = ws.getSpectrumNumbers()[sp] else: kwargs["axis"] = MantidAxType.BIN kwargs["wkspIndex"] = sp if self._error_bars: lines = axes.errorbar(ws, **kwargs) label = lines.get_label() color = lines.lines[0].get_color() else: lines = axes.plot(ws, **kwargs) label = lines[0].get_label() color = lines[0].get_color() self._view.modify_spectrum_label(ws_name, sp, label, color) if selection or plotted_data: axes.set_axis_on() try: figure.tight_layout() except ValueError: pass legend = axes.legend() if legend: legend_set_draggable(legend, True) else: legend = axes.get_legend() if legend: legend.remove() axes.set_axis_off() axes.set_title("") self._canvas.draw_idle()
def _show_axis_editor(self, event): """ Decides whether to show a dialog to edit axis information based on the contents of the event. Shows a dialog if necessary. @param event: the object representing the event @return: a flag to denote whether an action was taken e.g. opening a dialog. """ # We assume this is used for editing axis information e.g. labels # which are outside of the axes so event.inaxes is no use. canvas = self.canvas figure = canvas.figure axes = figure.get_axes() action_taken = False def move_and_show(editor): nonlocal action_taken action_taken = True editor.move(QCursor.pos()) editor.exec_() for ax in axes: if ax.title.contains(event)[0]: move_and_show(LabelEditor(canvas, ax.title)) elif ax.xaxis.label.contains(event)[0]: move_and_show(LabelEditor(canvas, ax.xaxis.label)) elif ax.yaxis.label.contains(event)[0]: move_and_show(LabelEditor(canvas, ax.yaxis.label)) elif (ax.xaxis.contains(event)[0] or any( tick.contains(event)[0] for tick in ax.get_xticklabels())): move_and_show(XAxisEditor(canvas, ax)) elif (ax.yaxis.contains(event)[0] or any( tick.contains(event)[0] for tick in ax.get_yticklabels())): if type(ax) == Axes: move_and_show(ColorbarAxisEditor(canvas, ax)) else: move_and_show(YAxisEditor(canvas, ax)) elif hasattr(ax, 'zaxis'): if ax.zaxis.label.contains(event)[0]: move_and_show(LabelEditor(canvas, ax.zaxis.label)) elif (ax.zaxis.contains(event)[0] or any( tick.contains(event)[0] for tick in ax.get_zticklabels())): move_and_show(ZAxisEditor(canvas, ax)) elif ax.get_legend() is not None and ax.get_legend().contains( event)[0]: # We have to set the legend as non draggable else we hold onto the legend # until the mouse button is clicked again legend_set_draggable(ax.get_legend(), False) legend_texts = ax.get_legend().get_texts() active_lines = datafunctions.get_legend_handles(ax) remove_legend_flag = True # remove the legend if no curve texts were clicked for legend_text, curve in zip(legend_texts, active_lines): if legend_text.contains(event)[0]: remove_legend_flag = False move_and_show(LegendEditor(canvas, legend_text, curve)) legend_set_draggable(ax.get_legend(), True) if remove_legend_flag: action_taken = True legend = ax.get_legend() legend.set_visible(False) canvas.draw() return action_taken