def _update_text(self): vb = self.plot_item.getViewBox() data_coords = vb.mapSceneToView(self.last_hover_event.scenePos()) # TODO: Draw text directly to graphics scene rather than going through # pyqtgraph for performance - don't need any of the fancy interaction # or layouting features that come with being a plot item. def make_text(): text = pyqtgraph.TextItem() # Don't take text item into account for auto-scaling; otherwise # there will be positive feedback if the cursor is towards the # bottom right of the screen. text.setFlag(text.ItemHasNoContents) self.plot_item.addItem(text) return text if not self.x_text: self.x_text = make_text() if not self.y_text: self.y_text = make_text() x_range, y_range = vb.state["viewRange"] x_range = np.array(x_range) * self.x_data_to_display_scale y_range = np.array(y_range) * self.y_data_to_display_scale def num_digits_after_point(r): # We want to be able to resolve at least 1000 points in the displayed # range. smallest_digit = np.floor(np.log10(r[1] - r[0])) - 3 return int(-smallest_digit) if smallest_digit < 0 else 0 self.x_text.setText("{0:.{width}f}{1}".format( data_coords.x() * self.x_data_to_display_scale, self.x_unit_suffix, width=num_digits_after_point(x_range))) self.x_text.setPos(data_coords) self.last_x = data_coords.x() y_text_pos = QtCore.QPointF(self.last_hover_event.scenePos()) y_text_pos.setY(self.last_hover_event.scenePos().y() + 10) self.y_text.setText("{0:.{width}f}{1}".format( data_coords.y() * self.y_data_to_display_scale, self.y_unit_suffix, width=num_digits_after_point(y_range))) self.y_text.setPos(vb.mapSceneToView(y_text_pos)) self.last_y = data_coords.y()
def _update(self): x_data = self.points["axis_0"] y_data = self.points["axis_1"] z_data = self.points["channel_" + self.active_channel_name] # Figure out how many complete data points we have, and whether there are any # not already shown. num_to_show = min(len(x_data), len(y_data), len(z_data)) if num_to_show == self.num_shown: return num_skip = self.num_shown self.num_shown = num_to_show # Update z autorange if active. if True: # TODO: Provide manual override. data_min = np.min(z_data[num_skip:num_to_show]) data_max = np.max(z_data[num_skip:num_to_show]) if self.current_z_limits is None: self.current_z_limits = (data_min, data_max) num_skip = 0 else: z_limits = (min(self.current_z_limits[0], data_min), max(self.current_z_limits[1], data_max)) if z_limits != self.current_z_limits: self.current_z_limits = z_limits num_skip = 0 # Determine range of x/y values to show and prepare image buffer accordingly if # it changed. x_range = _calc_range_spec(self.x_min, self.x_max, self.x_increment, x_data) y_range = _calc_range_spec(self.y_min, self.y_max, self.y_increment, y_data) if x_range != self.x_range or y_range != self.y_range: self.x_range = x_range self.y_range = y_range # TODO: Splat old data for progressively less blurry look on refining scans? self.image_data = np.full((_num_points_in_range(x_range), _num_points_in_range(y_range), 4), 0, dtype="ubyte") self.image_rect = QtCore.QRectF( QtCore.QPointF(x_range[0] - x_range[2] / 2, y_range[0] - y_range[2] / 2), QtCore.QPointF(x_range[1] + x_range[2] / 2, y_range[1] + y_range[2] / 2)) num_skip = 0 x_inds = _coords_to_indices(x_data[num_skip:num_to_show], self.x_range) y_inds = _coords_to_indices(y_data[num_skip:num_to_show], self.y_range) z_min, z_max = self.current_z_limits z_scaled = (z_data[num_skip:num_to_show] - z_min) / (z_max - z_min) cmap = colormaps.plasma if self._get_display_hints().get("coordinate_type", "") == "cyclic": cmap = colormaps.kovesi_c8 self.image_data[x_inds, y_inds, :] = cmap.map(z_scaled) self.image_item.setImage(self.image_data, autoLevels=False) if num_skip == 0: # Image size has changed, set plot item size accordingly. self.image_item.setRect(self.image_rect)