def get_default_title(self): """ Get the default title, which for a plot is just a list of DataSet locations. A custom title can be set when adding any trace (via either __init__ or add. these kwargs all eventually end up in self.traces[i]['config']) and it looks like we will take the first title we find from any trace... otherwise, if no trace specifies a title, then we combine whatever dataset locations we find. Note: (alexj): yeah, that's awkward, isn't it, and it looks like a weird implementation, feel free to change it 👼 Returns: string: the title of the figure """ title_parts = [] for trace in self.traces: config = trace['config'] if 'title' in config: # can be passed using **kw return config['title'] for part in self.data_keys: data_array = config.get(part, '') if hasattr(data_array, 'data_set'): if data_array.data_set is not None: location = data_array.data_set.location if location and location not in title_parts: title_parts.append(location) return ', '.join(title_parts)
def _initialize_metadata(self, dataset: DataSet = None): """Initialize dataset metadata""" if dataset is None: dataset = self.dataset config = qcodes_config.get('user', {}).get('silq_config', qcodes_config) dataset.add_metadata({"config": config}) dataset.add_metadata({"measurement_type": "Measurement"}) # Add instrument information if Station.default is not None: dataset.add_metadata({"station": Station.default.snapshot()}) if using_ipython(): measurement_cell = get_last_input_cells(1)[0] measurement_code = measurement_cell # If the code is run from a measurement thread, there is some # initial code that should be stripped init_string = "get_ipython().run_cell_magic('new_job', '', " if measurement_code.startswith(init_string): measurement_code = measurement_code[len(init_string) + 1 : -4] self._t_start = datetime.now() dataset.add_metadata( { "measurement_cell": measurement_cell, "measurement_code": measurement_code, "last_input_cells": get_last_input_cells(20), "t_start": self._t_start.strftime('%Y-%m-%d %H:%M:%S') } )
def update_plot(self): """ update the plot. The DataSets themselves have already been updated in update, here we just push the changes to the plot. """ # matplotlib doesn't know how to autoscale to a pcolormesh after the # first draw (relim ignores it...) so we have to do this ourselves bboxes = dict(zip(self.subplots, [[] for p in self.subplots])) for trace in self.traces: config = trace['config'] plot_object = trace['plot_object'] if 'z' in config: # pcolormesh doesn't seem to allow editing x and y data, only z # so instead, we'll remove and re-add the data. if plot_object: plot_object.remove() ax = self[config.get('subplot', 1) - 1] kwargs = deepcopy(config) # figsize may be passed in as part of config. # pcolormesh will raise an error if this is passed to it # so strip it here. if 'figsize' in kwargs: kwargs.pop('figsize') plot_object = self._draw_pcolormesh(ax, **kwargs) trace['plot_object'] = plot_object if plot_object: bboxes[plot_object.axes].append( plot_object.get_datalim(plot_object.axes.transData)) else: for axletter in 'xy': setter = 'set_' + axletter + 'data' if axletter in config: getattr(plot_object, setter)(config[axletter]) for ax in self.subplots: if ax.get_autoscale_on(): ax.relim() if bboxes[ax]: bbox = Bbox.union(bboxes[ax]) if np.all(np.isfinite(ax.dataLim)): # should take care of the case of lines + heatmaps # where there's already a finite dataLim from relim ax.dataLim.set(Bbox.union(ax.dataLim, bbox)) else: # when there's only a heatmap, relim gives inf bounds # so just completely overwrite it ax.dataLim = bbox ax.autoscale() self.fig.canvas.draw()
def _update_image(self, plot_object, config): z = config['z'] img = plot_object['image'] hist = plot_object['hist'] scales = plot_object['scales'] # make sure z is a *new* numpy float array (pyqtgraph barfs on ints), # and replace nan with minimum val bcs I can't figure out how to make # pyqtgraph handle nans - though the source does hint at a way: # http://www.pyqtgraph.org/documentation/_modules/pyqtgraph/widgets/ColorMapWidget.html # see class RangeColorMapItem z = np.asfarray(z).T with warnings.catch_warnings(): warnings.simplefilter('error') try: z_range = (np.nanmin(z), np.nanmax(z)) except: # we get a warning here when z is entirely NaN # nothing to plot, so give up. return z[np.where(np.isnan(z))] = z_range[0] hist_range = hist.getLevels() if hist_range == plot_object['histlevels']: plot_object['histlevels'] = z_range hist.setLevels(*z_range) hist_range = z_range img.setImage(self._clean_array(z), levels=hist_range) scales_changed = False for axletter, axscale in scales.items(): if axscale.revisit: axdata = config.get(axletter, None) newscale = self._get_transform(axdata) if (newscale.translate != axscale.translate or newscale.scale != axscale.scale): scales_changed = True scales[axletter] = newscale if scales_changed: img.resetTransform() img.translate(scales['x'].translate, scales['y'].translate) img.scale(scales['x'].scale, scales['y'].scale)