def setScale(self, scale=None): """ Set the value scaling for this axis. The scaling value 1) multiplies the values displayed along the axis and 2) changes the way units are displayed in the label. For example: If the axis spans values from -0.1 to 0.1 and has units set to 'V' then a scale of 1000 would cause the axis to display values -100 to 100 and the units would appear as 'mV' If scale is None, then it will be determined automatically based on the current range displayed by the axis. """ if scale is None: #if self.drawLabel: ## If there is a label, then we are free to rescale the values if self.label.isVisible(): d = self.range[1] - self.range[0] #(scale, prefix) = fn.siScale(d / 2.) (scale, prefix) = fn.siScale(max(abs(self.range[0]), abs(self.range[1]))) if self.labelUnits == '' and prefix in ['k', 'm']: ## If we are not showing units, wait until 1e6 before scaling. scale = 1.0 prefix = '' self.setLabel(unitPrefix=prefix) else: scale = 1.0 if scale != self.scale: self.scale = scale self.setLabel() self.picture = None self.update()
def setScale(self, scale=None): """ Set the value scaling for this axis. The scaling value 1) multiplies the values displayed along the axis and 2) changes the way units are displayed in the label. For example: If the axis spans values from -0.1 to 0.1 and has units set to 'V' then a scale of 1000 would cause the axis to display values -100 to 100 and the units would appear as 'mV' If scale is None, then it will be determined automatically based on the current range displayed by the axis. """ if scale is None: # if self.drawLabel: ## If there is a label, then we are free to rescale the values if self.label.isVisible(): d = self.range[1] - self.range[0] # (scale, prefix) = fn.siScale(d / 2.) (scale, prefix) = fn.siScale(max(abs(self.range[0]), abs(self.range[1]))) if self.labelUnits == "" and prefix in [ "k", "m", ]: ## If we are not showing units, wait until 1e6 before scaling. scale = 1.0 prefix = "" self.setLabel(unitPrefix=prefix) else: scale = 1.0 if scale != self.scale: self.scale = scale self.setLabel() self.picture = None self.update()
def updateText(self, prev=None): # get the number of decimal places to print decimals = self.opts.get('decimals') # temporarily disable validation self.skipValidate = True # if we're supposed to add a prefix to the label if self.opts['siPrefix']: # special case: if it's zero use the previous prefix if self.val == 0 and prev is not None: (s, p) = fn.siScale(prev) # NOTE: Could have the user specify a format string and use it here txt = ("%."+str(decimals)+"g %s%s") % (0, p, self.opts['suffix']) else: # NOTE: Could have the user specify a format string and send it as an argument here txt = fn.siFormat(float(self.val), precision=decimals, suffix=self.opts['suffix']) # otherwise, format the string manually else: # NOTE: Could have the user specify a format string and use it here txt = ('%.'+str(decimals)+'g%s') % (self.val , self.opts['suffix']) # actually set the text self.lineEdit().setText(txt) self.lastText = txt # re-enable the validation self.skipValidate = False
def setFloat(self, val): """.""" sc, prf = functions.siScale(val) val *= sc text = self.FMT.format(val) text += ' ' + prf + self.unit super().setText(text)
def setScale(self, scale=None): """ Set the value scaling for this axis. Values on the axis are multiplied by this scale factor before being displayed as text. By default, this scaling value is automatically determined based on the visible range and the axis units are updated to reflect the chosen scale factor. For example: If the axis spans values from -0.1 to 0.1 and has units set to 'V' then a scale of 1000 would cause the axis to display values -100 to 100 and the units would appear as 'mV' """ if scale is None: #if self.drawLabel: ## If there is a label, then we are free to rescale the values if self.label.isVisible(): #d = self.range[1] - self.range[0] #(scale, prefix) = fn.siScale(d / 2.) (scale, prefix) = fn.siScale(max(abs(self.range[0]), abs(self.range[1]))) if self.labelUnits == '' and prefix in ['k', 'm']: ## If we are not showing units, wait until 1e6 before scaling. scale = 1.0 prefix = '' self.setLabel(unitPrefix=prefix) else: scale = 1.0 else: self.setLabel(unitPrefix='') self.autoScale = False if scale != self.scale: self.scale = scale self.setLabel() self.picture = None self.update()
def setScale(self, scale=None): """ Set the value scaling for this axis. Values on the axis are multiplied by this scale factor before being displayed as text. By default, this scaling value is automatically determined based on the visible range and the axis units are updated to reflect the chosen scale factor. For example: If the axis spans values from -0.1 to 0.1 and has units set to 'V' then a scale of 1000 would cause the axis to display values -100 to 100 and the units would appear as 'mV' """ if scale is None: #if self.drawLabel: ## If there is a label, then we are free to rescale the values if self.label.isVisible(): #d = self.range[1] - self.range[0] #(scale, prefix) = fn.siScale(d / 2.) (scale, prefix) = fn.siScale( max(abs(self.range[0]), abs(self.range[1]))) if self.labelUnits == '' and prefix in [ 'k', 'm' ]: ## If we are not showing units, wait until 1e6 before scaling. scale = 1.0 prefix = '' self.setLabel(unitPrefix=prefix) else: scale = 1.0 else: self.setLabel(unitPrefix='') self.autoScale = False if scale != self.scale: self.scale = scale self.setLabel() self.picture = None self.update()
def _show_tooltip(self, pos, pln='x'): unit = 'rad' if self.is_orb: names = self._csorb.bpm_nicknames posi = self._csorb.bpm_pos unit = 'm' elif pln == 'x': names = self._csorb.ch_nicknames posi = self._csorb.ch_pos else: names = self._csorb.cv_nicknames posi = self._csorb.cv_pos graph = self.graph[pln] curve = graph.curveAtIndex(0) posx = curve.scatter.mapFromScene(pos).x() if self._csorb.isring: posx = posx % self._csorb.circum ind = _np.argmin(_np.abs(_np.array(posi) - posx)) posy = curve.scatter.mapFromScene(pos).y() sca, prf = functions.siScale(posy) txt = '{0:s}, y = {1:.3f} {2:s}'.format(names[ind], sca * posy, prf + unit) QToolTip.showText(graph.mapToGlobal(pos.toPoint()), txt, graph, graph.geometry(), 500)
def value_changed(self, new_value): """ Callback invoked when the Channel value is changed. Sets the value of new_value accordingly at the Label. Parameters ---------- new_value : str, int, float, bool or np.ndarray The new value from the channel. The type depends on the channel. """ super(SiriusLabel, self).value_changed(new_value) # If it is a DiaplayFormat.Time, parse with siriuspy.clientarch.Time if self._display_format_type == self.DisplayFormat.Time: time = _Time(int(new_value)).time().isoformat() \ if new_value is not None else '' self.setText(time) return new_value = parse_value_for_display( value=new_value, precision=self.precision, display_format_type=self._display_format_type, string_encoding=self._string_encoding, widget=self) # If the value is a string, just display it as-is, no formatting # needed. if isinstance(new_value, str): self.setText(new_value) return # If the value is an enum, display the appropriate enum string for # the value. if self.enum_strings and isinstance(new_value, (int, float)): try: self.setText(self.enum_strings[int(new_value)]) except IndexError: self.setText(f'Index Overflow [{new_value}]') return # If the value is a number (float or int), display it using a # format string if necessary. if isinstance(new_value, (int, float)): if self._show_units and self._unit != '': new_value *= self._conv sc, prf = func.siScale(new_value) self.setText(self.format_string.format(sc * new_value, prf)) else: self.setText(self.format_string.format(new_value)) return # If you made it this far, just turn whatever the heck the value # is into a string and display it. self.setText(str(new_value))
def updateText(self, prev=None): #print "Update text." self.skipValidate = True if self.opts['siPrefix']: if self.val == 0 and prev is not None: (s, p) = fn.siScale(prev) txt = "0.0 %s%s" % (p, self.opts['suffix']) else: txt = fn.siFormat(float(self.val), suffix=self.opts['suffix']) else: txt = '%g%s' % (self.val , self.opts['suffix']) self.lineEdit().setText(txt) self.lastText = txt self.skipValidate = False
def mouseMoveEvent(self, ev): unit = 'urad' pos = ev.pos() posx = self.curve.scatter.mapFromScene(pos).x() posx = posx % self.c0 ind = _np.argmin(_np.abs(_np.array(self.xdata) - posx)) posy = self.curve.scatter.mapFromScene(pos).y() sca, prf = functions.siScale(posy) txt = '{0:s}, y = {1:.3f} {2:s}'.format(self.tooltip_names[ind], sca * posy, prf + unit) QToolTip.showText(self.mapToGlobal(pos), txt, self, self.geometry(), 500)
def updateText(self, prev=None): #print "Update text." self.skipValidate = True if self.opts['siPrefix']: if self.val == 0 and prev is not None: (s, p) = fn.siScale(prev) txt = "0.0 %s%s" % (p, self.opts['suffix']) else: txt = fn.siFormat(float(self.val), suffix=self.opts['suffix']) else: txt = '%g%s' % (self.val, self.opts['suffix']) self.lineEdit().setText(txt) self.lastText = txt self.skipValidate = False
def updateAutoSIPrefix(self): if self.label.isVisible(): (scale, prefix) = fn.siScale(max(abs(self.range[0] * self.scale), abs(self.range[1] * self.scale))) if self.labelUnits == "" and prefix in [ "k", "m", ]: ## If we are not showing units, wait until 1e6 before scaling. scale = 1.0 prefix = "" self.setLabel(unitPrefix=prefix) else: scale = 1.0 self.autoSIPrefixScale = scale self.picture = None self.update()
def generateDrawSpecs(self, p): #Force proper SI prefix usage... # - this is normally done in self.updateAutoSIPrefix, but pyqtgraph # only enables tick label scaling when there is a genuine x axis # label (and we don't have one). scale = self.scale xmin, xmax = self.range (scale, prefix) = siScale(max(abs(xmin * scale), abs(xmax * scale))) self.autoSIPrefixScale = scale #Get the standard tick labels... ret = list(super(RTSAFrequencyAxisItem, self).generateDrawSpecs(p)) #Add in our start/centre/stop labels... ret[2].extend(self._getFrequencyTextSpecs()) return tuple(ret)
def updateAutoSIPrefix(self): if self.label.isVisible(): (scale, prefix) = fn.siScale( max(abs(self.range[0] * self.scale), abs(self.range[1] * self.scale))) if self.labelUnits == '' and prefix in [ 'k', 'm' ]: ## If we are not showing units, wait until 1e6 before scaling. scale = 1.0 prefix = '' self.setLabel(unitPrefix=prefix) else: scale = 1.0 self.autoSIPrefixScale = scale self.picture = None self.update()
def updateText(self, prev=None): # print("Update text.") self.skipValidate = True if self.opts['siPrefix']: if self.val == 0 and prev is not None: (s, p) = fn.siScale(prev) txt = "0.0 {0!s}{1!s}".format(p, self.opts['suffix']) else: txt = fn.siFormat(float(self.val), precision=self.opts['decimals'] + 1, suffix=self.opts['suffix']) else: txt = '{0:.14g}{1!s}'.format(self.val, self.opts['suffix']) self.lineEdit().setText(txt) self.lastText = txt self.skipValidate = False
def updateText(self, prev=None): self.skipValidate = True if self.opts['siPrefix']: if self.val == 0 and prev is not None: (s, p) = fn.siScale(prev) txt = "0.0 %s%s" % (p, self.opts['suffix']) else: txt = fn.siFormat(float(self.val), precision=self.opts['decimals'], suffix=self.opts['suffix']) else: fmt = "%." + str(self.opts['decimals']) + "g%s" txt = fmt % (self.val, self.opts['suffix']) self.lineEdit().setText(txt) self.lastText = txt self.skipValidate = False
def updateText(self, prev=None): # print("Update text.") self.skipValidate = True if self.opts['siPrefix']: if self.val == 0 and prev is not None: (s, p) = fn.siScale(prev) txt = "0.0 {0!s}{1!s}".format(p, self.opts['suffix']) else: txt = fn.siFormat(float(self.val), precision=self.opts['decimals']+1, suffix=self.opts['suffix'] ) else: txt = '{0:.14g}{1!s}'.format(self.val , self.opts['suffix']) self.lineEdit().setText(txt) self.lastText = txt self.skipValidate = False
def _getFrequencyTextSpecs(self): """Generates f axis labels for the overridden generateDrawSpecs. Expected form is a list of (QRectF, Alignment flags, unicode). """ #TODO: proper/consistent sig fig handling would be nice freq_min, freq_max = self.range freq_center = (freq_max + freq_min) / 2.0 #baseline QRect values... # - note that we don't clip, and we do properly align, so (w,h) is meh y = 22 w = 30 h = 20 #Use common SI scaling, based on the low end... # - this avoids start being 600.00 MHz, and stop being 2.50 GHz #scale, si_prefix = siScale(freq_min) #set label contents... Qt = QtCore.Qt #space saver xpositions = [0, 0.5* self.width(), self.width() - 50] # -50 is a hack to fix pyrf_plot clipping issue labels = ["Start", "Center", "Stop"] freqs = [freq_min, freq_center, freq_max] alignments = [Qt.AlignLeft, Qt.AlignCenter, Qt.AlignRight] #Generate labels in a common way... textSpecs = [] #same as in superclass generateDrawSpecs for label, freq, alignment, x in zip(labels, freqs, alignments, xpositions): rect = QtCore.QRectF(x, y, w, h) textFlags = alignment | Qt.TextDontClip | Qt.AlignVCenter if freq <= 0: freq_txt = u"---" else: scale, si_prefix = siScale(freq) freq_txt = u"%.4f %sHz" % ((scale * freq), si_prefix) txt = u"%s = %s" % (label, freq_txt) textSpecs.append((rect, textFlags, txt)) return textSpecs
def create_formatted_output(param_dict, num_sig_digits=5): """ Display a parameter set nicely in SI units. @param dict param_dict: dictionary with entries being again dictionaries with two needed keywords 'value' and 'unit' and one optional keyword 'error'. Add the proper items to the specified keywords. Note, that if no error is specified, no proper rounding (and therefore displaying) can be guaranteed. @param int num_sig_digits: optional, the number of significant digits will be taken, if the rounding procedure was not successful at all. That will ensure at least that not all the digits are displayed. According to that the error will be displayed. @return str: a string, which is nicely formatted. Note: If you want that the values are displayed in a certain order, then use OrderedDict from the collections package. Note2: The absolute tolerance to a zero is set to 1e-18. Example of a param dict: param_dict = {'Rabi frequency': {'value':123.43, 'error': 0.321, 'unit': 'Hz'}, 'ODMR contrast': {'value':2.563423, 'error': 0.523, 'unit': '%'}, 'Fidelity': {'value':0.783, 'error': 0.2222, 'unit': ''}} If you want to access on the value of the Fidelity, then you can do that via: param_dict['Fidelity']['value'] or on the error of the ODMR contrast: param_dict['ODMR contrast']['error'] """ if (fn is None): raise Exception('This function requires pyqtgraph.') output_str = '' atol = 1e-18 # absolute tolerance for the detection of zero. for entry in param_dict: if param_dict[entry].get('error') is not None: value, error, digit = round_value_to_error( param_dict[entry]['value'], param_dict[entry]['error']) if (np.isclose(value, 0.0, atol=atol) or np.isnan(error) or np.isclose(error, 0.0, atol=atol) or np.isinf(error)): sc_fact, unit_prefix = fn.siScale(param_dict[entry]['value']) str_val = '{0:.{1}e}'.format( param_dict[entry]['value'], num_sig_digits - 1) if np.isnan(np.float(str_val)): value = np.NAN elif np.isinf(np.float(str_val)): value = np.inf else: value = float('{0:.{1}e}'.format( param_dict[entry]['value'], num_sig_digits - 1)) else: # the factor 10 moves the displayed digit by one to the right, # so that the values from 100 to 0.1 are displayed within one # range, rather then from the value 1000 to 1, which is # default. sc_fact, unit_prefix = fn.siScale(error * 10) output_str += '{0}: {1} \u00B1 {2} {3}{4} \n'.format(entry, round( value * sc_fact, num_sig_digits - 1), round( error * sc_fact, num_sig_digits - 1), unit_prefix, param_dict[entry][ 'unit'], ) else: output_str += '{0}: '.format(entry) + fn.siFormat(param_dict[entry]['value'], precision=num_sig_digits, suffix=param_dict[entry]['unit']) + '\n' return output_str
def validate(self, strn, pos): # print('validate', strn, pos) if self.skipValidate: # print("skip validate") #self.textValid = False ret = QtGui.QValidator.Acceptable else: try: ## first make sure we didn't mess with the suffix suff = self.opts.get('suffix', '') # fix: if the whole text is selected and one needs to typ in a # new number, then a single integer character is ignored. if len(strn) == 1 and strn.isdigit(): scl_str = fn.siScale(self.val)[1] strn = '{0} {1}{2}'.format(strn, scl_str, suff) if len(suff) > 0 and asUnicode(strn)[-len(suff):] != suff: #print '"%s" != "%s"' % (unicode(strn)[-len(suff):], suff) ret = QtGui.QValidator.Invalid # print('invalid input', 'suff:', suff, '{0} != {1}'.format(asUnicode(strn)[-len(suff):], suff)) ## next see if we actually have an interpretable value else: val = self.interpret() if val is False: #print "can't interpret" #self.setStyleSheet('SpinBox {border: 2px solid #C55;}') #self.textValid = False ret = QtGui.QValidator.Intermediate else: if self.valueInRange(val): if not self.opts['delayUntilEditFinished']: self.setValue(val, update=False) #print " OK:", self.val #self.setStyleSheet('') #self.textValid = True ret = QtGui.QValidator.Acceptable else: ret = QtGui.QValidator.Intermediate except: #print " BAD" #import sys #sys.excepthook(*sys.exc_info()) #self.textValid = False #self.setStyleSheet('SpinBox {border: 2px solid #C55;}') ret = QtGui.QValidator.Intermediate ## draw / clear border if ret == QtGui.QValidator.Intermediate: self.textValid = False elif ret == QtGui.QValidator.Acceptable: self.textValid = True ## note: if text is invalid, we don't change the textValid flag ## since the text will be forced to its previous state anyway self.update() ## support 2 different pyqt APIs. Bleh. if hasattr(QtCore, 'QString'): return (ret, pos) else: return (ret, strn, pos)