"""
Base Page for fitting
"""
import sys
import os
import wx
import numpy
import time
import copy
import math
import string
import json
from collections import defaultdict
from wx.lib.scrolledpanel import ScrolledPanel
from sas.guiframe.panel_base import PanelBase
from sas.guiframe.utils import format_number, check_float
from sas.guiframe.events import PanelOnFocusEvent
from sas.guiframe.events import StatusEvent
from sas.guiframe.events import AppendBookmarkEvent
from sas.guiframe.dataFitting import Data2D
from sas.guiframe.dataFitting import Data1D
from sas.guiframe.dataFitting import check_data_validity
from sas.guiframe.gui_style import GUIFRAME_ID
from sas.dataloader.data_info import Detector
from sas.dataloader.data_info import Source
from sas.perspectives.fitting.pagestate import PageState
from sas.guiframe.CategoryInstaller import CategoryInstaller
(PageInfoEvent, EVT_PAGE_INFO) = wx.lib.newevent.NewEvent()
(PreviousStateEvent, EVT_PREVIOUS_STATE) = wx.lib.newevent.NewEvent()
(NextStateEvent, EVT_NEXT_STATE) = wx.lib.newevent.NewEvent()
_BOX_WIDTH = 76
_QMIN_DEFAULT = 0.0005
_QMAX_DEFAULT = 0.5
_NPTS_DEFAULT = 50
#Control panel width
if sys.platform.count("win32") > 0:
PANEL_WIDTH = 450
FONT_VARIANT = 0
ON_MAC = False
else:
PANEL_WIDTH = 500
FONT_VARIANT = 1
ON_MAC = True
[docs]class BasicPage(ScrolledPanel, PanelBase):
"""
This class provide general structure of fitpanel page
"""
## Internal name for the AUI manager
window_name = "Fit Page"
## Title to appear on top of the window
window_caption = "Fit Page "
def __init__(self, parent, color='blue', **kwargs):
"""
"""
ScrolledPanel.__init__(self, parent, **kwargs)
PanelBase.__init__(self, parent)
self.SetupScrolling()
#Set window's font size
self.SetWindowVariant(variant=FONT_VARIANT)
self.SetBackgroundColour(color)
## parent of the page
self.parent = parent
## manager is the fitting plugin
## owner of the page (fitting plugin)
self.event_owner = None
## current model
self.model = None
self.m_name = None
self.index_model = None
self.panel = None
## data
self.data = None
#list of available data
self.data_list = []
self.mask = None
self.uid = wx.NewId()
self.graph_id = None
#Q range for data set
self.qmin_data_set = numpy.inf
self.qmax_data_set = None
self.npts_data_set = 0
## Q range
self.qmin = None
self.qmax = None
self.qmax_x = _QMAX_DEFAULT
self.qmin_x = _QMIN_DEFAULT
self.npts_x = _NPTS_DEFAULT
## total number of point: float
self.npts = None
self.num_points = None
## default fitengine type
self.engine_type = 'bumps'
## smear default
self.current_smearer = None
## 2D smear accuracy default
self.smear2d_accuracy = 'Low'
## slit smear:
self.dxl = None
self.dxw = None
## pinhole smear
self.dx_min = None
self.dx_max = None
##semar attrbs
self.enable_smearer = None
self.disable_smearer = None
self.pinhole_smearer = None
self.slit_smearer = None
##weigth attrbs
self.dI_noweight = None
self.dI_didata = None
self.dI_sqrdata = None
self.dI_idata = None
##other attrbs
self.dq_l = None
self.dq_r = None
self.tcChi = None
self.disp_box = None
self.model_disp = None
self.Npts_fit = None
self.Npts_total = None
self.theory_qmin = None
self.theory_qmax = None
self.theory_qmin_x = None
self.theory_qmax_x = None
self.cb1 = None
self.btEditMask = None
self.btFit = None
self.sld_axes = None
self.multi_factor = None
self.disp_cb_dict = {}
#self.state = PageState(parent=parent)
## dictionary containing list of models
self.model_list_box = {}
## Data member to store the dispersion object created
self._disp_obj_dict = {}
## selected parameters to apply dispersion
self.disp_cb_dict = {}
## smearer object
self.enable2D = False
self._has_magnetic = False
self.magnetic_on = False
self.is_mac = ON_MAC
self.formfactorbox = None
self.structurebox = None
self.categorybox = None
##list of model parameters. each item must have same length
## each item related to a given parameters
##[cb state, name, value, "+/-", error of fit, min, max , units]
self.parameters = []
# non-fittable parameter whose value is astring
self.str_parameters = []
## list of parameters to fit , must be like self.parameters
self.param_toFit = []
## list of looking like parameters but with non fittable parameters info
self.fixed_param = []
## list of looking like parameters but with fittable parameters info
self.fittable_param = []
##list of dispersion parameters
self.disp_list = []
self.disp_name = ""
## list of orientation parameters
self.orientation_params = []
self.orientation_params_disp = []
# Self.model should ALWAYS be None here. It was set to none above in
# this long init setting. no obvious function call in between setting
# and this - commenting out on 4/8/2014 by PDB. Remove once clear
# it is pointless.
# if self.model != None:
# self.disp_list = self.model.getDispParamList()
self.temp_multi_functional = False
##enable model 2D draw
self.enable2D = False
## check that the fit range is correct to plot the model again
self.fitrange = True
## Create memento to save the current state
self.state = PageState(parent=self.parent,
model=self.model, data=self.data)
## flag to determine if state has change
self.state_change = False
## save customized array
self.values = []
self.weights = []
## retrieve saved state
self.number_saved_state = 0
## dictionary of saved state
self.saved_states = {}
## Create context menu for page
self.popUpMenu = wx.Menu()
id = wx.NewId()
self._keep = wx.MenuItem(self.popUpMenu, id, "Add bookmark",
" Keep the panel status to recall it later")
self.popUpMenu.AppendItem(self._keep)
self._keep.Enable(False)
self._set_bookmark_flag(False)
self._set_save_flag(False)
wx.EVT_MENU(self, id, self.on_bookmark)
self.popUpMenu.AppendSeparator()
## Default locations
self._default_save_location = os.getcwd()
## save initial state on context menu
#self.onSave(event=None)
self.Bind(wx.EVT_CONTEXT_MENU, self.onContextMenu)
# bind key event
self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down)
## create the basic structure of the panel with empty sizer
self.define_page_structure()
## drawing Initial dispersion parameters sizer
self.set_dispers_sizer()
## layout
self.set_layout()
[docs] def set_index_model(self, index):
"""
Index related to this page
"""
self.index_model = index
[docs] def create_default_data(self):
"""
Given the user selection, creates a 1D or 2D data
Only when the page is on theory mode.
"""
if not hasattr(self, "model_view"):
return
toggle_mode_on = self.model_view.IsEnabled()
if toggle_mode_on:
if self.enable2D and not check_data_validity(self.data):
self._create_default_2d_data()
else:
if self.pointsbox.GetValue():
self._create_log_1d_data()
else:
self._create_default_1d_data()
if self.model != None:
if not self.data.is_data:
self._manager.page_finder[self.uid].set_fit_data(data=\
[self.data])
self.on_smear_helper(update=True)
self.state.enable_smearer = self.enable_smearer.GetValue()
self.state.disable_smearer = self.disable_smearer.GetValue()
self.state.pinhole_smearer = self.pinhole_smearer.GetValue()
self.state.slit_smearer = self.slit_smearer.GetValue()
def _create_default_1d_data(self):
"""
Create default data for fitting perspective
Only when the page is on theory mode.
:warning: This data is never plotted.
"""
x = numpy.linspace(start=self.qmin_x, stop=self.qmax_x,
num=self.npts_x, endpoint=True)
self.data = Data1D(x=x)
self.data.xaxis('\\rm{Q}', "A^{-1}")
self.data.yaxis('\\rm{Intensity}', "cm^{-1}")
self.data.is_data = False
self.data.id = str(self.uid) + " data"
self.data.group_id = str(self.uid) + " Model1D"
def _create_log_1d_data(self):
"""
Create log-spaced data for fitting perspective
Only when the page is on theory mode.
:warning: This data is never plotted.
"""
if self.qmin_x >= 1.e-10:
qmin = numpy.log10(self.qmin_x)
else:
qmin = -10.
if self.qmax_x <= 1.e10:
qmax = numpy.log10(self.qmax_x)
else:
qmax = 10.
x = numpy.logspace(start=qmin, stop=qmax,
num=self.npts_x, endpoint=True, base=10.0)
self.data = Data1D(x=x)
self.data.xaxis('\\rm{Q}', "A^{-1}")
self.data.yaxis('\\rm{Intensity}', "cm^{-1}")
self.data.is_data = False
self.data.id = str(self.uid) + " data"
self.data.group_id = str(self.uid) + " Model1D"
def _create_default_2d_data(self):
"""
Create 2D data by default
Only when the page is on theory mode.
:warning: This data is never plotted.
"""
self.data = Data2D()
qmax = self.qmax_x / math.sqrt(2)
self.data.xaxis('\\rm{Q_{x}}', 'A^{-1}')
self.data.yaxis('\\rm{Q_{y}}', 'A^{-1}')
self.data.is_data = False
self.data.id = str(self.uid) + " data"
self.data.group_id = str(self.uid) + " Model2D"
## Default values
self.data.detector.append(Detector())
index = len(self.data.detector) - 1
self.data.detector[index].distance = 8000 # mm
self.data.source.wavelength = 6 # A
self.data.detector[index].pixel_size.x = 5 # mm
self.data.detector[index].pixel_size.y = 5 # mm
self.data.detector[index].beam_center.x = qmax
self.data.detector[index].beam_center.y = qmax
## create x_bins and y_bins of the model 2D
#pixel_width_x = self.data.detector[index].pixel_size.x
#pixel_width_y = self.data.detector[index].pixel_size.y
#center_x = self.data.detector[index].beam_center.x/pixel_width_x
#center_y = self.data.detector[index].beam_center.y/pixel_width_y
# theory default: assume the beam
#center is located at the center of sqr detector
xmax = qmax
xmin = -qmax
ymax = qmax
ymin = -qmax
qstep = self.npts_x
x = numpy.linspace(start=xmin, stop=xmax, num=qstep, endpoint=True)
y = numpy.linspace(start=ymin, stop=ymax, num=qstep, endpoint=True)
## use data info instead
new_x = numpy.tile(x, (len(y), 1))
new_y = numpy.tile(y, (len(x), 1))
new_y = new_y.swapaxes(0, 1)
# all data reuire now in 1d array
qx_data = new_x.flatten()
qy_data = new_y.flatten()
q_data = numpy.sqrt(qx_data * qx_data + qy_data * qy_data)
# set all True (standing for unmasked) as default
mask = numpy.ones(len(qx_data), dtype=bool)
# calculate the range of qx and qy: this way,
# it is a little more independent
#x_size = xmax - xmin
#y_size = ymax - ymin
# store x and y bin centers in q space
x_bins = x
y_bins = y
# bin size: x- & y-directions
#xstep = x_size / len(x_bins - 1)
#ystep = y_size / len(y_bins - 1)
self.data.source = Source()
self.data.data = numpy.ones(len(mask))
self.data.err_data = numpy.ones(len(mask))
self.data.qx_data = qx_data
self.data.qy_data = qy_data
self.data.q_data = q_data
self.data.mask = mask
self.data.x_bins = x_bins
self.data.y_bins = y_bins
# max and min taking account of the bin sizes
self.data.xmin = xmin
self.data.xmax = xmax
self.data.ymin = ymin
self.data.ymax = ymax
[docs] def on_set_focus(self, event):
"""
On Set Focus, update guimanger and menu
"""
if self._manager is not None:
wx.PostEvent(self._manager.parent, PanelOnFocusEvent(panel=self))
self.on_tap_focus()
[docs] def on_tap_focus(self):
"""
Update menu1 on cliking the page tap
"""
if self._manager.menu1 != None:
chain_menu = self._manager.menu1.FindItemById(\
self._manager.id_reset_flag)
chain_menu.Enable(self.batch_on)
sim_menu = self._manager.menu1.FindItemById(self._manager.id_simfit)
flag = self.data.is_data\
and (self.model != None)
sim_menu.Enable(not self.batch_on and flag)
batch_menu = \
self._manager.menu1.FindItemById(self._manager.id_batchfit)
batch_menu.Enable(self.batch_on and flag)
[docs] class ModelTextCtrl(wx.TextCtrl):
"""
Text control for model and fit parameters.
Binds the appropriate events for user interactions.
Default callback methods can be overwritten on initialization
:param kill_focus_callback: callback method for EVT_KILL_FOCUS event
:param set_focus_callback: callback method for EVT_SET_FOCUS event
:param mouse_up_callback: callback method for EVT_LEFT_UP event
:param text_enter_callback: callback method for EVT_TEXT_ENTER event
"""
## Set to True when the mouse is clicked while whole string is selected
full_selection = False
## Call back for EVT_SET_FOCUS events
_on_set_focus_callback = None
def __init__(self, parent, id=-1,
value=wx.EmptyString,
pos=wx.DefaultPosition,
size=wx.DefaultSize,
style=0,
validator=wx.DefaultValidator,
name=wx.TextCtrlNameStr,
kill_focus_callback=None,
set_focus_callback=None,
mouse_up_callback=None,
text_enter_callback=None):
wx.TextCtrl.__init__(self, parent, id, value, pos,
size, style, validator, name)
# Bind appropriate events
self._on_set_focus_callback = parent.onSetFocus \
if set_focus_callback is None else set_focus_callback
self.Bind(wx.EVT_SET_FOCUS, self._on_set_focus)
self.Bind(wx.EVT_KILL_FOCUS, self._silent_kill_focus \
if kill_focus_callback is None else kill_focus_callback)
self.Bind(wx.EVT_TEXT_ENTER, parent._onparamEnter \
if text_enter_callback is None else text_enter_callback)
if not ON_MAC:
self.Bind(wx.EVT_LEFT_UP, self._highlight_text \
if mouse_up_callback is None else mouse_up_callback)
def _on_set_focus(self, event):
"""
Catch when the text control is set in focus to highlight the whole
text if necessary
:param event: mouse event
"""
event.Skip()
self.full_selection = True
return self._on_set_focus_callback(event)
def _highlight_text(self, event):
"""
Highlight text of a TextCtrl only of no text has be selected
:param event: mouse event
"""
# Make sure the mouse event is available to other listeners
event.Skip()
control = event.GetEventObject()
if self.full_selection:
self.full_selection = False
# Check that we have a TextCtrl
if issubclass(control.__class__, wx.TextCtrl):
# Check whether text has been selected,
# if not, select the whole string
(start, end) = control.GetSelection()
if start == end:
control.SetSelection(-1, -1)
def _silent_kill_focus(self, event):
"""
Save the state of the page
"""
event.Skip()
#pass
[docs] def set_page_info(self, page_info):
"""
set some page important information at once
"""
# THIS METHOD/FUNCTION NO LONGE APPEARS TO BE CALLED. Started up program
# and started new fit window and PR and Invariant and a fit in fitting
# but never entered this routine which should be an initialization
# routine. Leave for a while but probably something to clean up at
# some point?
#
# PDB April 13 2014
#
##window_name
self.window_name = page_info.window_name
##window_caption
self.window_caption = page_info.window_caption
## manager is the fitting plugin
self._manager = page_info.manager
## owner of the page (fitting plugin)
self.event_owner = page_info.event_owner
## current model
self.model = page_info.model
## data
self.data = page_info.data
## dictionary containing list of models
self.model_list_box = page_info.model_list_box
## Data member to store the dispersion object created
self.populate_box(model_dict=self.model_list_box)
[docs] def onUndo(self, event):
"""
Cancel the previous action
"""
event = PreviousStateEvent(page=self)
wx.PostEvent(self.parent, event)
[docs] def onRedo(self, event):
"""
Restore the previous action cancelled
"""
event = NextStateEvent(page=self)
wx.PostEvent(self.parent, event)
[docs] def define_page_structure(self):
"""
Create empty sizer for a panel
"""
self.vbox = wx.BoxSizer(wx.VERTICAL)
self.sizer0 = wx.BoxSizer(wx.VERTICAL)
self.sizer1 = wx.BoxSizer(wx.VERTICAL)
self.sizer2 = wx.BoxSizer(wx.VERTICAL)
self.sizer3 = wx.BoxSizer(wx.VERTICAL)
self.sizer4 = wx.BoxSizer(wx.VERTICAL)
self.sizer5 = wx.BoxSizer(wx.VERTICAL)
self.sizer6 = wx.BoxSizer(wx.VERTICAL)
self.sizer0.SetMinSize((PANEL_WIDTH, -1))
self.sizer1.SetMinSize((PANEL_WIDTH, -1))
self.sizer2.SetMinSize((PANEL_WIDTH, -1))
self.sizer3.SetMinSize((PANEL_WIDTH, -1))
self.sizer4.SetMinSize((PANEL_WIDTH, -1))
self.sizer5.SetMinSize((PANEL_WIDTH, -1))
self.sizer6.SetMinSize((PANEL_WIDTH, -1))
self.vbox.Add(self.sizer0)
self.vbox.Add(self.sizer1)
self.vbox.Add(self.sizer2)
self.vbox.Add(self.sizer3)
self.vbox.Add(self.sizer4)
self.vbox.Add(self.sizer5)
self.vbox.Add(self.sizer6)
[docs] def set_layout(self):
"""
layout
"""
self.vbox.Layout()
self.vbox.Fit(self)
self.SetSizer(self.vbox)
self.Centre()
[docs] def set_owner(self, owner):
"""
set owner of fitpage
:param owner: the class responsible of plotting
"""
self.event_owner = owner
self.state.event_owner = owner
[docs] def get_state(self):
"""
"""
return self.state
[docs] def get_data(self):
"""
return the current data
"""
return self.data
[docs] def get_data_list(self):
"""
return the current data
"""
return self.data_list
[docs] def set_manager(self, manager):
"""
set panel manager
:param manager: instance of plugin fitting
"""
self._manager = manager
self.state.manager = manager
[docs] def populate_box(self, model_dict):
"""
Store list of model
:param model_dict: dictionary containing list of models
"""
self.model_list_box = model_dict
self.state.model_list_box = self.model_list_box
self.initialize_combox()
[docs] def set_model_dictionary(self, model_dict):
"""
Store a dictionary linking model name -> model object
:param model_dict: dictionary containing list of models
"""
self.model_dict = model_dict
[docs] def initialize_combox(self):
"""
put default value in the combobox
"""
## fill combox box
if self.model_list_box is None:
return
if len(self.model_list_box) > 0:
## This is obsolete code since form factor box is no longer static.
## It is now set dynamically through _show_combox and _show_combos_helper
## These are called for first time by formfactor_combo_init
## itself called from fitpanel only. If we find that I'm wrong and
## we DO need to initialize somehow here - do it by a call to
## formfactor_combo_init
## self.formfator_combo_init()
## BUT NOT HERE -- make it last line of this
## method so that structure box is populated before _show_comboox_helper
## is called. Otherwise wx will complain mightily:-)
##
## Also change the name to initiatlize_structurebox along with changes
## to other combobox methods (_populate_listbox --> _populate_categorybox
## etc )
##
## PDB 4/26/2014
# self._populate_box(self.formfactorbox,
# self.model_list_box["Shapes"])
self._populate_box(self.structurebox,
self.model_list_box["Structure Factors"])
self.structurebox.Insert("None", 0, None)
self.structurebox.SetSelection(0)
self.structurebox.Hide()
self.text2.Hide()
self.structurebox.Disable()
self.text2.Disable()
if self.model.__class__ in self.model_list_box["P(Q)*S(Q)"]:
self.structurebox.Show()
self.text2.Show()
self.structurebox.Enable()
self.text2.Enable()
[docs] def set_dispers_sizer(self):
"""
fill sizer containing dispersity info
"""
self.sizer4.Clear(True)
name = "Polydispersity and Orientational Distribution"
box_description = wx.StaticBox(self, -1, name)
box_description.SetForegroundColour(wx.BLUE)
boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
#----------------------------------------------------
self.disable_disp = wx.RadioButton(self, -1, 'Off', (10, 10),
style=wx.RB_GROUP)
self.enable_disp = wx.RadioButton(self, -1, 'On', (10, 30))
# best size for MAC and PC
if ON_MAC:
size_q = (30, 20)
else:
size_q = (20, 15)
self.disp_help_bt = wx.Button(self, wx.NewId(), '?',
style=wx.BU_EXACTFIT,
size=size_q)
self.disp_help_bt.Bind(wx.EVT_BUTTON,
self.on_pd_help_clicked, id=self.disp_help_bt.GetId())
self.disp_help_bt.SetToolTipString("Helps for Polydispersion.")
self.Bind(wx.EVT_RADIOBUTTON, self._set_dipers_Param,
id=self.disable_disp.GetId())
self.Bind(wx.EVT_RADIOBUTTON, self._set_dipers_Param,
id=self.enable_disp.GetId())
#MAC needs SetValue
self.disable_disp.SetValue(True)
sizer_dispersion = wx.BoxSizer(wx.HORIZONTAL)
sizer_dispersion.Add((20, 20))
name = "" # Polydispersity and \nOrientational Distribution "
sizer_dispersion.Add(wx.StaticText(self, -1, name))
sizer_dispersion.Add(self.enable_disp)
sizer_dispersion.Add((20, 20))
sizer_dispersion.Add(self.disable_disp)
sizer_dispersion.Add((25, 20))
sizer_dispersion.Add(self.disp_help_bt)
## fill a sizer for dispersion
boxsizer1.Add(sizer_dispersion, 0,
wx.TOP | wx.BOTTOM | wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE,
border=5)
self.sizer4_4 = wx.GridBagSizer(6, 5)
boxsizer1.Add(self.sizer4_4)
#-----------------------------------------------------
self.sizer4.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
self.sizer4_4.Layout()
self.sizer4.Layout()
self.Layout()
self.Refresh()
## saving the state of enable dispersity button
self.state.enable_disp = self.enable_disp.GetValue()
self.state.disable_disp = self.disable_disp.GetValue()
self.SetupScrolling()
[docs] def onResetModel(self, event):
"""
Reset model state
"""
menu = event.GetEventObject()
## post help message for the selected model
msg = menu.GetHelpString(event.GetId())
msg += " reloaded"
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
self.Show(False)
name = menu.GetLabel(event.GetId())
self._on_select_model_helper()
if self.model != None:
self.m_name = self.model.name
if name in self.saved_states.keys():
previous_state = self.saved_states[name]
## reset state of checkbox,textcrtl and regular parameters value
self.reset_page(previous_state)
self.state.m_name = self.m_name
self.Show(True)
[docs] def on_preview(self, event):
"""
Report the current fit results
"""
# Get plot image from plotpanel
images, canvases = self.get_images()
# get the report dialog
self.state.report(images, canvases)
[docs] def on_save(self, event):
"""
Save the current state into file
"""
self.save_current_state()
new_state = self.state.clone()
# Ask the user the location of the file to write to.
path = None
if self.parent != None:
self._default_save_location = \
self._manager.parent._default_save_location
dlg = wx.FileDialog(self, "Choose a file", self._default_save_location,
self.window_caption, "*.fitv", wx.SAVE)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
self._default_save_location = os.path.dirname(path)
self._manager.parent._default_save_location =\
self._default_save_location
else:
return None
# MAC always needs the extension for saving
extens = ".fitv"
# Make sure the ext included in the file name
fName = os.path.splitext(path)[0] + extens
#the manager write the state into file
self._manager.save_fit_state(filepath=fName, fitstate=new_state)
return new_state
[docs] def on_copy(self, event):
"""
Copy Parameter values to the clipboad
"""
if event != None:
event.Skip()
# It seems MAC needs wxCallAfter
if event.GetId() == GUIFRAME_ID.COPYEX_ID:
print "copy excel"
wx.CallAfter(self.get_copy_excel)
elif event.GetId() == GUIFRAME_ID.COPYLAT_ID:
print "copy latex"
wx.CallAfter(self.get_copy_latex)
else:
wx.CallAfter(self.get_copy)
[docs] def on_paste(self, event):
"""
Paste Parameter values to the panel if possible
"""
#if event != None:
# event.Skip()
# It seems MAC needs wxCallAfter for the setvalues
# for multiple textctrl items, otherwise it tends to crash once a while
wx.CallAfter(self.get_paste)
# messages depending on the flag
#self._copy_info(True)
def _copy_info(self, flag):
"""
Send event dpemding on flag
: Param flag: flag that distinguish event
"""
# messages depending on the flag
if flag == None:
msg = " Parameter values are copied to the clipboard..."
infor = 'warning'
elif flag:
msg = " Parameter values are pasted from the clipboad..."
infor = "warning"
else:
msg = "Error occured: "
msg += "No valid parameter values to paste from the clipboard..."
infor = "error"
wx.PostEvent(self._manager.parent,
StatusEvent(status=msg, info=infor))
# inform msg to wx
wx.PostEvent(self._manager.parent,
StatusEvent(status=msg, info=infor))
def _get_time_stamp(self):
"""
return time and date stings
"""
# date and time
year, month, day, hour, minute, second, _, _, _ = time.localtime()
current_time = str(hour) + ":" + str(minute) + ":" + str(second)
current_date = str(month) + "/" + str(day) + "/" + str(year)
return current_time, current_date
[docs] def on_bookmark(self, event):
"""
save history of the data and model
"""
if self.model == None:
msg = "Can not bookmark; Please select Data and Model first..."
wx.MessageBox(msg, 'Info')
return
self.save_current_state()
new_state = self.state.clone()
##Add model state on context menu
self.number_saved_state += 1
current_time, current_date = self._get_time_stamp()
#name= self.model.name+"[%g]"%self.number_saved_state
name = "Fitting: %g]" % self.number_saved_state
name += self.model.__class__.__name__
name += "bookmarked at %s on %s" % (current_time, current_date)
self.saved_states[name] = new_state
## Add item in the context menu
msg = "Model saved at %s on %s" % (current_time, current_date)
## post help message for the selected model
msg += " Saved! right click on this page to retrieve this model"
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
id = wx.NewId()
self.popUpMenu.Append(id, name, str(msg))
wx.EVT_MENU(self, id, self.onResetModel)
wx.PostEvent(self._manager.parent,
AppendBookmarkEvent(title=name,
hint=str(msg),
handler=self._back_to_bookmark))
def _back_to_bookmark(self, event):
"""
Back to bookmark
"""
self._manager.on_perspective(event)
self.onResetModel(event)
self._draw_model()
[docs] def onSetFocus(self, evt):
"""
highlight the current textcrtl and hide the error text control shown
after fitting
"""
return
[docs] def read_file(self, path):
"""
Read two columns file
:param path: the path to the file to read
"""
try:
if path == None:
wx.PostEvent(self._manager.parent,
StatusEvent(status= \
" Selected Distribution was not loaded: %s" % path))
return None, None
input_f = open(path, 'r')
buff = input_f.read()
lines = buff.split('\n')
input_f.close()
angles = []
weights = []
for line in lines:
toks = line.split()
try:
angle = float(toks[0])
weight = float(toks[1])
angles.append(angle)
weights.append(weight)
except:
# Skip non-data lines
pass
return numpy.array(angles), numpy.array(weights)
except:
raise
[docs] def createMemento(self):
"""
return the current state of the page
"""
return self.state.clone()
[docs] def save_current_state(self):
"""
Store current state
"""
self.state.engine_type = copy.deepcopy(self.engine_type)
## save model option
if self.model != None:
self.disp_list = self.model.getDispParamList()
self.state.disp_list = copy.deepcopy(self.disp_list)
self.state.model = self.model.clone()
#model combobox: complex code because of mac's silent error
if self.structurebox != None:
if self.structurebox.IsShown():
self.state.structurecombobox = 'None'
s_select = self.structurebox.GetSelection()
if s_select > 0:
self.state.structurecombobox = self.structurebox.\
GetString(s_select)
if self.formfactorbox != None:
f_select = self.formfactorbox.GetSelection()
if f_select > 0:
self.state.formfactorcombobox = self.formfactorbox.\
GetString(f_select)
if self.categorybox != None:
cb_select = self.categorybox.GetSelection()
if cb_select > 0:
self.state.categorycombobox = self.categorybox.\
GetString(cb_select)
self.state.enable2D = copy.deepcopy(self.enable2D)
self.state.values = copy.deepcopy(self.values)
self.state.weights = copy.deepcopy(self.weights)
## save data
self.state.data = copy.deepcopy(self.data)
self.state.qmax_x = self.qmax_x
self.state.qmin_x = self.qmin_x
self.state.dI_noweight = copy.deepcopy(self.dI_noweight.GetValue())
self.state.dI_didata = copy.deepcopy(self.dI_didata.GetValue())
self.state.dI_sqrdata = copy.deepcopy(self.dI_sqrdata.GetValue())
self.state.dI_idata = copy.deepcopy(self.dI_idata.GetValue())
self.state.dq_l = self.dq_l
self.state.dq_r = self.dq_r
if hasattr(self, "enable_disp"):
self.state.enable_disp = self.enable_disp.GetValue()
self.state.disable_disp = self.disable_disp.GetValue()
self.state.smearer = copy.deepcopy(self.current_smearer)
if hasattr(self, "enable_smearer"):
self.state.enable_smearer = \
copy.deepcopy(self.enable_smearer.GetValue())
self.state.disable_smearer = \
copy.deepcopy(self.disable_smearer.GetValue())
self.state.pinhole_smearer = \
copy.deepcopy(self.pinhole_smearer.GetValue())
self.state.dx_max = copy.deepcopy(self.dx_max)
self.state.dx_min = copy.deepcopy(self.dx_min)
self.state.dxl = copy.deepcopy(self.dxl)
self.state.dxw = copy.deepcopy(self.dxw)
self.state.slit_smearer = copy.deepcopy(self.slit_smearer.GetValue())
if len(self._disp_obj_dict) > 0:
for k, v in self._disp_obj_dict.iteritems():
self.state._disp_obj_dict[k] = v
self.state.values = copy.deepcopy(self.values)
self.state.weights = copy.deepcopy(self.weights)
## save plotting range
self._save_plotting_range()
self.state.orientation_params = []
self.state.orientation_params_disp = []
self.state.parameters = []
self.state.fittable_param = []
self.state.fixed_param = []
self.state.str_parameters = []
## save checkbutton state and txtcrtl values
self._copy_parameters_state(self.str_parameters,
self.state.str_parameters)
self._copy_parameters_state(self.orientation_params,
self.state.orientation_params)
self._copy_parameters_state(self.orientation_params_disp,
self.state.orientation_params_disp)
self._copy_parameters_state(self.parameters, self.state.parameters)
self._copy_parameters_state(self.fittable_param,
self.state.fittable_param)
self._copy_parameters_state(self.fixed_param, self.state.fixed_param)
#save chisqr
self.state.tcChi = self.tcChi.GetValue()
[docs] def save_current_state_fit(self):
"""
Store current state for fit_page
"""
## save model option
if self.model != None:
self.disp_list = self.model.getDispParamList()
self.state.disp_list = copy.deepcopy(self.disp_list)
self.state.model = self.model.clone()
if hasattr(self, "engine_type"):
self.state.engine_type = copy.deepcopy(self.engine_type)
self.state.enable2D = copy.deepcopy(self.enable2D)
self.state.values = copy.deepcopy(self.values)
self.state.weights = copy.deepcopy(self.weights)
## save data
self.state.data = copy.deepcopy(self.data)
if hasattr(self, "enable_disp"):
self.state.enable_disp = self.enable_disp.GetValue()
self.state.disable_disp = self.disable_disp.GetValue()
self.state.smearer = copy.deepcopy(self.current_smearer)
if hasattr(self, "enable_smearer"):
self.state.enable_smearer = \
copy.deepcopy(self.enable_smearer.GetValue())
self.state.disable_smearer = \
copy.deepcopy(self.disable_smearer.GetValue())
self.state.pinhole_smearer = \
copy.deepcopy(self.pinhole_smearer.GetValue())
self.state.slit_smearer = copy.deepcopy(self.slit_smearer.GetValue())
self.state.dI_noweight = copy.deepcopy(self.dI_noweight.GetValue())
self.state.dI_didata = copy.deepcopy(self.dI_didata.GetValue())
self.state.dI_sqrdata = copy.deepcopy(self.dI_sqrdata.GetValue())
self.state.dI_idata = copy.deepcopy(self.dI_idata.GetValue())
if hasattr(self, "disp_box") and self.disp_box != None:
self.state.disp_box = self.disp_box.GetCurrentSelection()
if len(self.disp_cb_dict) > 0:
for k, v in self.disp_cb_dict.iteritems():
if v == None:
self.state.disp_cb_dict[k] = v
else:
try:
self.state.disp_cb_dict[k] = v.GetValue()
except:
self.state.disp_cb_dict[k] = None
if len(self._disp_obj_dict) > 0:
for k, v in self._disp_obj_dict.iteritems():
self.state._disp_obj_dict[k] = v
self.state.values = copy.deepcopy(self.values)
self.state.weights = copy.deepcopy(self.weights)
## save plotting range
self._save_plotting_range()
## save checkbutton state and txtcrtl values
self._copy_parameters_state(self.orientation_params,
self.state.orientation_params)
self._copy_parameters_state(self.orientation_params_disp,
self.state.orientation_params_disp)
self._copy_parameters_state(self.parameters, self.state.parameters)
self._copy_parameters_state(self.fittable_param,
self.state.fittable_param)
self._copy_parameters_state(self.fixed_param, self.state.fixed_param)
[docs] def check_invalid_panel(self):
"""
check if the user can already perform some action with this panel
"""
if self.data is None:
self.disable_smearer.SetValue(True)
self.disable_disp.SetValue(True)
msg = "Please load Data and select Model to start..."
wx.MessageBox(msg, 'Info')
return True
[docs] def set_model_state(self, state):
"""
reset page given a model state
"""
self.disp_cb_dict = state.disp_cb_dict
self.disp_list = state.disp_list
## set the state of the radio box
#self.shape_rbutton.SetValue(state.shape_rbutton)
#self.shape_indep_rbutton.SetValue(state.shape_indep_rbutton)
#self.struct_rbutton.SetValue(state.struct_rbutton)
#self.plugin_rbutton.SetValue(state.plugin_rbutton)
## fill model combobox
self._show_combox_helper()
#select the current model
try:
# to support older version
category_pos = int(state.categorycombobox)
except:
category_pos = 0
for ind_cat in range(self.categorybox.GetCount()):
if self.categorycombobox.GetString(ind_form) == \
state.categorycombobox:
category_pos = int(ind_cat)
break
self.categorybox.Select(category_pos)
try:
# to support older version
formfactor_pos = int(state.formfactorcombobox)
except:
formfactor_pos = 0
for ind_form in range(self.formfactorbox.GetCount()):
if self.formfactorbox.GetString(ind_form) == \
state.formfactorcombobox:
formfactor_pos = int(ind_form)
break
self.formfactorbox.Select(formfactor_pos)
try:
# to support older version
structfactor_pos = int(state.structurecombobox)
except:
structfactor_pos = 0
for ind_struct in range(self.structurebox.GetCount()):
if self.structurebox.GetString(ind_struct) == \
state.structurecombobox:
structfactor_pos = int(ind_struct)
break
self.structurebox.SetSelection(structfactor_pos)
if state.multi_factor != None:
self.multifactorbox.SetSelection(state.multi_factor)
## reset state of checkbox,textcrtl and regular parameters value
self._reset_parameters_state(self.orientation_params_disp,
state.orientation_params_disp)
self._reset_parameters_state(self.orientation_params,
state.orientation_params)
self._reset_parameters_state(self.str_parameters,
state.str_parameters)
self._reset_parameters_state(self.parameters, state.parameters)
## display dispersion info layer
self.enable_disp.SetValue(state.enable_disp)
self.disable_disp.SetValue(state.disable_disp)
if hasattr(self, "disp_box") and self.disp_box != None:
self.disp_box.SetSelection(state.disp_box)
n = self.disp_box.GetCurrentSelection()
dispersity = self.disp_box.GetClientData(n)
name = dispersity.__name__
self._set_dipers_Param(event=None)
if name == "ArrayDispersion":
for item in self.disp_cb_dict.keys():
if hasattr(self.disp_cb_dict[item], "SetValue"):
self.disp_cb_dict[item].SetValue(\
state.disp_cb_dict[item])
# Create the dispersion objects
from sas.models.dispersion_models import ArrayDispersion
disp_model = ArrayDispersion()
if hasattr(state, "values") and \
self.disp_cb_dict[item].GetValue() == True:
if len(state.values) > 0:
self.values = state.values
self.weights = state.weights
disp_model.set_weights(self.values,
state.weights)
else:
self._reset_dispersity()
self._disp_obj_dict[item] = disp_model
# Set the new model as the dispersion object
#for the selected parameter
self.model.set_dispersion(item, disp_model)
self.model._persistency_dict[item] = \
[state.values, state.weights]
else:
keys = self.model.getParamList()
for item in keys:
if item in self.disp_list and \
not item in self.model.details:
self.model.details[item] = ["", None, None]
self.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
self.state.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
## smearing info restore
if hasattr(self, "enable_smearer"):
## set smearing value whether or not the data
#contain the smearing info
self.enable_smearer.SetValue(state.enable_smearer)
self.disable_smearer.SetValue(state.disable_smearer)
self.onSmear(event=None)
self.pinhole_smearer.SetValue(state.pinhole_smearer)
self.slit_smearer.SetValue(state.slit_smearer)
self.dI_noweight.SetValue(state.dI_noweight)
self.dI_didata.SetValue(state.dI_didata)
self.dI_sqrdata.SetValue(state.dI_sqrdata)
self.dI_idata.SetValue(state.dI_idata)
## we have two more options for smearing
if self.pinhole_smearer.GetValue():
self.onPinholeSmear(event=None)
elif self.slit_smearer.GetValue():
self.onSlitSmear(event=None)
## reset state of checkbox,textcrtl and dispersity parameters value
self._reset_parameters_state(self.fittable_param, state.fittable_param)
self._reset_parameters_state(self.fixed_param, state.fixed_param)
## draw the model with previous parameters value
self._onparamEnter_helper()
self.select_param(event=None)
#Save state_fit
self.save_current_state_fit()
self._lay_out()
self.Refresh()
[docs] def reset_page_helper(self, state):
"""
Use page_state and change the state of existing page
:precondition: the page is already drawn or created
:postcondition: the state of the underlying data change as well as the
state of the graphic interface
"""
if state == None:
return
# set data, etc. from the state
# reset page between theory and fitting from bookmarking
#if state.data == None:
# data = None
#else:
data = state.data
if data == None:
data_min = state.qmin
data_max = state.qmax
self.qmin_x = data_min
self.qmax_x = data_max
self.qmin.SetValue(str(data_min))
self.qmax.SetValue(str(data_max))
self.state.data = data
self.state.qmin = self.qmin_x
self.state.qmax = self.qmax_x
else:
self.set_data(data)
self.enable2D = state.enable2D
try:
self.magnetic_on = state.magnetic_on
except:
# Backward compatibility (for older state files)
self.magnetic_on = False
self.engine_type = state.engine_type
self.disp_cb_dict = state.disp_cb_dict
self.disp_list = state.disp_list
## set the state of the radio box
#self.shape_rbutton.SetValue(state.shape_rbutton)
#self.shape_indep_rbutton.SetValue(state.shape_indep_rbutton)
#self.struct_rbutton.SetValue(state.struct_rbutton)
#self.plugin_rbutton.SetValue(state.plugin_rbutton)
## fill model combobox
self._show_combox_helper()
#select the current model
try:
# to support older version
category_pos = int(state.categorycombobox)
except:
category_pos = 0
for ind_cat in range(self.categorybox.GetCount()):
if self.categorybox.GetString(ind_cat) == \
state.categorycombobox:
category_pos = int(ind_cat)
break
self.categorybox.Select(category_pos)
self._show_combox(None)
try:
# to support older version
formfactor_pos = int(state.formfactorcombobox)
except:
formfactor_pos = 0
for ind_form in range(self.formfactorbox.GetCount()):
if self.formfactorbox.GetString(ind_form) == \
(state.formfactorcombobox):
formfactor_pos = int(ind_form)
break
self.formfactorbox.Select(formfactor_pos)
try:
# to support older version
structfactor_pos = int(state.structurecombobox)
except:
structfactor_pos = 0
for ind_struct in range(self.structurebox.GetCount()):
if self.structurebox.GetString(ind_struct) == \
(state.structurecombobox):
structfactor_pos = int(ind_struct)
break
self.structurebox.SetSelection(structfactor_pos)
if state.multi_factor != None:
self.multifactorbox.SetSelection(state.multi_factor)
#reset the fitting engine type
self.engine_type = state.engine_type
#draw the pnael according to the new model parameter
self._on_select_model(event=None)
# take care of 2D button
if data == None and self.model_view.IsEnabled():
if self.enable2D:
self.model_view.SetLabel("2D Mode")
else:
self.model_view.SetLabel("1D Mode")
# else:
if self._manager != None and self.engine_type != None:
self._manager._on_change_engine(engine=self.engine_type)
## set the select all check box to the a given state
self.cb1.SetValue(state.cb1)
## reset state of checkbox,textcrtl and regular parameters value
self._reset_parameters_state(self.orientation_params_disp,
state.orientation_params_disp)
self._reset_parameters_state(self.orientation_params,
state.orientation_params)
self._reset_parameters_state(self.str_parameters,
state.str_parameters)
self._reset_parameters_state(self.parameters, state.parameters)
## display dispersion info layer
self.enable_disp.SetValue(state.enable_disp)
self.disable_disp.SetValue(state.disable_disp)
# If the polydispersion is ON
if state.enable_disp:
# reset dispersion according the state
self._set_dipers_Param(event=None)
self._reset_page_disp_helper(state)
##plotting range restore
self._reset_plotting_range(state)
## smearing info restore
if hasattr(self, "enable_smearer"):
## set smearing value whether or not the data
#contain the smearing info
self.enable_smearer.SetValue(state.enable_smearer)
self.disable_smearer.SetValue(state.disable_smearer)
self.onSmear(event=None)
self.pinhole_smearer.SetValue(state.pinhole_smearer)
self.slit_smearer.SetValue(state.slit_smearer)
try:
self.dI_noweight.SetValue(state.dI_noweight)
self.dI_didata.SetValue(state.dI_didata)
self.dI_sqrdata.SetValue(state.dI_sqrdata)
self.dI_idata.SetValue(state.dI_idata)
except:
# to support older state file formats
self.dI_noweight.SetValue(False)
self.dI_didata.SetValue(True)
self.dI_sqrdata.SetValue(False)
self.dI_idata.SetValue(False)
## we have two more options for smearing
if self.pinhole_smearer.GetValue():
self.dx_min = state.dx_min
self.dx_max = state.dx_max
if self.dx_min != None:
self.smear_pinhole_min.SetValue(str(self.dx_min))
if self.dx_max != None:
self.smear_pinhole_max.SetValue(str(self.dx_max))
self.onPinholeSmear(event=None)
elif self.slit_smearer.GetValue():
self.dxl = state.dxl
self.dxw = state.dxw
if self.dxl != None:
self.smear_slit_height.SetValue(str(self.dxl))
if self.dxw != None:
self.smear_slit_width.SetValue(str(self.dxw))
else:
self.smear_slit_width.SetValue('')
self.onSlitSmear(event=None)
## reset state of checkbox,textcrtl and dispersity parameters value
self._reset_parameters_state(self.fittable_param, state.fittable_param)
self._reset_parameters_state(self.fixed_param, state.fixed_param)
## draw the model with previous parameters value
self._onparamEnter_helper()
#reset the value of chisqr when not consistent with the value computed
self.tcChi.SetValue(str(self.state.tcChi))
## reset context menu items
self._reset_context_menu()
## set the value of the current state to the state given as parameter
self.state = state.clone()
self.state.m_name = self.m_name
def _reset_page_disp_helper(self, state):
"""
Help to rest page for dispersions
"""
keys = self.model.getParamList()
for item in keys:
if item in self.disp_list and \
not item in self.model.details:
self.model.details[item] = ["", None, None]
#for k,v in self.state.disp_cb_dict.iteritems():
self.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
self.state.disp_cb_dict = copy.deepcopy(state.disp_cb_dict)
self.values = copy.deepcopy(state.values)
self.weights = copy.deepcopy(state.weights)
for key, disp in state._disp_obj_dict.iteritems():
# From saved file, disp_model can not be sent in model obj.
# it will be sent as a string here, then converted to model object.
if disp.__class__.__name__ == 'str':
disp_model = None
com_str = "from sas.models.dispersion_models "
com_str += "import %s as disp_func \ndisp_model = disp_func()"
exec com_str % disp
else:
disp_model = disp
self._disp_obj_dict[key] = disp_model
param_name = key.split('.')[0]
# Try to set dispersion only when available
# for eg., pass the orient. angles for 1D Cal
try:
self.model.set_dispersion(param_name, disp_model)
self.model._persistency_dict[key] = \
[state.values, state.weights]
except:
pass
selection = self._find_polyfunc_selection(disp_model)
for list in self.fittable_param:
if list[1] == key and list[7] != None:
list[7].SetSelection(selection)
# For the array disp_model, set the values and weights
if selection == 1:
disp_model.set_weights(self.values[key],
self.weights[key])
try:
# Diables all fittable params for array
list[0].SetValue(False)
list[0].Disable()
list[2].Disable()
list[5].Disable()
list[6].Disable()
except:
pass
# For array, disable all fixed params
if selection == 1:
for item in self.fixed_param:
if item[1].split(".")[0] == key.split(".")[0]:
# try it and pass it for the orientation for 1D
try:
item[2].Disable()
except:
pass
# Make sure the check box updated when all checked
if self.cb1.GetValue():
self.select_all_param(None)
def _selectDlg(self):
"""
open a dialog file to selected the customized dispersity
"""
if self.parent != None:
self._default_save_location = \
self._manager.parent.get_save_location()
dlg = wx.FileDialog(self, "Choose a weight file",
self._default_save_location, "",
"*.*", wx.OPEN)
path = None
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
dlg.Destroy()
return path
def _reset_context_menu(self):
"""
reset the context menu
"""
for name, _ in self.state.saved_states.iteritems():
self.number_saved_state += 1
## Add item in the context menu
id = wx.NewId()
msg = 'Save model and state %g' % self.number_saved_state
self.popUpMenu.Append(id, name, msg)
wx.EVT_MENU(self, id, self.onResetModel)
def _reset_plotting_range(self, state):
"""
Reset the plotting range to a given state
"""
self.qmin.SetValue(str(state.qmin))
self.qmax.SetValue(str(state.qmax))
def _save_typeOfmodel(self):
"""
save radiobutton containing the type model that can be selected
"""
#self.state.shape_rbutton = self.shape_rbutton.GetValue()
#self.state.shape_indep_rbutton = self.shape_indep_rbutton.GetValue()
#self.state.struct_rbutton = self.struct_rbutton.GetValue()
#self.state.plugin_rbutton = self.plugin_rbutton.GetValue()
self.state.structurecombobox = self.structurebox.GetLabel()
self.state.formfactorcombobox = self.formfactorbox.GetLabel()
self.state.categorycombobox = self.categorybox.GetLabel()
## post state to fit panel
event = PageInfoEvent(page=self)
wx.PostEvent(self.parent, event)
def _save_plotting_range(self):
"""
save the state of plotting range
"""
self.state.qmin = self.qmin_x
self.state.qmax = self.qmax_x
self.state.npts = self.npts_x
def _onparamEnter_helper(self):
"""
check if values entered by the user are changed and valid to replot
model
"""
# Flag to register when a parameter has changed.
is_modified = False
self.fitrange = True
is_2Ddata = False
#self._undo.Enable(True)
# check if 2d data
if self.data.__class__.__name__ == "Data2D":
is_2Ddata = True
if self.model != None:
try:
is_modified = self._check_value_enter(self.fittable_param,
is_modified)
is_modified = self._check_value_enter(self.fixed_param,
is_modified)
is_modified = self._check_value_enter(self.parameters,
is_modified)
except:
pass
# Here we should check whether the boundaries have been modified.
# If qmin and qmax have been modified, update qmin and qmax and
# set the is_modified flag to True
if self._validate_qrange(self.qmin, self.qmax):
tempmin = float(self.qmin.GetValue())
if tempmin != self.qmin_x:
self.qmin_x = tempmin
is_modified = True
tempmax = float(self.qmax.GetValue())
if tempmax != self.qmax_x:
self.qmax_x = tempmax
is_modified = True
if is_2Ddata:
# set mask
is_modified = self._validate_Npts()
else:
self.fitrange = False
if not self.data.is_data:
is_modified = True
## if any value is modify draw model with new value
if not self.fitrange:
#self.btFit.Disable()
if is_2Ddata:
self.btEditMask.Disable()
else:
if is_2Ddata and self.data.is_data and not self.batch_on:
self.btEditMask.Enable(True)
if is_modified and self.fitrange:
# Theory case: need to get npts value to draw
self.npts_x = float(self.Npts_total.GetValue())
self.create_default_data()
self.state_change = True
self._draw_model()
self.Refresh()
return is_modified
def _update_paramv_on_fit(self):
"""
make sure that update param values just before the fitting
"""
#flag for qmin qmax check values
flag = True
self.fitrange = True
is_modified = False
#wx.PostEvent(self._manager.parent, StatusEvent(status=" \
#updating ... ",type="update"))
##So make sure that update param values on_Fit.
#self._undo.Enable(True)
if self.model != None:
if self.Npts_total.GetValue() != self.Npts_fit.GetValue():
if not self.data.is_data:
self._manager.page_finder[self.uid].set_fit_data(data=\
[self.data])
##Check the values
self._check_value_enter(self.fittable_param, is_modified)
self._check_value_enter(self.fixed_param, is_modified)
self._check_value_enter(self.parameters, is_modified)
# If qmin and qmax have been modified, update qmin and qmax and
# Here we should check whether the boundaries have been modified.
# If qmin and qmax have been modified, update qmin and qmax and
# set the is_modified flag to True
self.fitrange = self._validate_qrange(self.qmin, self.qmax)
if self.fitrange:
tempmin = float(self.qmin.GetValue())
if tempmin != self.qmin_x:
self.qmin_x = tempmin
tempmax = float(self.qmax.GetValue())
if tempmax != self.qmax_x:
self.qmax_x = tempmax
if tempmax == tempmin:
flag = False
temp_smearer = None
if not self.disable_smearer.GetValue():
temp_smearer = self.current_smearer
if self.slit_smearer.GetValue():
flag = self.update_slit_smear()
elif self.pinhole_smearer.GetValue():
flag = self.update_pinhole_smear()
else:
self._manager.set_smearer(smearer=temp_smearer,
uid=self.uid,
fid=self.data.id,
qmin=float(self.qmin_x),
qmax=float(self.qmax_x),
enable_smearer=not self.disable_smearer.GetValue(),
draw=False)
elif not self._is_2D():
self._manager.set_smearer(smearer=temp_smearer,
qmin=float(self.qmin_x),
uid=self.uid,
fid=self.data.id,
qmax=float(self.qmax_x),
enable_smearer=not self.disable_smearer.GetValue(),
draw=False)
if self.data != None:
index_data = ((self.qmin_x <= self.data.x) & \
(self.data.x <= self.qmax_x))
val = str(len(self.data.x[index_data == True]))
self.Npts_fit.SetValue(val)
else:
# No data in the panel
try:
self.npts_x = float(self.Npts_total.GetValue())
except:
flag = False
return flag
flag = True
if self._is_2D():
# only 2D case set mask
flag = self._validate_Npts()
if not flag:
return flag
else:
flag = False
else:
flag = False
#For invalid q range, disable the mask editor and fit button, vs.
if not self.fitrange:
if self._is_2D():
self.btEditMask.Disable()
else:
if self._is_2D() and self.data.is_data and not self.batch_on:
self.btEditMask.Enable(True)
if not flag:
msg = "Cannot Plot or Fit :Must select a "
msg += " model or Fitting range is not valid!!! "
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
try:
self.save_current_state()
except:
pass
return flag
def _is_modified(self, is_modified):
"""
return to self._is_modified
"""
return is_modified
def _reset_parameters_state(self, listtorestore, statelist):
"""
Reset the parameters at the given state
"""
if len(statelist) == 0 or len(listtorestore) == 0:
return
if len(statelist) != len(listtorestore):
return
for j in range(len(listtorestore)):
item_page = listtorestore[j]
item_page_info = statelist[j]
##change the state of the check box for simple parameters
if item_page[0] != None:
item_page[0].SetValue(item_page_info[0])
if item_page[2] != None:
item_page[2].SetValue(item_page_info[2])
if item_page[2].__class__.__name__ == "ComboBox":
if item_page_info[2] in self.model.fun_list:
fun_val = self.model.fun_list[item_page_info[2]]
self.model.setParam(item_page_info[1], fun_val)
if item_page[3] != None:
## show or hide text +/-
if item_page_info[2]:
item_page[3].Show(True)
else:
item_page[3].Hide()
if item_page[4] != None:
## show of hide the text crtl for fitting error
if item_page_info[4][0]:
item_page[4].Show(True)
item_page[4].SetValue(item_page_info[4][1])
else:
item_page[3].Hide()
if item_page[5] != None:
## show of hide the text crtl for fitting error
item_page[5].Show(item_page_info[5][0])
item_page[5].SetValue(item_page_info[5][1])
if item_page[6] != None:
## show of hide the text crtl for fitting error
item_page[6].Show(item_page_info[6][0])
item_page[6].SetValue(item_page_info[6][1])
def _reset_strparam_state(self, listtorestore, statelist):
"""
Reset the string parameters at the given state
"""
if len(statelist) == 0:
return
listtorestore = copy.deepcopy(statelist)
for j in range(len(listtorestore)):
item_page = listtorestore[j]
item_page_info = statelist[j]
##change the state of the check box for simple parameters
if item_page[0] != None:
item_page[0].SetValue(format_number(item_page_info[0], True))
if item_page[2] != None:
param_name = item_page_info[1]
value = item_page_info[2]
selection = value
if value in self.model.fun_list:
selection = self.model.fun_list[value]
item_page[2].SetValue(selection)
self.model.setParam(param_name, selection)
def _copy_parameters_state(self, listtocopy, statelist):
"""
copy the state of button
:param listtocopy: the list of check button to copy
:param statelist: list of state object to store the current state
"""
if len(listtocopy) == 0:
return
for item in listtocopy:
checkbox_state = None
if item[0] != None:
checkbox_state = item[0].GetValue()
parameter_name = item[1]
parameter_value = None
if item[2] != None:
parameter_value = item[2].GetValue()
static_text = None
if item[3] != None:
static_text = item[3].IsShown()
error_value = None
error_state = None
if item[4] != None:
error_value = item[4].GetValue()
error_state = item[4].IsShown()
min_value = None
min_state = None
if item[5] != None:
min_value = item[5].GetValue()
min_state = item[5].IsShown()
max_value = None
max_state = None
if item[6] != None:
max_value = item[6].GetValue()
max_state = item[6].IsShown()
unit = None
if item[7] != None:
unit = item[7].GetLabel()
statelist.append([checkbox_state, parameter_name, parameter_value,
static_text, [error_state, error_value],
[min_state, min_value],
[max_state, max_value], unit])
# The following funcion seems to be superseded with fillsizer and
# init combo box. certainly it seems not to know about categories and uses
# only shapes and shape independent -- tested after commenting out and does
# not seem to cause problem. Leave commented out for now but delete in
# a code cleanup once clear it really is no longer used.
# PDB 8 April 2014
# def _set_model_sizer_selection(self, model):
# """
# Display the sizer according to the type of the current model
# """
# if model == None:
# return
# if hasattr(model, "s_model"):
#
# class_name = model.s_model.__class__
# name = model.s_model.name
# flag = (name != "NoStructure")
# if flag and \
# (class_name in self.model_list_box["Structure Factors"]):
# self.structurebox.Show()
# self.text2.Show()
# self.structurebox.Enable()
# self.text2.Enable()
# items = self.structurebox.GetItems()
# self.sizer1.Layout()
#
# for i in range(len(items)):
# if items[i] == str(name):
# self.structurebox.SetSelection(i)
# break
#
# if hasattr(model, "p_model"):
# class_name = model.p_model.__class__
# name = model.p_model.name
# self.formfactorbox.Clear()
#
# for k, list in self.model_list_box.iteritems():
# if k in["P(Q)*S(Q)", "Shapes"] and \
# class_name in self.model_list_box["Shapes"]:
# self.shape_rbutton.SetValue(True)
# ## fill the form factor list with new model
# self._populate_box(self.formfactorbox,
# self.model_list_box["Shapes"])
# items = self.formfactorbox.GetItems()
# ## set comboxbox to the selected item
# for i in range(len(items)):
# if items[i] == str(name):
# self.formfactorbox.SetSelection(i)
# break
# return
# elif k == "Shape-Independent":
# self.shape_indep_rbutton.SetValue(True)
# elif k == "Structure Factors":
# self.struct_rbutton.SetValue(True)
# elif k == "Multi-Functions":
# continue
# else:
# self.plugin_rbutton.SetValue(True)
#
# if class_name in list:
# ## fill the form factor list with new model
# self._populate_box(self.formfactorbox, list)
# items = self.formfactorbox.GetItems()
# ## set comboxbox to the selected item
# for i in range(len(items)):
# if items[i] == str(name):
# self.formfactorbox.SetSelection(i)
# break
# break
# else:
## Select the model from the menu
# class_name = model.__class__
# name = model.name
# self.formfactorbox.Clear()
# items = self.formfactorbox.GetItems()
#
# for k, list in self.model_list_box.iteritems():
# if k in["P(Q)*S(Q)", "Shapes"] and \
# class_name in self.model_list_box["Shapes"]:
# if class_name in self.model_list_box["P(Q)*S(Q)"]:
# self.structurebox.Show()
# self.text2.Show()
# self.structurebox.Enable()
# self.structurebox.SetSelection(0)
# self.text2.Enable()
# else:
# self.structurebox.Hide()
# self.text2.Hide()
# self.structurebox.Disable()
# self.structurebox.SetSelection(0)
# self.text2.Disable()
#
# self.shape_rbutton.SetValue(True)
## fill the form factor list with new model
# self._populate_box(self.formfactorbox,
# self.model_list_box["Shapes"])
# items = self.formfactorbox.GetItems()
# ## set comboxbox to the selected item
# for i in range(len(items)):
# if items[i] == str(name):
# self.formfactorbox.SetSelection(i)
# break
# return
# elif k == "Shape-Independent":
# self.shape_indep_rbutton.SetValue(True)
# elif k == "Structure Factors":
# self.struct_rbutton.SetValue(True)
# elif k == "Multi-Functions":
# continue
# else:
# self.plugin_rbutton.SetValue(True)
# if class_name in list:
# self.structurebox.SetSelection(0)
# self.structurebox.Disable()
# self.text2.Disable()
## fill the form factor list with new model
# self._populate_box(self.formfactorbox, list)
# items = self.formfactorbox.GetItems()
## set comboxbox to the selected item
# for i in range(len(items)):
# if items[i] == str(name):
# self.formfactorbox.SetSelection(i)
# break
# break
def _draw_model(self, update_chisqr=True, source='model'):
"""
Method to draw or refresh a plotted model.
The method will use the data member from the model page
to build a call to the fitting perspective manager.
:param chisqr: update chisqr value [bool]
"""
wx.CallAfter(self._draw_model_after, update_chisqr, source)
def _draw_model_after(self, update_chisqr=True, source='model'):
"""
Method to draw or refresh a plotted model.
The method will use the data member from the model page
to build a call to the fitting perspective manager.
:param chisqr: update chisqr value [bool]
"""
#if self.check_invalid_panel():
# return
if self.model != None:
temp_smear = None
if hasattr(self, "enable_smearer"):
if not self.disable_smearer.GetValue():
temp_smear = self.current_smearer
# compute weight for the current data
from sas.perspectives.fitting.utils import get_weight
flag = self.get_weight_flag()
weight = get_weight(data=self.data, is2d=self._is_2D(), flag=flag)
toggle_mode_on = self.model_view.IsEnabled()
is_2d = self._is_2D()
self._manager.draw_model(self.model,
data=self.data,
smearer=temp_smear,
qmin=float(self.qmin_x),
qmax=float(self.qmax_x),
page_id=self.uid,
toggle_mode_on=toggle_mode_on,
state=self.state,
enable2D=is_2d,
update_chisqr=update_chisqr,
source='model',
weight=weight)
def _on_show_sld(self, event=None):
"""
Plot SLD profile
"""
# get profile data
x, y = self.model.getProfile()
from sas.plottools import Data1D as pf_data1d
#from sas.perspectives.theory.profile_dialog import SLDPanel
from sas.guiframe.local_perspectives.plotting.profile_dialog \
import SLDPanel
sld_data = pf_data1d(x, y)
sld_data.name = 'SLD'
sld_data.axes = self.sld_axes
self.panel = SLDPanel(self, data=sld_data, axes=self.sld_axes, id=-1)
self.panel.ShowModal()
def _set_multfactor_combobox(self, multiplicity=10):
"""
Set comboBox for muitfactor of CoreMultiShellModel
:param multiplicit: no. of multi-functionality
"""
# build content of the combobox
for idx in range(0, multiplicity):
self.multifactorbox.Append(str(idx), int(idx))
self._hide_multfactor_combobox()
def _show_multfactor_combobox(self):
"""
Show the comboBox of muitfactor of CoreMultiShellModel
"""
if not self.mutifactor_text.IsShown():
self.mutifactor_text.Show(True)
self.mutifactor_text1.Show(True)
if not self.multifactorbox.IsShown():
self.multifactorbox.Show(True)
def _hide_multfactor_combobox(self):
"""
Hide the comboBox of muitfactor of CoreMultiShellModel
"""
if self.mutifactor_text.IsShown():
self.mutifactor_text.Hide()
self.mutifactor_text1.Hide()
if self.multifactorbox.IsShown():
self.multifactorbox.Hide()
[docs] def formfactor_combo_init(self):
"""
First time calls _show_combox_helper
"""
self._show_combox(None)
def _show_combox_helper(self):
"""
Fill panel's combo box according to the type of model selected
"""
custom_model = 'Customized Models'
mod_cat = self.categorybox.GetStringSelection()
self.structurebox.SetSelection(0)
self.structurebox.Disable()
self.formfactorbox.Clear()
if mod_cat == None:
return
m_list = []
try:
if mod_cat == custom_model:
for model in self.model_list_box[mod_cat]:
str_m = str(model).split(".")[0]
#self.model_box.Append(str_m)
m_list.append(self.model_dict[str_m])
else:
cat_dic = self.master_category_dict[mod_cat]
for (model, enabled) in cat_dic:
if enabled:
m_list.append(self.model_dict[model])
#else:
# msg = "This model is disabled by Category Manager."
# wx.PostEvent(self.parent.parent,
# StatusEvent(status=msg, info="error"))
except:
msg = "%s\n" % (sys.exc_value)
wx.PostEvent(self._manager.parent,
StatusEvent(status=msg, info="error"))
self._populate_box(self.formfactorbox, m_list)
def _on_modify_cat(self, event=None):
self._manager.parent.on_category_panel(event)
def _show_combox(self, event=None):
"""
Show combox box associate with type of model selected
"""
self.Show(False)
self._show_combox_helper()
self._on_select_model(event=None)
self.Show(True)
self._save_typeOfmodel()
self.sizer4_4.Layout()
self.sizer4.Layout()
self.Layout()
self.Refresh()
def _populate_box(self, combobox, list):
"""
fill combox box with dict item
:param list: contains item to fill the combox
item must model class
"""
mlist = []
for models in list:
model = models()
name = model.__class__.__name__
if models.__name__ != "NoStructure":
if hasattr(model, "name"):
name = model.name
mlist.append((name, models))
# Sort the models
mlist_sorted = sorted(mlist)
for item in mlist_sorted:
combobox.Append(item[0], item[1])
return 0
def _onQrangeEnter(self, event):
"""
Check validity of value enter in the Q range field
"""
tcrtl = event.GetEventObject()
#Clear msg if previously shown.
msg = ""
wx.PostEvent(self.parent, StatusEvent(status=msg))
# Flag to register when a parameter has changed.
#is_modified = False
if tcrtl.GetValue().lstrip().rstrip() != "":
try:
float(tcrtl.GetValue())
tcrtl.SetBackgroundColour(wx.WHITE)
# If qmin and qmax have been modified, update qmin and qmax
if self._validate_qrange(self.qmin, self.qmax):
tempmin = float(self.qmin.GetValue())
if tempmin != self.qmin_x:
self.qmin_x = tempmin
tempmax = float(self.qmax.GetValue())
if tempmax != self.qmax_x:
self.qmax_x = tempmax
else:
tcrtl.SetBackgroundColour("pink")
msg = "Model Error: wrong value entered: %s" % sys.exc_value
wx.PostEvent(self.parent, StatusEvent(status=msg))
return
except:
tcrtl.SetBackgroundColour("pink")
msg = "Model Error: wrong value entered: %s" % sys.exc_value
wx.PostEvent(self.parent, StatusEvent(status=msg))
return
#Check if # of points for theory model are valid(>0).
if self.npts != None:
if check_float(self.npts):
temp_npts = float(self.npts.GetValue())
if temp_npts != self.num_points:
self.num_points = temp_npts
#is_modified = True
else:
msg = "Cannot plot: No points in Q range!!! "
wx.PostEvent(self.parent, StatusEvent(status=msg))
else:
tcrtl.SetBackgroundColour("pink")
msg = "Model Error: wrong value entered!!!"
wx.PostEvent(self.parent, StatusEvent(status=msg))
self.save_current_state()
event = PageInfoEvent(page=self)
wx.PostEvent(self.parent, event)
self.state_change = False
#Draw the model for a different range
if not self.data.is_data:
self.create_default_data()
self._draw_model()
def _theory_qrange_enter(self, event):
"""
Check validity of value enter in the Q range field
"""
tcrtl = event.GetEventObject()
#Clear msg if previously shown.
msg = ""
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
# Flag to register when a parameter has changed.
is_modified = False
if tcrtl.GetValue().lstrip().rstrip() != "":
try:
value = float(tcrtl.GetValue())
tcrtl.SetBackgroundColour(wx.WHITE)
# If qmin and qmax have been modified, update qmin and qmax
if self._validate_qrange(self.theory_qmin, self.theory_qmax):
tempmin = float(self.theory_qmin.GetValue())
if tempmin != self.theory_qmin_x:
self.theory_qmin_x = tempmin
tempmax = float(self.theory_qmax.GetValue())
if tempmax != self.qmax_x:
self.theory_qmax_x = tempmax
else:
tcrtl.SetBackgroundColour("pink")
msg = "Model Error: wrong value entered: %s" % sys.exc_value
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
return
except:
tcrtl.SetBackgroundColour("pink")
msg = "Model Error: wrong value entered: %s" % sys.exc_value
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
return
#Check if # of points for theory model are valid(>0).
if self.Npts_total.IsEditable():
if check_float(self.Npts_total):
temp_npts = float(self.Npts_total.GetValue())
if temp_npts != self.num_points:
self.num_points = temp_npts
is_modified = True
else:
msg = "Cannot Plot: No points in Q range!!! "
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
else:
tcrtl.SetBackgroundColour("pink")
msg = "Model Error: wrong value entered!!!"
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
self.save_current_state()
event = PageInfoEvent(page=self)
wx.PostEvent(self.parent, event)
self.state_change = False
#Draw the model for a different range
self.create_default_data()
self._draw_model()
def _on_select_model_helper(self):
"""
call back for model selection
"""
## reset dictionary containing reference to dispersion
self._disp_obj_dict = {}
self.disp_cb_dict = {}
self.temp_multi_functional = False
f_id = self.formfactorbox.GetCurrentSelection()
#For MAC
form_factor = None
if f_id >= 0:
form_factor = self.formfactorbox.GetClientData(f_id)
if not form_factor in self.model_list_box["multiplication"]:
self.structurebox.Hide()
self.text2.Hide()
self.structurebox.Disable()
self.structurebox.SetSelection(0)
self.text2.Disable()
else:
self.structurebox.Show()
self.text2.Show()
self.structurebox.Enable()
self.text2.Enable()
if form_factor != None:
# set multifactor for Mutifunctional models
if form_factor().__class__ in \
self.model_list_box["Multi-Functions"]:
m_id = self.multifactorbox.GetCurrentSelection()
multiplicity = form_factor().multiplicity_info[0]
self.multifactorbox.Clear()
self._set_multfactor_combobox(multiplicity)
self._show_multfactor_combobox()
#ToDo: this info should be called directly from the model
text = form_factor().multiplicity_info[1] # 'No. of Shells: '
self.mutifactor_text.SetLabel(text)
if m_id > multiplicity - 1:
# default value
m_id = 1
self.multi_factor = self.multifactorbox.GetClientData(m_id)
if self.multi_factor == None:
self.multi_factor = 0
form_factor = form_factor(int(self.multi_factor))
self.multifactorbox.SetSelection(m_id)
# Check len of the text1 and max_multiplicity
text = ''
if form_factor.multiplicity_info[0] == \
len(form_factor.multiplicity_info[2]):
text = form_factor.multiplicity_info[2][self.multi_factor]
self.mutifactor_text1.SetLabel(text)
# Check if model has get sld profile.
if len(form_factor.multiplicity_info[3]) > 0:
self.sld_axes = form_factor.multiplicity_info[3]
self.show_sld_button.Show(True)
else:
self.sld_axes = ""
else:
self._hide_multfactor_combobox()
self.show_sld_button.Hide()
form_factor = form_factor()
self.multi_factor = None
else:
self._hide_multfactor_combobox()
self.show_sld_button.Hide()
self.multi_factor = None
s_id = self.structurebox.GetCurrentSelection()
struct_factor = self.structurebox.GetClientData(s_id)
if struct_factor != None:
from sas.models.MultiplicationModel import MultiplicationModel
self.model = MultiplicationModel(form_factor, struct_factor())
# multifunctional form factor
if len(form_factor.non_fittable) > 0:
self.temp_multi_functional = True
else:
if form_factor != None:
self.model = form_factor
else:
self.model = None
return self.model
# check if model has magnetic parameters
if len(self.model.magnetic_params) > 0:
self._has_magnetic = True
else:
self._has_magnetic = False
## post state to fit panel
self.state.parameters = []
self.state.model = self.model
self.state.qmin = self.qmin_x
self.state.multi_factor = self.multi_factor
self.disp_list = self.model.getDispParamList()
self.state.disp_list = self.disp_list
self.on_set_focus(None)
self.Layout()
def _validate_qrange(self, qmin_ctrl, qmax_ctrl):
"""
Verify that the Q range controls have valid values
and that Qmin < Qmax.
:param qmin_ctrl: text control for Qmin
:param qmax_ctrl: text control for Qmax
:return: True is the Q range is value, False otherwise
"""
qmin_validity = check_float(qmin_ctrl)
qmax_validity = check_float(qmax_ctrl)
if not (qmin_validity and qmax_validity):
return False
else:
qmin = float(qmin_ctrl.GetValue())
qmax = float(qmax_ctrl.GetValue())
if qmin < qmax:
#Make sure to set both colours white.
qmin_ctrl.SetBackgroundColour(wx.WHITE)
qmin_ctrl.Refresh()
qmax_ctrl.SetBackgroundColour(wx.WHITE)
qmax_ctrl.Refresh()
else:
qmin_ctrl.SetBackgroundColour("pink")
qmin_ctrl.Refresh()
qmax_ctrl.SetBackgroundColour("pink")
qmax_ctrl.Refresh()
msg = "Invalid Q range: Q min must be smaller than Q max"
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
return False
return True
def _validate_Npts(self):
"""
Validate the number of points for fitting is more than 10 points.
If valid, setvalues Npts_fit otherwise post msg.
"""
#default flag
flag = True
# Theory
if self.data == None and self.enable2D:
return flag
for data in self.data_list:
# q value from qx and qy
radius = numpy.sqrt(data.qx_data * data.qx_data +
data.qy_data * data.qy_data)
#get unmasked index
index_data = (float(self.qmin.GetValue()) <= radius) & \
(radius <= float(self.qmax.GetValue()))
index_data = (index_data) & (data.mask)
index_data = (index_data) & (numpy.isfinite(data.data))
if len(index_data[index_data]) < 10:
# change the color pink.
self.qmin.SetBackgroundColour("pink")
self.qmin.Refresh()
self.qmax.SetBackgroundColour("pink")
self.qmax.Refresh()
msg = "Data Error: "
msg += "Too few points in %s." % data.name
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
self.fitrange = False
flag = False
else:
self.Npts_fit.SetValue(str(len(index_data[index_data == True])))
self.fitrange = True
return flag
def _validate_Npts_1D(self):
"""
Validate the number of points for fitting is more than 5 points.
If valid, setvalues Npts_fit otherwise post msg.
"""
#default flag
flag = True
# Theory
if self.data == None:
return flag
for data in self.data_list:
# q value from qx and qy
radius = data.x
#get unmasked index
index_data = (float(self.qmin.GetValue()) <= radius) & \
(radius <= float(self.qmax.GetValue()))
index_data = (index_data) & (numpy.isfinite(data.y))
if len(index_data[index_data]) < 5:
# change the color pink.
self.qmin.SetBackgroundColour("pink")
self.qmin.Refresh()
self.qmax.SetBackgroundColour("pink")
self.qmax.Refresh()
msg = "Data Error: "
msg += "Too few points in %s." % data.name
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
self.fitrange = False
flag = False
else:
self.Npts_fit.SetValue(str(len(index_data[index_data == True])))
self.fitrange = True
return flag
def _check_value_enter(self, list, modified):
"""
:param list: model parameter and panel info
:Note: each item of the list should be as follow:
item=[check button state, parameter's name,
paramater's value, string="+/-",
parameter's error of fit,
parameter's minimum value,
parrameter's maximum value ,
parameter's units]
"""
is_modified = modified
if len(list) == 0:
return is_modified
for item in list:
#skip angle parameters for 1D
if not self.enable2D:
if item in self.orientation_params:
continue
#try:
name = str(item[1])
if string.find(name, ".npts") == -1 and \
string.find(name, ".nsigmas") == -1:
## check model parameters range
param_min = None
param_max = None
## check minimun value
if item[5] != None and item[5] != "":
if item[5].GetValue().lstrip().rstrip() != "":
try:
param_min = float(item[5].GetValue())
if not self._validate_qrange(item[5], item[2]):
if numpy.isfinite(param_min):
item[2].SetValue(format_number(param_min))
item[5].SetBackgroundColour(wx.WHITE)
item[2].SetBackgroundColour(wx.WHITE)
except:
msg = "Wrong fit parameter range entered"
wx.PostEvent(self._manager.parent,
StatusEvent(status=msg))
raise ValueError, msg
is_modified = True
## check maximum value
if item[6] != None and item[6] != "":
if item[6].GetValue().lstrip().rstrip() != "":
try:
param_max = float(item[6].GetValue())
if not self._validate_qrange(item[2], item[6]):
if numpy.isfinite(param_max):
item[2].SetValue(format_number(param_max))
item[6].SetBackgroundColour(wx.WHITE)
item[2].SetBackgroundColour(wx.WHITE)
except:
msg = "Wrong Fit parameter range entered "
wx.PostEvent(self._manager.parent,
StatusEvent(status=msg))
raise ValueError, msg
is_modified = True
if param_min != None and param_max != None:
if not self._validate_qrange(item[5], item[6]):
msg = "Wrong Fit range entered for parameter "
msg += "name %s of model %s " % (name, self.model.name)
wx.PostEvent(self._manager.parent,
StatusEvent(status=msg))
if name in self.model.details.keys():
self.model.details[name][1:3] = param_min, param_max
is_modified = True
else:
self.model.details[name] = ["", param_min, param_max]
is_modified = True
try:
# Check if the textctr is enabled
if item[2].IsEnabled():
value = float(item[2].GetValue())
item[2].SetBackgroundColour("white")
# If the value of the parameter has changed,
# +update the model and set the is_modified flag
if value != self.model.getParam(name) and \
numpy.isfinite(value):
self.model.setParam(name, value)
except:
item[2].SetBackgroundColour("pink")
msg = "Wrong Fit parameter value entered "
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
return is_modified
def _set_dipers_Param(self, event):
"""
respond to self.enable_disp and self.disable_disp radio box.
The dispersity object is reset inside the model into Gaussian.
When the user select yes , this method display a combo box for
more selection when the user selects No,the combo box disappears.
Redraw the model with the default dispersity (Gaussian)
"""
## On selction if no model exists.
if self.model == None:
self.disable_disp.SetValue(True)
msg = "Please select a Model first..."
wx.MessageBox(msg, 'Info')
wx.PostEvent(self._manager.parent,
StatusEvent(status="Polydispersion: %s" % msg))
return
self._reset_dispersity()
if self.model == None:
self.model_disp.Hide()
self.sizer4_4.Clear(True)
return
if self.enable_disp.GetValue():
## layout for model containing no dispersity parameters
self.disp_list = self.model.getDispParamList()
if len(self.disp_list) == 0 and len(self.disp_cb_dict) == 0:
self._layout_sizer_noDipers()
else:
## set gaussian sizer
self._on_select_Disp(event=None)
else:
self.sizer4_4.Clear(True)
## post state to fit panel
self.save_current_state()
if event != None:
event = PageInfoEvent(page=self)
wx.PostEvent(self.parent, event)
#draw the model with the current dispersity
self._draw_model()
self.sizer4_4.Layout()
self.sizer5.Layout()
self.Layout()
self.Refresh()
def _layout_sizer_noDipers(self):
"""
Draw a sizer with no dispersity info
"""
ix = 0
iy = 1
self.fittable_param = []
self.fixed_param = []
self.orientation_params_disp = []
self.sizer4_4.Clear(True)
text = "No polydispersity available for this model"
model_disp = wx.StaticText(self, -1, text)
self.sizer4_4.Add(model_disp, (iy, ix), (1, 1),
wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10)
self.sizer4_4.Layout()
self.sizer4.Layout()
def _reset_dispersity(self):
"""
put gaussian dispersity into current model
"""
if len(self.param_toFit) > 0:
for item in self.fittable_param:
if item in self.param_toFit:
self.param_toFit.remove(item)
for item in self.orientation_params_disp:
if item in self.param_toFit:
self.param_toFit.remove(item)
self.fittable_param = []
self.fixed_param = []
self.orientation_params_disp = []
self.values = {}
self.weights = {}
from sas.models.dispersion_models import GaussianDispersion
if len(self.disp_cb_dict) == 0:
self.save_current_state()
self.sizer4_4.Clear(True)
self.Layout()
return
if (len(self.disp_cb_dict) > 0):
for p in self.disp_cb_dict:
# The parameter was un-selected.
# Go back to Gaussian model (with 0 pts)
disp_model = GaussianDispersion()
self._disp_obj_dict[p] = disp_model
# Set the new model as the dispersion object
# for the selected parameter
try:
self.model.set_dispersion(p, disp_model)
except:
pass
## save state into
self.save_current_state()
self.Layout()
self.Refresh()
def _on_select_Disp(self, event):
"""
allow selecting different dispersion
self.disp_list should change type later .now only gaussian
"""
self._set_sizer_dispersion()
## Redraw the model
self._draw_model()
#self._undo.Enable(True)
event = PageInfoEvent(page=self)
wx.PostEvent(self.parent, event)
self.sizer4_4.Layout()
self.sizer4.Layout()
self.SetupScrolling()
def _on_disp_func(self, event=None):
"""
Select a distribution function for the polydispersion
:Param event: ComboBox event
"""
# get ready for new event
if event != None:
event.Skip()
# Get event object
disp_box = event.GetEventObject()
# Try to select a Distr. function
try:
disp_box.SetBackgroundColour("white")
selection = disp_box.GetCurrentSelection()
param_name = disp_box.Name.split('.')[0]
disp_name = disp_box.GetValue()
dispersity = disp_box.GetClientData(selection)
#disp_model = GaussianDispersion()
disp_model = dispersity()
# Get param names to reset the values of the param
name1 = param_name + ".width"
name2 = param_name + ".npts"
name3 = param_name + ".nsigmas"
# Check Disp. function whether or not it is 'array'
if disp_name.lower() == "array":
value2 = ""
value3 = ""
value1 = self._set_array_disp(name=name1, disp=disp_model)
else:
self._del_array_values(name1)
#self._reset_array_disp(param_name)
self._disp_obj_dict[name1] = disp_model
self.model.set_dispersion(param_name, disp_model)
self.state._disp_obj_dict[name1] = disp_model
value1 = str(format_number(self.model.getParam(name1), True))
value2 = str(format_number(self.model.getParam(name2)))
value3 = str(format_number(self.model.getParam(name3)))
# Reset fittable polydispersin parameter value
for item in self.fittable_param:
if item[1] == name1:
item[2].SetValue(value1)
item[5].SetValue("")
item[6].SetValue("")
# Disable for array
if disp_name.lower() == "array":
item[0].SetValue(False)
item[0].Disable()
item[2].Disable()
item[3].Show(False)
item[4].Show(False)
item[5].Disable()
item[6].Disable()
else:
item[0].Enable()
item[2].Enable()
item[5].Enable()
item[6].Enable()
break
# Reset fixed polydispersion params
for item in self.fixed_param:
if item[1] == name2:
item[2].SetValue(value2)
# Disable Npts for array
if disp_name.lower() == "array":
item[2].Disable()
else:
item[2].Enable()
if item[1] == name3:
item[2].SetValue(value3)
# Disable Nsigs for array
if disp_name.lower() == "array":
item[2].Disable()
else:
item[2].Enable()
# Make sure the check box updated when all checked
if self.cb1.GetValue():
#self.select_all_param(None)
self.get_all_checked_params()
# update params
self._update_paramv_on_fit()
# draw
self._draw_model()
self.Refresh()
except:
# Error msg
msg = "Error occurred:"
msg += " Could not select the distribution function..."
msg += " Please select another distribution function."
disp_box.SetBackgroundColour("pink")
# Focus on Fit button so that users can see the pinky box
self.btFit.SetFocus()
wx.PostEvent(self._manager.parent,
StatusEvent(status=msg, info="error"))
def _set_array_disp(self, name=None, disp=None):
"""
Set array dispersion
:param name: name of the parameter for the dispersion to be set
:param disp: the polydisperion object
"""
# The user wants this parameter to be averaged.
# Pop up the file selection dialog.
path = self._selectDlg()
# Array data
values = []
weights = []
# If nothing was selected, just return
if path is None:
self.disp_cb_dict[name].SetValue(False)
#self.noDisper_rbox.SetValue(True)
return
self._default_save_location = os.path.dirname(path)
if self._manager != None:
self._manager.parent._default_save_location =\
self._default_save_location
basename = os.path.basename(path)
values, weights = self.read_file(path)
# If any of the two arrays is empty, notify the user that we won't
# proceed
if len(self.param_toFit) > 0:
if name in self.param_toFit:
self.param_toFit.remove(name)
# Tell the user that we are about to apply the distribution
msg = "Applying loaded %s distribution: %s" % (name, path)
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
self._set_array_disp_model(name=name, disp=disp,
values=values, weights=weights)
return basename
def _set_array_disp_model(self, name=None, disp=None,
values=[], weights=[]):
"""
Set array dispersion model
:param name: name of the parameter for the dispersion to be set
:param disp: the polydisperion object
"""
disp.set_weights(values, weights)
self._disp_obj_dict[name] = disp
self.model.set_dispersion(name.split('.')[0], disp)
self.state._disp_obj_dict[name] = disp
self.values[name] = values
self.weights[name] = weights
# Store the object to make it persist outside the
# scope of this method
#TODO: refactor model to clean this up?
self.state.values = {}
self.state.weights = {}
self.state.values = copy.deepcopy(self.values)
self.state.weights = copy.deepcopy(self.weights)
# Set the new model as the dispersion object for the
#selected parameter
#self.model.set_dispersion(p, disp_model)
# Store a reference to the weights in the model object
#so that
# it's not lost when we use the model within another thread.
self.state.model = self.model.clone()
self.model._persistency_dict[name.split('.')[0]] = \
[values, weights]
self.state.model._persistency_dict[name.split('.')[0]] = \
[values, weights]
def _del_array_values(self, name=None):
"""
Reset array dispersion
:param name: name of the parameter for the dispersion to be set
"""
# Try to delete values and weight of the names array dic if exists
try:
del self.values[name]
del self.weights[name]
# delete all other dic
del self.state.values[name]
del self.state.weights[name]
del self.model._persistency_dict[name.split('.')[0]]
del self.state.model._persistency_dict[name.split('.')[0]]
except:
pass
def _lay_out(self):
"""
returns self.Layout
:Note: Mac seems to like this better when self.
Layout is called after fitting.
"""
self._sleep4sec()
self.Layout()
return
def _sleep4sec(self):
"""
sleep for 1 sec only applied on Mac
Note: This 1sec helps for Mac not to crash on self.
Layout after self._draw_model
"""
if ON_MAC == True:
time.sleep(1)
def _find_polyfunc_selection(self, disp_func=None):
"""
FInd Comboox selection from disp_func
:param disp_function: dispersion distr. function
"""
# List of the poly_model name in the combobox
list = ["RectangleDispersion", "ArrayDispersion",
"LogNormalDispersion", "GaussianDispersion",
"SchulzDispersion"]
# Find the selection
try:
selection = list.index(disp_func.__class__.__name__)
return selection
except:
return 3
[docs] def on_reset_clicked(self, event):
"""
On 'Reset' button for Q range clicked
"""
flag = True
##For 3 different cases: Data2D, Data1D, and theory
if self.model == None:
msg = "Please select a model first..."
wx.MessageBox(msg, 'Info')
flag = False
return
elif self.data.__class__.__name__ == "Data2D":
data_min = 0
x = max(math.fabs(self.data.xmin), math.fabs(self.data.xmax))
y = max(math.fabs(self.data.ymin), math.fabs(self.data.ymax))
self.qmin_x = data_min
self.qmax_x = math.sqrt(x*x + y*y)
#self.data.mask = numpy.ones(len(self.data.data),dtype=bool)
# check smearing
if not self.disable_smearer.GetValue():
## set smearing value whether or
# not the data contain the smearing info
if self.pinhole_smearer.GetValue():
flag = self.update_pinhole_smear()
else:
flag = True
elif self.data == None:
self.qmin_x = _QMIN_DEFAULT
self.qmax_x = _QMAX_DEFAULT
self.num_points = _NPTS_DEFAULT
self.state.npts = self.num_points
elif self.data.__class__.__name__ != "Data2D":
self.qmin_x = min(self.data.x)
self.qmax_x = max(self.data.x)
# check smearing
if not self.disable_smearer.GetValue():
## set smearing value whether or
# not the data contain the smearing info
if self.slit_smearer.GetValue():
flag = self.update_slit_smear()
elif self.pinhole_smearer.GetValue():
flag = self.update_pinhole_smear()
else:
flag = True
else:
flag = False
if flag == False:
msg = "Cannot Plot :Must enter a number!!! "
wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
else:
# set relative text ctrs.
self.qmin.SetValue(str(self.qmin_x))
self.qmax.SetValue(str(self.qmax_x))
self.show_npts2fit()
# At this point, some button and variables satatus (disabled?)
# should be checked such as color that should be reset to
# white in case that it was pink.
self._onparamEnter_helper()
self.save_current_state()
self.state.qmin = self.qmin_x
self.state.qmax = self.qmax_x
#reset the q range values
self._reset_plotting_range(self.state)
self._draw_model()
[docs] def select_log(self, event):
"""
Log checked to generate log spaced points for theory model
"""
[docs] def get_images(self):
"""
Get the images of the plots corresponding this panel for report
: return graphs: list of figures
: Need Move to guiframe
"""
# set list of graphs
graphs = []
canvases = []
res_item = None
# call gui_manager
gui_manager = self._manager.parent
# loops through the panels [dic]
for _, item2 in gui_manager.plot_panels.iteritems():
data_title = self.data.group_id
# try to get all plots belonging to this control panel
try:
g_id = item2.group_id
if g_id == data_title or \
str(g_id).count("res" + str(self.graph_id)) or \
str(g_id).count(str(self.uid)) > 0:
if str(g_id).count("res" + str(self.graph_id)) > 0:
res_item = [item2.figure, item2.canvas]
else:
# append to the list
graphs.append(item2.figure)
canvases.append(item2.canvas)
except:
# Not for control panels
pass
# Make sure the resduals plot goes to the last
if res_item != None:
graphs.append(res_item[0])
canvases.append(res_item[1])
# return the list of graphs
return graphs, canvases
[docs] def on_model_help_clicked(self, event):
"""
on 'More details' button
"""
from sas.perspectives.fitting.help_panel import HelpWindow
from sas.models import get_data_path
# Get models help model_function path
path = get_data_path(media='media')
model_path = os.path.join(path, "model_functions.html")
if self.model == None:
name = 'FuncHelp'
else:
name = self.formfactorbox.GetValue()
frame = HelpWindow(None, -1, pageToOpen=model_path)
# If model name exists and model is not a custom model
#mod_cat = self.categorybox.GetStringSelection()
if frame.rhelp.HasAnchor(name):
frame.Show(True)
frame.rhelp.ScrollToAnchor(name)
else:
if self.model != None:
frame.Destroy()
msg = 'Model description:\n'
if str(self.model.description).rstrip().lstrip() == '':
msg += "Sorry, no information is available for this model."
else:
msg += self.model.description + '\n'
info = "Info"
wx.MessageBox(msg, info)
else:
frame.Show(True)
def _on_mag_help(self, event):
"""
Magnetic angles help panel
"""
from sas.perspectives.fitting.help_panel import HelpWindow
# Get models help model_function path
#import sas.perspectives.fitting as fitmedia
from sas.models import get_data_path
media = get_data_path(media='media')
path = os.path.join(media, "mag_pic.html")
name = "Polar/Magnetic Angles"
frame = HelpWindow(None, -1,
title=' Help: Polarization/Magnetization Angles',
pageToOpen=path, size=(865, 450))
try:
frame.splitter.DetachWindow(frame.lpanel)
# Display only the right side one
frame.lpanel.Hide()
frame.Show(True)
except:
frame.Destroy()
msg = 'Display Error\n'
info = "Info"
wx.MessageBox(msg, info)
def _on_mag_on(self, event):
"""
Magnetic Parameters ON/OFF
"""
button = event.GetEventObject()
if button.GetLabel().count('ON') > 0:
self.magnetic_on = True
button.SetLabel("Magnetic OFF")
m_value = 1.0e-06
for key in self.model.magnetic_params:
if key.count('M0') > 0:
self.model.setParam(key, m_value)
m_value += 0.5e-06
else:
self.magnetic_on = False
button.SetLabel("Magnetic ON")
for key in self.model.magnetic_params:
if key.count('M0') > 0:
#reset mag value to zero fo safety
self.model.setParam(key, 0.0)
self.Show(False)
self.set_model_param_sizer(self.model)
#self._set_sizer_dispersion()
self.state.magnetic_on = self.magnetic_on
self.SetupScrolling()
self.Show(True)
[docs] def on_pd_help_clicked(self, event):
"""
Button event for PD help
"""
from help_panel import HelpWindow
import sas.models as models
# Get models help model_function path
path = models.get_data_path(media='media')
pd_path = os.path.join(path, "pd_help.html")
frame = HelpWindow(None, -1, pageToOpen=pd_path)
frame.Show(True)
[docs] def on_left_down(self, event):
"""
Get key stroke event
"""
# Figuring out key combo: Cmd for copy, Alt for paste
if event.CmdDown() and event.ShiftDown():
self.get_paste()
elif event.CmdDown():
self.get_copy()
else:
event.Skip()
return
# make event free
event.Skip()
[docs] def get_copy(self):
"""
Get copy params to clipboard
"""
content = self.get_copy_params()
flag = self.set_clipboard(content)
self._copy_info(flag)
return flag
[docs] def get_copy_params(self):
"""
Get the string copies of the param names and values in the tap
"""
content = 'sasview_parameter_values:'
# Do it if params exist
if self.parameters != []:
# go through the parameters
strings = self._get_copy_helper(self.parameters,
self.orientation_params)
content += strings
# go through the fittables
strings = self._get_copy_helper(self.fittable_param,
self.orientation_params_disp)
content += strings
# go through the fixed params
strings = self._get_copy_helper(self.fixed_param,
self.orientation_params_disp)
content += strings
# go through the str params
strings = self._get_copy_helper(self.str_parameters,
self.orientation_params)
content += strings
return content
else:
return False
[docs] def get_copy_excel(self):
"""
Get copy params to clipboard
"""
content = self.get_copy_params_excel()
flag = self.set_clipboard(content)
self._copy_info(flag)
return flag
[docs] def get_copy_params_excel(self):
"""
Get the string copies of the param names and values in the tap
"""
content = ''
crlf = chr(13) + chr(10)
tab = chr(9)
# Do it if params exist
if self.parameters != []:
for param in self.parameters:
content += param[1] #parameter name
content += tab
content += param[1]+"_err"
content += tab
content += crlf
#row of values and errors...
for param in self.parameters:
content += param[2].GetValue() #value
content +=tab
content += param[4].GetValue() #error
content +=tab
return content
else:
return False
[docs] def get_copy_latex(self):
"""
Get copy params to clipboard
"""
content = self.get_copy_params_latex()
flag = self.set_clipboard(content)
self._copy_info(flag)
return flag
[docs] def get_copy_params_latex(self):
"""
Get the string copies of the param names and values in the tap
"""
content = '\\begin{table}'
content += '\\begin{tabular}[h]'
crlf = chr(13) + chr(10)
tab = chr(9)
# Do it if params exist
if self.parameters != []:
content += '{|'
for param in self.parameters:
content += 'l|l|'
content += '}\hline'
content += crlf
for index, param in enumerate(self.parameters):
content += param[1].replace('_','\_') #parameter name
content += ' & '
content += param[1].replace('_','\_')+"\_err"
if index < len(self.parameters)-1:
content += ' & '
content += '\\\\ \\hline'
content += crlf
#row of values and errors...
for index, param in enumerate(self.parameters):
content += param[2].GetValue() #parameter value
content += ' & '
content += param[4].GetValue() #parameter error
if index < len(self.parameters)-1:
content += ' & '
content += '\\\\ \\hline'
content += crlf
content += '\\end{tabular}'
content += '\\end{table}'
return content
else:
return False
[docs] def set_clipboard(self, content=None):
"""
Put the string to the clipboard
"""
if not content:
return False
if wx.TheClipboard.Open():
wx.TheClipboard.SetData(wx.TextDataObject(str(content)))
wx.TheClipboard.Close()
return True
return None
def _get_copy_helper(self, param, orient_param):
"""
Helping get value and name of the params
: param param: parameters
: param orient_param = oritational params
: return content: strings [list] [name,value:....]
"""
content = ''
# go through the str params
for item in param:
# copy only the params shown
if not item[2].IsShown():
continue
disfunc = ''
try:
if item[7].__class__.__name__ == 'ComboBox':
disfunc = str(item[7].GetValue())
except:
pass
# 2D
if self.data.__class__.__name__ == "Data2D":
try:
check = item[0].GetValue()
except:
check = None
name = item[1]
value = item[2].GetValue()
# 1D
else:
## for 1D all parameters except orientation
if not item[1] in orient_param:
try:
check = item[0].GetValue()
except:
check = None
name = item[1]
value = item[2].GetValue()
# add to the content
if disfunc != '':
disfunc = ',' + disfunc
# Need to support array func for copy/paste
try:
if disfunc.count('array') > 0:
disfunc += ','
for val in self.values[name]:
disfunc += ' ' + str(val)
disfunc += ','
for weight in self.weights[name]:
disfunc += ' ' + str(weight)
except:
pass
content += name + ',' + str(check) + ',' + value + disfunc + ':'
return content
[docs] def get_clipboard(self):
"""
Get strings in the clipboard
"""
text = ""
# Get text from the clip board
if wx.TheClipboard.Open():
if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
data = wx.TextDataObject()
# get wx dataobject
success = wx.TheClipboard.GetData(data)
# get text
if success:
text = data.GetText()
else:
text = ''
# close clipboard
wx.TheClipboard.Close()
return text
[docs] def get_paste(self):
"""
Paste params from the clipboard
"""
text = self.get_clipboard()
flag = self.get_paste_params(text)
self._copy_info(flag)
return flag
[docs] def get_paste_params(self, text=''):
"""
Get the string copies of the param names and values in the tap
"""
context = {}
# put the text into dictionary
lines = text.split(':')
if lines[0] != 'sasview_parameter_values':
self._copy_info(False)
return False
for line in lines[1:-1]:
if len(line) != 0:
item = line.split(',')
check = item[1]
name = item[0]
value = item[2]
# Transfer the text to content[dictionary]
context[name] = [check, value]
# ToDo: PlugIn this poly disp function for pasting
try:
poly_func = item[3]
context[name].append(poly_func)
try:
# take the vals and weights for array
array_values = item[4].split(' ')
array_weights = item[5].split(' ')
val = [float(a_val) for a_val in array_values[1:]]
weit = [float(a_weit) for a_weit in array_weights[1:]]
context[name].append(val)
context[name].append(weit)
except:
raise
except:
poly_func = ''
context[name].append(poly_func)
# Do it if params exist
if self.parameters != []:
# go through the parameters
self._get_paste_helper(self.parameters,
self.orientation_params, context)
# go through the fittables
self._get_paste_helper(self.fittable_param,
self.orientation_params_disp,
context)
# go through the fixed params
self._get_paste_helper(self.fixed_param,
self.orientation_params_disp, context)
# go through the str params
self._get_paste_helper(self.str_parameters,
self.orientation_params, context)
return True
return None
def _get_paste_helper(self, param, orient_param, content):
"""
Helping set values of the params
: param param: parameters
: param orient_param: oritational params
: param content: dictionary [ name, value: name1.value1,...]
"""
# go through the str params
for item in param:
# 2D
if self.data.__class__.__name__ == "Data2D":
name = item[1]
if name in content.keys():
check = content[name][0]
pd = content[name][1]
if name.count('.') > 0:
try:
float(pd)
except:
#continue
if not pd and pd != '':
continue
item[2].SetValue(str(pd))
if item in self.fixed_param and pd == '':
# Only array func has pd == '' case.
item[2].Enable(False)
if item[2].__class__.__name__ == "ComboBox":
if content[name][1] in self.model.fun_list:
fun_val = self.model.fun_list[content[name][1]]
self.model.setParam(name, fun_val)
value = content[name][1:]
self._paste_poly_help(item, value)
if check == 'True':
is_true = True
elif check == 'False':
is_true = False
else:
is_true = None
if is_true != None:
item[0].SetValue(is_true)
# 1D
else:
## for 1D all parameters except orientation
if not item[1] in orient_param:
name = item[1]
if name in content.keys():
check = content[name][0]
# Avoid changing combox content
value = content[name][1:]
pd = value[0]
if name.count('.') > 0:
try:
pd = float(pd)
except:
#continue
if not pd and pd != '':
continue
item[2].SetValue(str(pd))
if item in self.fixed_param and pd == '':
# Only array func has pd == '' case.
item[2].Enable(False)
if item[2].__class__.__name__ == "ComboBox":
if value[0] in self.model.fun_list:
fun_val = self.model.fun_list[value[0]]
self.model.setParam(name, fun_val)
# save state
self._paste_poly_help(item, value)
if check == 'True':
is_true = True
elif check == 'False':
is_true = False
else:
is_true = None
if is_true != None:
item[0].SetValue(is_true)
def _paste_poly_help(self, item, value):
"""
Helps get paste for poly function
:param item: Gui param items
:param value: the values for parameter ctrols
"""
is_array = False
if len(value[1]) > 0:
# Only for dispersion func.s
try:
item[7].SetValue(value[1])
selection = item[7].GetCurrentSelection()
name = item[7].Name
param_name = name.split('.')[0]
dispersity = item[7].GetClientData(selection)
disp_model = dispersity()
# Only for array disp
try:
pd_vals = numpy.array(value[2])
pd_weights = numpy.array(value[3])
if len(pd_vals) > 0 and len(pd_vals) > 0:
if len(pd_vals) == len(pd_weights):
self._set_disp_array_cb(item=item)
self._set_array_disp_model(name=name,
disp=disp_model,
values=pd_vals,
weights=pd_weights)
is_array = True
except:
pass
if not is_array:
self._disp_obj_dict[name] = disp_model
self.model.set_dispersion(name,
disp_model)
self.state._disp_obj_dict[name] = \
disp_model
self.model.set_dispersion(param_name, disp_model)
self.state.values = self.values
self.state.weights = self.weights
self.model._persistency_dict[param_name] = \
[self.state.values,
self.state.weights]
except:
print "Error in BasePage._paste_poly_help: %s" % sys.exc_value
def _set_disp_array_cb(self, item):
"""
Set cb for array disp
"""
item[0].SetValue(False)
item[0].Enable(False)
item[2].Enable(False)
item[3].Show(False)
item[4].Show(False)
item[5].SetValue('')
item[5].Enable(False)
item[6].SetValue('')
item[6].Enable(False)
[docs] def update_pinhole_smear(self):
"""
Method to be called by sub-classes
Moveit; This method doesn't belong here
"""
print "BasicPage.update_pinhole_smear was called: skipping"
return
def _read_category_info(self):
"""
Reads the categories in from file
"""
# # ILL mod starts here - July 2012 kieranrcampbell@gmail.com
self.master_category_dict = defaultdict(list)
self.by_model_dict = defaultdict(list)
self.model_enabled_dict = defaultdict(bool)
try:
categorization_file = CategoryInstaller.get_user_file()
if not os.path.isfile(categorization_file):
categorization_file = CategoryInstaller.get_default_file()
cat_file = open(categorization_file, 'rb')
self.master_category_dict = json.load(cat_file)
self._regenerate_model_dict()
cat_file.close()
except IOError:
raise
print 'Problem reading in category file.'
print 'We even looked for it, made sure it was there.'
print 'An existential crisis if there ever was one.'
def _regenerate_model_dict(self):
"""
regenerates self.by_model_dict which has each model name as the
key and the list of categories belonging to that model
along with the enabled mapping
"""
self.by_model_dict = defaultdict(list)
for category in self.master_category_dict:
for (model, enabled) in self.master_category_dict[category]:
self.by_model_dict[model].append(category)
self.model_enabled_dict[model] = enabled
def _populate_listbox(self):
"""
fills out the category list box
"""
uncat_str = 'Customized Models'
self._read_category_info()
self.categorybox.Clear()
cat_list = sorted(self.master_category_dict.keys())
if not uncat_str in cat_list:
cat_list.append(uncat_str)
for category in cat_list:
if category != '':
self.categorybox.Append(category)
if self.categorybox.GetSelection() == wx.NOT_FOUND:
self.categorybox.SetSelection(0)
else:
self.categorybox.SetSelection( \
self.categorybox.GetSelection())
#self._on_change_cat(None)
def _on_change_cat(self, event):
"""
Callback for category change action
"""
self.model_name = None
category = self.categorybox.GetStringSelection()
if category == None:
return
self.model_box.Clear()
if category == 'Customized Models':
for model in self.model_list_box[category]:
str_m = str(model).split(".")[0]
self.model_box.Append(str_m)
else:
for (model,enabled) in sorted(self.master_category_dict[category],
key = lambda name: name[0]):
if(enabled):
self.model_box.Append(model)
def _fill_model_sizer(self, sizer):
"""
fill sizer containing model info
"""
##Add model function Details button in fitpanel.
##The following 3 lines are for Mac. Let JHC know before modifying...
title = "Model"
self.formfactorbox = None
self.multifactorbox = None
self.mbox_description = wx.StaticBox(self, -1, str(title))
boxsizer1 = wx.StaticBoxSizer(self.mbox_description, wx.VERTICAL)
sizer_cat = wx.BoxSizer(wx.HORIZONTAL)
self.mbox_description.SetForegroundColour(wx.RED)
id = wx.NewId()
self.model_help = wx.Button(self, id, 'Details', size=(80, 23))
self.model_help.Bind(wx.EVT_BUTTON, self.on_model_help_clicked, id=id)
self.model_help.SetToolTipString("Model Function Help")
id = wx.NewId()
self.model_view = wx.Button(self, id, "Show 2D", size=(80, 23))
self.model_view.Bind(wx.EVT_BUTTON, self._onModel2D, id=id)
hint = "toggle view of model from 1D to 2D or 2D to 1D"
self.model_view.SetToolTipString(hint)
cat_set_box = wx.StaticBox(self, -1, 'Category')
sizer_cat_box = wx.StaticBoxSizer(cat_set_box, wx.HORIZONTAL)
sizer_cat_box.SetMinSize((200, 50))
self.categorybox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
self.categorybox.SetToolTip( wx.ToolTip("Select a Category/Type") )
self._populate_listbox()
wx.EVT_COMBOBOX(self.categorybox, -1, self._show_combox)
#self.shape_rbutton = wx.RadioButton(self, -1, 'Shapes',
# style=wx.RB_GROUP)
#self.shape_indep_rbutton = wx.RadioButton(self, -1,
# "Shape-Independent")
#self.struct_rbutton = wx.RadioButton(self, -1, "Structure Factor ")
#self.plugin_rbutton = wx.RadioButton(self, -1, "Uncategorized")
#self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
# id=self.shape_rbutton.GetId())
#self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
# id=self.shape_indep_rbutton.GetId())
#self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
# id=self.struct_rbutton.GetId())
#self.Bind(wx.EVT_RADIOBUTTON, self._show_combox,
# id=self.plugin_rbutton.GetId())
#MAC needs SetValue
show_cat_button = wx.Button(self, -1, "Modify")
cat_tip = "Modify model categories \n"
cat_tip += "(also accessible from the menu bar)."
show_cat_button.SetToolTip( wx.ToolTip(cat_tip) )
show_cat_button.Bind(wx.EVT_BUTTON, self._on_modify_cat)
sizer_cat_box.Add(self.categorybox, 1, wx.RIGHT, 3)
sizer_cat_box.Add((10,10))
sizer_cat_box.Add(show_cat_button)
#self.shape_rbutton.SetValue(True)
sizer_radiobutton = wx.GridSizer(2, 2, 5, 5)
#sizer_radiobutton.Add(self.shape_rbutton)
#sizer_radiobutton.Add(self.shape_indep_rbutton)
sizer_radiobutton.Add((5,5))
sizer_radiobutton.Add(self.model_view, 1, wx.RIGHT, 15)
#sizer_radiobutton.Add(self.plugin_rbutton)
#sizer_radiobutton.Add(self.struct_rbutton)
sizer_radiobutton.Add((5,5))
sizer_radiobutton.Add(self.model_help, 1, wx.RIGHT, 15)
sizer_cat.Add(sizer_cat_box, 1, wx.LEFT, 2.5)
sizer_cat.Add(sizer_radiobutton)
sizer_selection = wx.BoxSizer(wx.HORIZONTAL)
mutifactor_selection = wx.BoxSizer(wx.HORIZONTAL)
self.text1 = wx.StaticText(self, -1, "")
self.text2 = wx.StaticText(self, -1, "P(Q)*S(Q)")
self.mutifactor_text = wx.StaticText(self, -1, "No. of Shells: ")
self.mutifactor_text1 = wx.StaticText(self, -1, "")
self.show_sld_button = wx.Button(self, -1, "Show SLD Profile")
self.show_sld_button.Bind(wx.EVT_BUTTON, self._on_show_sld)
self.formfactorbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
self.formfactorbox.SetToolTip( wx.ToolTip("Select a Model") )
if self.model != None:
self.formfactorbox.SetValue(self.model.name)
self.structurebox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
self.multifactorbox = wx.ComboBox(self, -1, style=wx.CB_READONLY)
self.initialize_combox()
wx.EVT_COMBOBOX(self.formfactorbox, -1, self._on_select_model)
wx.EVT_COMBOBOX(self.structurebox, -1, self._on_select_model)
wx.EVT_COMBOBOX(self.multifactorbox, -1, self._on_select_model)
## check model type to show sizer
if self.model != None:
print "_set_model_sizer_selection: disabled."
#self._set_model_sizer_selection(self.model)
sizer_selection.Add(self.text1)
sizer_selection.Add((10, 5))
sizer_selection.Add(self.formfactorbox)
sizer_selection.Add((5, 5))
sizer_selection.Add(self.text2)
sizer_selection.Add((5, 5))
sizer_selection.Add(self.structurebox)
mutifactor_selection.Add((13, 5))
mutifactor_selection.Add(self.mutifactor_text)
mutifactor_selection.Add(self.multifactorbox)
mutifactor_selection.Add((5, 5))
mutifactor_selection.Add(self.mutifactor_text1)
mutifactor_selection.Add((10, 5))
mutifactor_selection.Add(self.show_sld_button)
boxsizer1.Add(sizer_cat)
boxsizer1.Add((10, 10))
boxsizer1.Add(sizer_selection)
boxsizer1.Add((10, 10))
boxsizer1.Add(mutifactor_selection)
self._set_multfactor_combobox()
self.multifactorbox.SetSelection(1)
self.show_sld_button.Hide()
sizer.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
sizer.Layout()
[docs] def on_smear_helper(self, update=False):
"""
Help for onSmear if implemented
:param update: force or not to update
"""
[docs] def reset_page(self, state, first=False):
"""
reset the state if implemented
"""
[docs] def onSmear(self, event):
"""
Create a smear object if implemented
"""
[docs] def onPinholeSmear(self, event):
"""
Create a custom pinhole smear object if implemented
"""
[docs] def onSlitSmear(self, event):
"""
Create a custom slit smear object if implemented
"""
[docs] def update_slit_smear(self):
"""
called by kill_focus on pinhole TextCntrl
to update the changes if implemented
"""
[docs] def select_param(self, event):
"""
Select TextCtrl checked if implemented
"""
[docs] def set_data(self, data=None):
"""
Sets data if implemented
"""
def _is_2D(self):
"""
Check if data_name is Data2D if implemented
"""
def _on_select_model(self, event=None):
"""
call back for model selection if implemented
"""
[docs] def select_all_param(self, event):
"""
set to true or false all checkBox if implemented
"""
[docs] def get_weight_flag(self):
"""
Get flag corresponding to a given weighting dI data if implemented
"""
def _set_sizer_dispersion(self):
"""
draw sizer for dispersity if implemented
"""
[docs] def get_all_checked_params(self):
"""
Found all parameters current check and add them to list of parameters
to fit if implemented
"""
[docs] def show_npts2fit(self):
"""
setValue Npts for fitting if implemented
"""
def _onModel2D(self, event):
"""
toggle view of model from 1D to 2D or 2D from 1D if implemented
"""