Source code for diffpy.pdfgui.gui.datasetconfigurepanel

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
##############################################################################
#
# PDFgui            by DANSE Diffraction group
#                   Simon J. L. Billinge
#                   (c) 2006 trustees of the Michigan State University.
#                   All rights reserved.
#
# File coded by:    Chris Farrow
#
# See AUTHORS.txt for a list of people who contributed.
# See LICENSE.txt for license information.
#
##############################################################################

# generated by wxGlade 0.9.3 on Fri Jul 19 16:00:35 2019

import wx

from diffpy.pdfgui.gui import tooltips
from diffpy.pdfgui.gui.pdfpanel import PDFPanel
from diffpy.pdfgui.gui.wxextensions.textctrlutils import textCtrlAsGridCell
from diffpy.pdfgui.gui.wxextensions.validators import FLOAT_ONLY, TextValidator


[docs] class DataSetConfigurePanel(wx.Panel, PDFPanel): def __init__(self, *args, **kwds): PDFPanel.__init__(self) # begin wxGlade: DataSetConfigurePanel.__init__ kwds["style"] = kwds.get("style", 0) | wx.TAB_TRAVERSAL wx.Panel.__init__(self, *args, **kwds) sizer_1 = wx.BoxSizer(wx.HORIZONTAL) outerSizer = wx.BoxSizer(wx.VERTICAL) sizer_1.Add(outerSizer, 1, wx.EXPAND, 0) sizer_panelname = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, ""), wx.HORIZONTAL) outerSizer.Add(sizer_panelname, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 5) self.panelNameLabel = wx.StaticText(self, wx.ID_ANY, "Data Set Configuration") self.panelNameLabel.SetFont( wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, 0, "", ) ) sizer_panelname.Add(self.panelNameLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT, 5) outerSizer.Add((450, 5), 0, 0, 0) self.radioBoxStype = wx.RadioBox( self, wx.ID_ANY, "Scatterer Type", choices=["Neutron", "X-ray"], majorDimension=2, style=wx.RA_SPECIFY_COLS, ) self.radioBoxStype.SetMinSize((330, 43)) self.radioBoxStype.SetSelection(0) outerSizer.Add(self.radioBoxStype, 0, wx.ALL, 5) self.radioBoxSampling = wx.RadioBox( self, wx.ID_ANY, "Data Sampling", choices=["Data", "Nyquist", "Custom"], majorDimension=3, style=wx.RA_SPECIFY_COLS, ) self.radioBoxSampling.SetMinSize((232, 44)) self.radioBoxSampling.SetSelection(0) outerSizer.Add(self.radioBoxSampling, 0, wx.ALL, 5) grid_sizer_1 = wx.FlexGridSizer(5, 6, 5, 10) outerSizer.Add(grid_sizer_1, 0, wx.ALL | wx.EXPAND, 5) self.labelDataRange = wx.StaticText(self, wx.ID_ANY, "Data Range") grid_sizer_1.Add( self.labelDataRange, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 5, ) self.textCtrlDataFrom = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY) self.textCtrlDataFrom.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) grid_sizer_1.Add(self.textCtrlDataFrom, 0, 0, 0) self.labelDataTo = wx.StaticText(self, wx.ID_ANY, "to") grid_sizer_1.Add(self.labelDataTo, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 20) self.textCtrlDataTo = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY) self.textCtrlDataTo.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) grid_sizer_1.Add(self.textCtrlDataTo, 0, 0, 0) self.labelDataStep = wx.StaticText(self, wx.ID_ANY, "spacing") grid_sizer_1.Add( self.labelDataStep, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 20, ) self.textCtrlDataStep = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY) self.textCtrlDataStep.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) grid_sizer_1.Add(self.textCtrlDataStep, 0, 0, 0) self.labelFitRange = wx.StaticText(self, wx.ID_ANY, "Fit Range", style=wx.ALIGN_RIGHT) grid_sizer_1.Add( self.labelFitRange, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 5, ) self.textCtrlFitFrom = wx.TextCtrl(self, wx.ID_ANY, "1.0") grid_sizer_1.Add(self.textCtrlFitFrom, 0, wx.ALIGN_CENTER_VERTICAL, 0) self.labelFitTo = wx.StaticText(self, wx.ID_ANY, "to", style=wx.ALIGN_RIGHT) grid_sizer_1.Add(self.labelFitTo, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 20) self.textCtrlFitTo = wx.TextCtrl(self, wx.ID_ANY, "10.0") grid_sizer_1.Add(self.textCtrlFitTo, 0, wx.ALIGN_CENTER_VERTICAL, 0) self.labelFitStep = wx.StaticText(self, wx.ID_ANY, "spacing") grid_sizer_1.Add( self.labelFitStep, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 20, ) self.textCtrlFitStep = wx.TextCtrl(self, wx.ID_ANY, "0") grid_sizer_1.Add(self.textCtrlFitStep, 0, wx.ALIGN_CENTER_VERTICAL, 0) self.labelScaleFactor = wx.StaticText(self, wx.ID_ANY, "Scale Factor", style=wx.ALIGN_RIGHT) grid_sizer_1.Add( self.labelScaleFactor, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 5, ) self.textCtrlScaleFactor = wx.TextCtrl(self, wx.ID_ANY, "1.0") grid_sizer_1.Add(self.textCtrlScaleFactor, 0, wx.ALIGN_CENTER_VERTICAL, 0) self.labelQmax = wx.StaticText(self, wx.ID_ANY, "Qmax", style=wx.ALIGN_RIGHT) grid_sizer_1.Add(self.labelQmax, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 20) self.textCtrlQmax = wx.TextCtrl(self, wx.ID_ANY, "25.0") grid_sizer_1.Add(self.textCtrlQmax, 0, wx.ALIGN_CENTER_VERTICAL, 0) self.blank1_copy = wx.StaticText(self, wx.ID_ANY, "") grid_sizer_1.Add(self.blank1_copy, 0, 0, 0) self.blank1_copy_4 = wx.StaticText(self, wx.ID_ANY, "") grid_sizer_1.Add(self.blank1_copy_4, 0, 0, 0) self.labelQdamp = wx.StaticText(self, wx.ID_ANY, "Qdamp", style=wx.ALIGN_RIGHT) grid_sizer_1.Add(self.labelQdamp, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 5) self.textCtrlQdamp = wx.TextCtrl(self, wx.ID_ANY, "0.0") grid_sizer_1.Add(self.textCtrlQdamp, 0, wx.ALIGN_CENTER_VERTICAL, 0) self.labelQbroad = wx.StaticText(self, wx.ID_ANY, "Qbroad", style=wx.ALIGN_RIGHT) grid_sizer_1.Add(self.labelQbroad, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 20) self.textCtrlQbroad = wx.TextCtrl(self, wx.ID_ANY, "0.0") grid_sizer_1.Add(self.textCtrlQbroad, 0, wx.ALIGN_CENTER_VERTICAL, 0) self.blank1_copy_1 = wx.StaticText(self, wx.ID_ANY, "") grid_sizer_1.Add(self.blank1_copy_1, 0, 0, 0) self.blank1_copy_5 = wx.StaticText(self, wx.ID_ANY, "") grid_sizer_1.Add(self.blank1_copy_5, 0, 0, 0) self.labelTemperature = wx.StaticText(self, wx.ID_ANY, "Temperature", style=wx.ALIGN_RIGHT) grid_sizer_1.Add( self.labelTemperature, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 5, ) self.textCtrlTemperature = wx.TextCtrl(self, wx.ID_ANY, "300.0") grid_sizer_1.Add(self.textCtrlTemperature, 0, wx.ALIGN_CENTER_VERTICAL, 0) self.labelDoping = wx.StaticText(self, wx.ID_ANY, "Doping", style=wx.ALIGN_RIGHT) grid_sizer_1.Add(self.labelDoping, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 20) self.textCtrlDoping = wx.TextCtrl(self, wx.ID_ANY, "1.0") grid_sizer_1.Add(self.textCtrlDoping, 0, wx.ALIGN_CENTER_VERTICAL, 0) self.blank1_copy_3 = wx.StaticText(self, wx.ID_ANY, "") grid_sizer_1.Add(self.blank1_copy_3, 0, 0, 0) self.blank1_copy_7 = wx.StaticText(self, wx.ID_ANY, "") grid_sizer_1.Add(self.blank1_copy_7, 0, 0, 0) self.SetSizer(sizer_1) sizer_1.Fit(self) self.Layout() self.Bind(wx.EVT_RADIOBOX, self.onStype, self.radioBoxStype) self.Bind(wx.EVT_RADIOBOX, self.onSampling, self.radioBoxSampling) # end wxGlade self.__customProperties() # USER CONFIGURATION CODE ################################################# def __customProperties(self): # Set some reasonable defaults self.configuration = None self.constraints = {} self.stypeMap = {0: "N", 1: "X"} self.metaNames = ["doping", "temperature"] self.constrainables = ["dscale", "qdamp", "qbroad"] self.sampList = ["data", "Nyquist", "custom"] self._focusedText = None # Note that the rstep and fitrstep attributes are special cases, so they # are handled separately. Qmax is also handled with these. self.ctrlMap = { "fitrmin": "textCtrlFitFrom", "fitrmax": "textCtrlFitTo", "rmin": "textCtrlDataFrom", "rmax": "textCtrlDataTo", "dscale": "textCtrlScaleFactor", "qdamp": "textCtrlQdamp", "qbroad": "textCtrlQbroad", "temperature": "textCtrlTemperature", "doping": "textCtrlDoping", } # Give each textCtrl a name that can be referenced and setup the # validator for key, value in self.ctrlMap.items(): textCtrl = getattr(self, value) textCtrl.SetName(key) textCtrl.SetValidator(TextValidator(FLOAT_ONLY)) self.textCtrlFitStep.SetValidator(TextValidator(FLOAT_ONLY)) # Setup the event code. for ctrlName in self.ctrlMap.values(): textCtrl = getattr(self, ctrlName) textCtrl.Bind(wx.EVT_SET_FOCUS, self.onSetFocus) textCtrl.Bind(wx.EVT_KILL_FOCUS, self.onLoseFocus) textCtrl.Bind(wx.EVT_KEY_DOWN, self.onTextCtrlKey) self.textCtrlFitStep.Bind(wx.EVT_KILL_FOCUS, self.onSampling) self.textCtrlQmax.Bind(wx.EVT_KILL_FOCUS, self.onSampling) self.textCtrlFitStep.Bind(wx.EVT_KEY_DOWN, self.onTextCtrlKey) self.textCtrlQmax.Bind(wx.EVT_KEY_DOWN, self.onTextCtrlKey) # define tooltips self.setToolTips(tooltips.datasetconfigurepanel) # make sure tooltips exist for all controls in `constrainables` as # this is later assumed in restrictConstrainedParameters code for tname in map(self.ctrlMap.get, self.constrainables): assert getattr(self, tname).GetToolTip() is not None # For blocked text controls. self.message = "This variable is constrained. Edit the associated parameter." return # Create the onTextCtrlKey event handler from textCtrlAsGridCell from # wxextensions.textctrlutils onTextCtrlKey = textCtrlAsGridCell
[docs] def setConfigurationData(self): """Set the values in the configuration panel. The values come from the configuration member dictionary. stype -- 'N' or 'X' dscale -- float qmax -- float qdamp -- float rmin -- float rmax -- float fitrmin -- float fitrmax -- float temperature -- float doping -- float """ if not self.configuration: return stype = self.configuration.stype if stype == "N": self.radioBoxStype.SetSelection(0) elif stype == "X": self.radioBoxStype.SetSelection(1) else: self.configuration.stype = "N" self.radioBoxStype.SetSelection(0) # iterate over all configurable items for key, value in self.ctrlMap.items(): textCtrl = getattr(self, value) if key in self.metaNames: value = self.configuration.metadata.get(key) else: value = getattr(self.configuration, key) if value is not None: textCtrl.SetValue(str(value)) else: textCtrl.SetValue("0.0") # Set qmax val = self.configuration.qmax self.textCtrlQmax.SetValue(str(val)) # Set the data step val = self.configuration.getObsSampling() self.textCtrlDataStep.SetValue(str(val)) # Set up the sampling type and fit step type st = self.configuration.getFitSamplingType() si = self.sampList.index(st) self.radioBoxSampling.SetSelection(si) val = self.configuration.fitrstep self.textCtrlFitStep.SetValue(str(val)) # Make sure the sampling info is consistent self.onSampling(None) return
[docs] def restrictConstrainedParameters(self): """Set 'read-only' boxes that correspond to constrained parameters.""" if not self.configuration: return self.setToolTips(tooltips.datasetconfigurepanel) txtbg = self.textCtrlScaleFactor.DefaultStyle.BackgroundColour for key in self.constrainables: value = self.ctrlMap[key] textCtrl = getattr(self, value) if key in self.constraints: textCtrl.SetEditable(False) textCtrl.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) tt = textCtrl.GetToolTip() tt.SetTip(self.constraints[key].formula) else: textCtrl.SetEditable(True) textCtrl.SetBackgroundColour(txtbg) return
def __coerseText(self, value): """Turn the text representation of a float into a float.""" if not value: value = "0" if value[-1].lower() in ("-", "e"): value += "0" return float(value) def __adjustFitRange(self, name, value): """Check the fit range values. The fit range values are set to their defaults (the data range) when the fit range is nonsensical. """ if name == "fitrmin": if value < self.configuration.rmin or value >= self.configuration.fitrmax: value = self.configuration.rmin self.textCtrlFitFrom.SetValue(str(value)) elif name == "fitrmax": if value < self.configuration.fitrmin or value >= self.configuration.rmax: value = self.configuration.rmax self.textCtrlFitTo.SetValue(str(value)) return value # EVENT CODE #############################################################
[docs] def onStype(self, event): # wxGlade: DataSetConfigurePanel.<event_handler> """Record the user's selection for stype.""" value = event.GetInt() self.configuration.stype = self.stypeMap[value] self.mainFrame.needsSave() return
[docs] def onSampling(self, event): # wxGlade: DataSetConfigurePanel.<event_handler> """Record how the data is to be sampled during the fit. This does not use the event argument, so feel free to call this method programmatically. """ si = self.radioBoxSampling.GetSelection() oldsampling = self.configuration.getFitSamplingType() sampling = self.sampList[si] oldstep = self.configuration.fitrstep # Get the value of the custom sampling and enable/disable status if sampling == "custom": # "custom" txtbg = self.textCtrlFitStep.DefaultStyle.BackgroundColour step = self.__coerseText(self.textCtrlFitStep.GetValue()) self.textCtrlFitStep.SetEditable(True) self.textCtrlFitStep.SetBackgroundColour(txtbg) else: step = None self.textCtrlFitStep.SetEditable(False) self.textCtrlFitStep.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) # Set the value of qmax val = self.__coerseText(self.textCtrlQmax.GetValue()) oldqmax = self.configuration.qmax if oldqmax != val: self.configuration.qmax = val self.mainFrame.needsSave() # Set the configured value if oldsampling != sampling or (sampling == "custom" and oldstep != step): self.configuration.setFitSamplingType(sampling, step) self.mainFrame.needsSave() # Update the text control self.textCtrlFitStep.SetValue(str(self.configuration.fitrstep)) if event is not None: event.Skip() return
[docs] def onSetFocus(self, event): """Saves a TextCtrl value, to be used later.""" self._focusedText = event.GetEventObject().GetValue() event.Skip() return
[docs] def onLoseFocus(self, event): """Record the user's selection for the text ctrl data.""" event.Skip() if not self.configuration: return textCtrl = event.GetEventObject() value = textCtrl.GetValue() value = self.__coerseText(value) name = textCtrl.GetName() # Check the fit range value = self.__adjustFitRange(name, value) if name in self.metaNames: temp = self.configuration.metadata.get(name) if temp != value: self.configuration.metadata[name] = value self.mainFrame.needsSave() else: temp = getattr(self.configuration, name) if temp != value: setattr(self.configuration, name, value) self.mainFrame.needsSave() return
# Methods overloaded from PDFPanel
[docs] def refresh(self): """Refresh the panel.""" self.setConfigurationData() self.restrictConstrainedParameters() return
# end of class DataSetConfigurePanel