def _create_plot(i, name, data, counter_two, display_plot=True): # Step the color on all subplots no just on plots # within the same axis/subplot # this is to match the qcodes-pyqtplot behaviour. title = "{} #{:03d}".format(CURRENT_EXPERIMENT["sample_name"], data.location_provider.counter) rasterized_note = " rasterized plot full data available in datafile" color = 'C' + str(counter_two) counter_two += 1 plot = MatPlot() if issubclass( i.__class__, MultiChannelInstrumentParameter) or i._instrument is None: inst_meas_name = name else: inst_meas_name = "{}_{}".format(i._instrument.name, name) inst_meas_data = getattr(data, inst_meas_name) try: inst_meas_data = getattr(data, inst_meas_name) except AttributeError: inst_meas_name = "{}{}_0_0".format(i._instrument.name, name) inst_meas_data = getattr(data, inst_meas_name) inst_meta_data = __get_plot_type(inst_meas_data, plot) if 'z' in inst_meta_data: xlen, ylen = inst_meta_data['z'].shape rasterized = xlen * ylen > 5000 po = plot.add(inst_meas_data, rasterized=rasterized) auto_color_scale_from_config(po.colorbar, auto_color_scale, inst_meta_data['z'], cutoff_percentile) else: rasterized = False plot.add(inst_meas_data, color=color) plot.subplots[0].grid() if rasterized: plot.subplots[0].set_title(title + rasterized_note) else: plot.subplots[0].set_title(title) title_list = plot.get_default_title().split(sep) title_list.insert(-1, CURRENT_EXPERIMENT['pdf_subfolder']) title = sep.join(title_list) plot.rescale_axis() plot.tight_layout() plot.save("{}_{:03d}.pdf".format(title, counter_two)) if display_plot: plot.fig.canvas.draw() plt.show() else: plt.close(plot.fig)
def plot_dataset( dataset: DataSetProtocol, axes: Optional[Union[matplotlib.axes.Axes, Sequence[matplotlib.axes.Axes]]] = None, colorbars: Optional[Union[matplotlib.colorbar.Colorbar, Sequence[matplotlib.colorbar.Colorbar]]] = None, rescale_axes: bool = True, auto_color_scale: Optional[bool] = None, cutoff_percentile: Optional[Union[Tuple[float, float], float]] = None, complex_plot_type: str = "real_and_imag", complex_plot_phase: str = "radians", **kwargs: Any, ) -> AxesTupleList: """ Construct all plots for a given dataset Implemented so far: * 1D line and scatter plots * 2D plots on filled out rectangular grids * 2D scatterplots (fallback) The function can optionally be supplied with a matplotlib axes or a list of axes that will be used for plotting. The user should ensure that the number of axes matches the number of datasets to plot. To plot several (1D) dataset in the same axes supply it several times. Colorbar axes are created dynamically. If colorbar axes are supplied, they will be reused, yet new colorbar axes will be returned. The plot has a title that comprises run id, experiment name, and sample name. ``**kwargs`` are passed to matplotlib's relevant plotting functions By default the data in any vector plot will be rasterized for scatter plots and heatmaps if more than 5000 points are supplied. This can be overridden by supplying the `rasterized` kwarg. Args: dataset: The dataset to plot axes: Optional Matplotlib axes to plot on. If not provided, new axes will be created colorbars: Optional Matplotlib Colorbars to use for 2D plots. If not provided, new ones will be created rescale_axes: If True, tick labels and units for axes of parameters with standard SI units will be rescaled so that, for example, '0.00000005' tick label on 'V' axis are transformed to '50' on 'nV' axis ('n' is 'nano') auto_color_scale: If True, the colorscale of heatmap plots will be automatically adjusted to disregard outliers. cutoff_percentile: Percentile of data that may maximally be clipped on both sides of the distribution. If given a tuple (a,b) the percentile limits will be a and 100-b. See also the plotting tuorial notebook. complex_plot_type: Method for converting complex-valued parameters into two real-valued parameters, either ``"real_and_imag"`` or ``"mag_and_phase"``. Applicable only for the cases where the dataset contains complex numbers complex_plot_phase: Format of phase for plotting complex-valued data, either ``"radians"`` or ``"degrees"``. Applicable only for the cases where the dataset contains complex numbers Returns: A list of axes and a list of colorbars of the same length. The colorbar axes may be `None` if no colorbar is created (e.g. for 1D plots) Config dependencies: (qcodesrc.json) """ # handle arguments and defaults subplots_kwargs = { k: kwargs.pop(k) for k in set(kwargs).intersection(SUBPLOTS_KWARGS) } # sanitize the complex plotting kwargs if complex_plot_type not in ['real_and_imag', 'mag_and_phase']: raise ValueError( f'Invalid complex plot type given. Received {complex_plot_type} ' 'but can only accept "real_and_imag" or "mag_and_phase".') if complex_plot_phase not in ['radians', 'degrees']: raise ValueError( f'Invalid complex plot phase given. Received {complex_plot_phase} ' 'but can only accept "degrees" or "radians".') degrees = complex_plot_phase == "degrees" # Retrieve info about the run for the title experiment_name = dataset.exp_name sample_name = dataset.sample_name title = f"Run #{dataset.captured_run_id}, " \ f"Experiment {experiment_name} ({sample_name})" alldata: NamedData = _get_data_from_ds(dataset) alldata = _complex_to_real_preparser(alldata, conversion=complex_plot_type, degrees=degrees) nplots = len(alldata) if isinstance(axes, matplotlib.axes.Axes): axeslist = [axes] else: axeslist = cast(List[matplotlib.axes.Axes], axes) if isinstance(colorbars, matplotlib.colorbar.Colorbar): colorbars = [colorbars] if axeslist is None: axeslist = [] for i in range(nplots): fig, ax = plt.subplots(1, 1, **subplots_kwargs) axeslist.append(ax) else: if len(subplots_kwargs) != 0: raise RuntimeError(f"Error: You cannot provide arguments for the " f"axes/figure creation if you supply your own " f"axes. " f"Provided arguments: {subplots_kwargs}") if len(axeslist) != nplots: raise RuntimeError(f"Trying to make {nplots} plots, but" f"received {len(axeslist)} axes objects.") if colorbars is None: colorbars = len(axeslist) * [None] new_colorbars: List[matplotlib.colorbar.Colorbar] = [] for data, ax, colorbar in zip(alldata, axeslist, colorbars): if len(data) == 2: # 1D PLOTTING log.debug(f'Doing a 1D plot with kwargs: {kwargs}') xpoints = data[0]["data"] ypoints = data[1]["data"] plottype = get_1D_plottype(xpoints, ypoints) log.debug(f'Determined plottype: {plottype}') if plottype == '1D_line': # sort for plotting order = xpoints.argsort() xpoints = xpoints[order] ypoints = ypoints[order] with _appropriate_kwargs(plottype, colorbar is not None, **kwargs) as k: ax.plot(xpoints, ypoints, **k) elif plottype == '1D_point': with _appropriate_kwargs(plottype, colorbar is not None, **kwargs) as k: ax.scatter(xpoints, ypoints, **k) elif plottype == '1D_bar': with _appropriate_kwargs(plottype, colorbar is not None, **kwargs) as k: ax.bar(xpoints, ypoints, **k) else: raise ValueError('Unknown plottype. Something is way wrong.') _set_data_axes_labels(ax, data) if rescale_axes: _rescale_ticks_and_units(ax, data, colorbar) new_colorbars.append(None) ax.set_title(title) elif len(data) == 3: # 2D PLOTTING log.debug(f'Doing a 2D plot with kwargs: {kwargs}') if data[2]["shape"] is None: xpoints = data[0]["data"].flatten() ypoints = data[1]["data"].flatten() zpoints = data[2]["data"].flatten() plottype = get_2D_plottype(xpoints, ypoints, zpoints) log.debug(f"Determined plottype: {plottype}") else: xpoints = data[0]["data"] ypoints = data[1]["data"] zpoints = data[2]["data"] plottype = "2D_grid" how_to_plot = { '2D_grid': plot_on_a_plain_grid, '2D_equidistant': plot_on_a_plain_grid, '2D_point': plot_2d_scatterplot, '2D_unknown': plot_2d_scatterplot } plot_func = how_to_plot[plottype] with _appropriate_kwargs(plottype, colorbar is not None, **kwargs) as k: ax, colorbar = plot_func(xpoints, ypoints, zpoints, ax, colorbar, **k) _set_data_axes_labels(ax, data, colorbar) if rescale_axes: _rescale_ticks_and_units(ax, data, colorbar) auto_color_scale_from_config(colorbar, auto_color_scale, zpoints, cutoff_percentile) new_colorbars.append(colorbar) ax.set_title(title) else: log.warning('Multi-dimensional data encountered. ' f'parameter {data[-1]["name"]} depends on ' f'{len(data)-1} parameters, cannot plot ' f'that.') new_colorbars.append(None) if len(axeslist) != len(new_colorbars): raise RuntimeError("Non equal number of axes. Perhaps colorbar is " "missing from one of the cases above") return axeslist, new_colorbars
def plot_by_id(run_id: int, axes: Optional[Union[matplotlib.axes.Axes, Sequence[matplotlib.axes.Axes]]]=None, colorbars: Optional[Union[matplotlib.colorbar.Colorbar, Sequence[ matplotlib.colorbar.Colorbar]]]=None, rescale_axes: bool=True, auto_color_scale: Optional[bool]=None, cutoff_percentile: Optional[Union[Tuple[Number, Number], Number]]=None, **kwargs) -> AxesTupleList: """ Construct all plots for a given run Implemented so far: * 1D line and scatter plots * 2D plots on filled out rectangular grids * 2D scatterplots (fallback) The function can optionally be supplied with a matplotlib axes or a list of axes that will be used for plotting. The user should ensure that the number of axes matches the number of datasets to plot. To plot several (1D) dataset in the same axes supply it several times. Colorbar axes are created dynamically. If colorbar axes are supplied, they will be reused, yet new colorbar axes will be returned. The plot has a title that comprises run id, experiment name, and sample name. ``**kwargs`` are passed to matplotlib's relevant plotting functions By default the data in any vector plot will be rasterized for scatter plots and heatmaps if more that 5000 points are supplied. This can be overridden by supplying the `rasterized` kwarg. Args: run_id: ID of the run to plot axes: Optional Matplotlib axes to plot on. If not provided, new axes will be created colorbars: Optional Matplotlib Colorbars to use for 2D plots. If not provided, new ones will be created rescale_axes: if True, tick labels and units for axes of parameters with standard SI units will be rescaled so that, for example, '0.00000005' tick label on 'V' axis are transformed to '50' on 'nV' axis ('n' is 'nano') auto_color_scale: if True, the colorscale of heatmap plots will be automatically adjusted to disregard outliers. cutoff_percentile: percentile of data that may maximally be clipped on both sides of the distribution. If given a tuple (a,b) the percentile limits will be a and 100-b. See also the plotting tuorial notebook. Returns: a list of axes and a list of colorbars of the same length. The colorbar axes may be None if no colorbar is created (e.g. for 1D plots) Config dependencies: (qcodesrc.json) """ # handle arguments and defaults subplots_kwargs = {k: kwargs.pop(k) for k in set(kwargs).intersection(SUBPLOTS_KWARGS)} # Retrieve info about the run for the title dataset = load_by_id(run_id) experiment_name = dataset.exp_name sample_name = dataset.sample_name title = f"Run #{run_id}, Experiment {experiment_name} ({sample_name})" alldata = get_data_by_id(run_id) nplots = len(alldata) if isinstance(axes, matplotlib.axes.Axes): axes = [axes] if isinstance(colorbars, matplotlib.colorbar.Colorbar): colorbars = [colorbars] if axes is None: axes = [] for i in range(nplots): fig, ax = plt.subplots(1, 1, **subplots_kwargs) axes.append(ax) else: if len(subplots_kwargs) != 0: raise RuntimeError(f"Error: You cannot provide arguments for the " f"axes/figure creation if you supply your own " f"axes. " f"Provided arguments: {subplots_kwargs}") if len(axes) != nplots: raise RuntimeError(f"Trying to make {nplots} plots, but" f"received {len(axes)} axes objects.") if colorbars is None: colorbars = len(axes)*[None] new_colorbars: List[matplotlib.colorbar.Colorbar] = [] for data, ax, colorbar in zip(alldata, axes, colorbars): if len(data) == 2: # 1D PLOTTING log.debug('Plotting by id, doing a 1D plot') xpoints = data[0]['data'] ypoints = data[1]['data'] plottype = get_1D_plottype(xpoints, ypoints) log.debug(f'Determined plottype: {plottype}') if plottype == 'line': # sort for plotting order = xpoints.argsort() xpoints = xpoints[order] ypoints = ypoints[order] ax.plot(xpoints, ypoints, **kwargs) elif plottype == 'point': ax.scatter(xpoints, ypoints, **kwargs) elif plottype == 'bar': ax.bar(xpoints, ypoints, **kwargs) else: raise ValueError('Unknown plottype. Something is way wrong.') _set_data_axes_labels(ax, data) if rescale_axes: _rescale_ticks_and_units(ax, data, colorbar) new_colorbars.append(None) ax.set_title(title) elif len(data) == 3: # 2D PLOTTING log.debug('Plotting by id, doing a 2D plot') # From the setpoints, figure out which 2D plotter to use # TODO: The "decision tree" for what gets plotted how and how # we check for that is still unfinished/not optimised xpoints = flatten_1D_data_for_plot(data[0]['data']) ypoints = flatten_1D_data_for_plot(data[1]['data']) zpoints = flatten_1D_data_for_plot(data[2]['data']) plottype = get_2D_plottype(xpoints, ypoints, zpoints) log.debug(f'Determined plottype: {plottype}') how_to_plot = {'grid': plot_on_a_plain_grid, 'equidistant': plot_on_a_plain_grid, 'point': plot_2d_scatterplot, 'unknown': plot_2d_scatterplot} plot_func = how_to_plot[plottype] if colorbar is None and 'cmap' not in kwargs: kwargs['cmap'] = qc.config.plotting.default_color_map ax, colorbar = plot_func(xpoints, ypoints, zpoints, ax, colorbar, **kwargs) _set_data_axes_labels(ax, data, colorbar) if rescale_axes: _rescale_ticks_and_units(ax, data, colorbar) auto_color_scale_from_config(colorbar, auto_color_scale, zpoints, cutoff_percentile) new_colorbars.append(colorbar) ax.set_title(title) else: log.warning('Multi-dimensional data encountered. ' f'parameter {data[-1]["name"]} depends on ' f'{len(data)-1} parameters, cannot plot ' f'that.') new_colorbars.append(None) if len(axes) != len(new_colorbars): raise RuntimeError("Non equal number of axes. Perhaps colorbar is " "missing from one of the cases above") return axes, new_colorbars
def _create_plot(plot, i, name, data, counter_two, j, k): """ Args: plot: The plot object, either QtPlot() or MatPlot() i: The parameter to measure name: - data: The DataSet of the current measurement counter_two: The sub-measurement counter. Each measurement has a number and each sub-measurement has a counter. j: The current sub-measurement k: - """ color = 'C' + str(counter_two) if issubclass( i.__class__, MultiChannelInstrumentParameter) or i._instrument is None: inst_meas_name = name else: parent_instr_name = (i._instrument.name + '_') if i._instrument else '' inst_meas_name = "{}{}".format(parent_instr_name, name) try: inst_meas_data = getattr(data, inst_meas_name) except AttributeError: inst_meas_name = "{}{}_0_0".format(parent_instr_name, name) inst_meas_data = getattr(data, inst_meas_name) inst_meta_data = __get_plot_type(inst_meas_data, plot) if useQT: plot.add(inst_meas_data, subplot=j + k + 1) plot.subplots[j + k].showGrid(True, True) if j == 0: plot.subplots[0].setTitle(title) else: plot.subplots[j + k].setTitle("") plot.fixUnitScaling(startranges) QtPlot.qc_helpers.foreground_qt_window(plot.win) else: if 'z' in inst_meta_data: xlen, ylen = inst_meta_data['z'].shape rasterized = xlen * ylen > 5000 po = plot.add(inst_meas_data, subplot=j + k + 1, rasterized=rasterized) auto_color_scale_from_config(po.colorbar, auto_color_scale, inst_meta_data['z'], cutoff_percentile) else: rasterized = False plot.add(inst_meas_data, subplot=j + k + 1, color=color) plot.subplots[j + k].grid() if j == 0: if rasterized: fulltitle = title + rasterized_note else: fulltitle = title plot.subplots[0].set_title(fulltitle) else: if rasterized: fulltitle = rasterized_note else: fulltitle = "" plot.subplots[j + k].set_title(fulltitle)