""" Generic Scattering panel. This module relies on guiframe manager. """ import wx import sys import os import numpy #import math import wx.aui as aui #import wx.lib.agw.aui as aui import logging import time import matplotlib matplotlib.interactive(False) #Use the WxAgg back end. The Wx one takes too long to render matplotlib.use('WXAgg') #from sas.guiframe.gui_manager import MDIFrame from sas.data_util.calcthread import CalcThread from sas.guiframe.local_perspectives.plotting.SimplePlot import PlotFrame from sas.guiframe.dataFitting import Data2D from sas.guiframe.dataFitting import Data1D from sas.dataloader.data_info import Detector from sas.dataloader.data_info import Source from sas.guiframe.panel_base import PanelBase from sas.guiframe.utils import format_number from sas.guiframe.events import StatusEvent from sas.calculator import sans_gen from sas.perspectives.calculator.calculator_widgets import OutputTextCtrl from sas.perspectives.calculator.calculator_widgets import InputTextCtrl from wx.lib.scrolledpanel import ScrolledPanel from sas.perspectives.calculator.load_thread import GenReader from sas.plottools.arrow3d import Arrow3D from sas.perspectives.calculator import calculator_widgets as widget from sas.guiframe.events import NewPlotEvent _BOX_WIDTH = 76 #Slit length panel size if sys.platform.count("win32") > 0: PANEL_WIDTH = 570 PANEL_HEIGHT = 370 FONT_VARIANT = 0 else: PANEL_WIDTH = 620 PANEL_HEIGHT = 370 FONT_VARIANT = 1 _QMAX_DEFAULT = 0.3 _NPTS_DEFAULT = 50 _Q1D_MIN = 0.001 def add_icon(parent, frame): """ Add icon in the frame """ if parent != None: if hasattr(frame, "IsIconized"): if not frame.IsIconized(): try: icon = parent.GetIcon() frame.SetIcon(icon) except: pass def _set_error(panel, item, show_msg=False): """ Set_error dialog """ if item != None: item.SetBackgroundColour("pink") item.Refresh() if show_msg: msg = "Error: wrong (or out of range) value entered." if panel.parent.parent != None: wx.PostEvent(panel.parent.parent, StatusEvent(status=msg, info='Error' )) panel.SetFocus() return False class CalcGen(CalcThread): """ Computation """ def __init__(self, id=-1, input = None, completefn = None, updatefn = None, #elapsed = 0, yieldtime = 0.01, worktime = 0.01): """ """ CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime) self.starttime = 0 self.id = id self.input = input self.update_fn = updatefn def compute(self): """ excuting computation """ #elapsed = time.time() - self.starttime self.starttime = time.time() self.complete(input=self.input, update=self.update_fn) class SasGenPanel(ScrolledPanel, PanelBase): """ Provides the sas gen calculator GUI. """ ## Internal nickname for the window, used by the AUI manager window_name = "Generic SANS Calculator" ## Name to appear on the window title bar window_caption = "Generic SANS " ## Flag to tell the AUI manager to put this panel in the center pane CENTER_PANE = True def __init__(self, parent, *args, **kwds): ScrolledPanel.__init__(self, parent, style=wx.RAISED_BORDER, *args, **kwds) #kwds['style'] = wx.SUNKEN_BORDER PanelBase.__init__(self) #Font size self.SetWindowVariant(variant=FONT_VARIANT) self.SetupScrolling() #thread to read data self.reader = None self.ext = None self.id = 'GenSANS' self.file_name = '' self.time_text = None self.orient_combo = None self.omfreader = sans_gen.OMFReader() self.sldreader = sans_gen.SLDReader() self.pdbreader = sans_gen.PDBReader() self.model = sans_gen.GenSAS() self.param_dic = self.model.params self.parameters = [] self.data = None self.scale2d = None self.is_avg = False self.plot_frame = None self.qmax_x = _QMAX_DEFAULT self.npts_x = _NPTS_DEFAULT self.sld_data = None self.graph_num = 1 self.default_shape = 'rectangular' # Object that receive status event self.parent = parent self._do_layout() self._create_default_sld_data() self._create_default_2d_data() wx.CallAfter(self._set_sld_data_helper) def _define_structure(self): """ Define the main sizers building to build this application. """ self.main_sizer = wx.BoxSizer(wx.VERTICAL) self.box_source = wx.StaticBox(self, -1, str("SLD Data File")) self.box_parameters = wx.StaticBox(self, -1, str("Input Parameters")) self.box_qrange = wx.StaticBox(self, -1, str("Q Range")) self.boxsizer_source = wx.StaticBoxSizer(self.box_source, wx.VERTICAL) self.boxsizer_parameters = wx.StaticBoxSizer(self.box_parameters, wx.VERTICAL) self.boxsizer_qrange = wx.StaticBoxSizer(self.box_qrange, wx.VERTICAL) self.data_name_sizer = wx.BoxSizer(wx.HORIZONTAL) self.param_sizer = wx.BoxSizer(wx.HORIZONTAL) self.shape_sizer = wx.BoxSizer(wx.HORIZONTAL) self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL) self.qrange_sizer = wx.BoxSizer(wx.HORIZONTAL) self.button_sizer = wx.BoxSizer(wx.HORIZONTAL) def _layout_data_name(self): """ Fill the sizer containing data's name """ data_name_txt = wx.StaticText(self, -1, 'Data: ') self.data_name_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH * 4, -1)) data_hint = "Loaded data" self.data_name_tcl.SetToolTipString(data_hint) #control that triggers importing data id = wx.NewId() self.browse_button = wx.Button(self, id, "Load") hint_on_browse = "Click on this button to load a data in this panel." #self.browse_button.SetToolTipString(hint_on_browse) self.Bind(wx.EVT_BUTTON, self.on_load_data, id=id) self.data_name_sizer.AddMany([(data_name_txt, 0, wx.LEFT, 15), (self.data_name_tcl, 0, wx.LEFT, 10), (self.browse_button, 0, wx.LEFT, 10)]) def _layout_param_size(self): """ Fill the sizer containing slit size information """ self.parameters = [] sizer = wx.GridBagSizer(3, 6) model = self.model details = self.model.details params = self.model.params ix = 0 iy = 0 param_title = wx.StaticText(self, -1, 'Parameter') sizer.Add(param_title, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) ix += 1 value_title = wx.StaticText(self, -1, 'Value') sizer.Add(value_title, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) ix += 1 unit_title = wx.StaticText(self, -1, 'Unit') sizer.Add(unit_title, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) key_list = params.keys() key_list.sort() for param in key_list: iy += 1 ix = 0 p_name = wx.StaticText(self, -1, param) sizer.Add(p_name, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) ## add parameter value ix += 1 value = model.getParam(param) ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 2, 20), style=wx.TE_PROCESS_ENTER) #ctl.SetToolTipString(\ # "Hit 'Enter' after typing to update the plot.") ctl.SetValue(format_number(value, True)) sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND) ## add unit ix += 1 unit = wx.StaticText(self, -1, details[param][0]) sizer.Add(unit, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) self.parameters.append([p_name, ctl, unit]) self.param_sizer.Add(sizer, 0, wx.LEFT, 10) def _layout_hint(self): """ Fill the sizer containing hint """ hint_msg = "We support omf, sld or pdb data files only." hint_msg += " " if FONT_VARIANT < 1: hint_msg += "Very " hint_msg += "SLOW drawing -->" hint_txt = wx.StaticText(self, -1, hint_msg) id = wx.NewId() self.draw_button = wx.Button(self, id, "Arrow Draw") hint_on_draw = "Draw with arrows. Caution: it is a very slow drawing." self.draw_button.SetToolTipString(hint_on_draw) self.draw_button.Bind(wx.EVT_BUTTON, self.sld_draw, id=id) self.draw_button.Enable(False) self.hint_sizer.AddMany([(hint_txt, 0, wx.LEFT, 15), (self.draw_button, 0, wx.LEFT, 7)]) def _layout_shape(self): """ Fill the shape sizer """ label_txt = wx.StaticText(self, -1, "Shape:") self.shape_combo = self._fill_shape_combo() self.shape_sizer.AddMany([(label_txt, 0, wx.LEFT, 15), (self.shape_combo, 0, wx.LEFT, 5)]) def _fill_shape_combo(self): """ Fill up the shape combo box """ shape_combo = wx.ComboBox(self, -1, size=(150, -1), style=wx.CB_READONLY) shape_combo.Append('Rectangular') shape_combo.Append('Ellipsoid') shape_combo.Bind(wx.EVT_COMBOBOX, self._on_shape_select) shape_combo.SetSelection(0) return shape_combo def _on_shape_select(self, event): """ On selecting a shape """ event.Skip() label = event.GetEventObject().GetValue().lower() self.default_shape = label self.parent.set_omfpanel_default_shap(self.default_shape) self.parent.set_omfpanel_npts() def _fill_orient_combo(self): """ Fill up the orientation combo box: used only for atomic structure """ orient_combo = wx.ComboBox(self, -1, size=(150, -1), style=wx.CB_READONLY) orient_combo.Append('Fixed orientation') orient_combo.Append('Debye full avg.') #orient_combo.Append('Debye sph. sym.') orient_combo.Bind(wx.EVT_COMBOBOX, self._on_orient_select) orient_combo.SetSelection(0) return orient_combo def _on_orient_select(self, event): """ On selecting a orientation """ event.Skip() cb = event.GetEventObject() if cb.GetCurrentSelection() == 2: self.is_avg = None else: is_avg = cb.GetCurrentSelection() == 1 self.is_avg = is_avg self.model.set_is_avg(self.is_avg) self.set_est_time() def _layout_qrange(self): """ Fill the sizer containing qrange """ sizer = wx.GridBagSizer(2, 3) ix = 0 iy = 0 #key_list.sort() name = wx.StaticText(self, -1, 'No. of Qx (Qy) bins: ') sizer.Add(name, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) ## add parameter value ix += 1 self.npt_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 1.5, 20), style=wx.TE_PROCESS_ENTER) self.npt_ctl.Bind(wx.EVT_TEXT, self._onparamEnter) self.npt_ctl.SetValue(format_number(self.npts_x, True)) sizer.Add(self.npt_ctl, (iy, ix), (1, 1), wx.EXPAND) ## add unit ix += 1 unit = wx.StaticText(self, -1, '') sizer.Add(unit, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) iy += 1 ix = 0 name = wx.StaticText(self, -1, 'Qx (Qy) Max: ') sizer.Add(name, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) ## add parameter value ix += 1 self.qmax_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 1.5, 20), style=wx.TE_PROCESS_ENTER) self.qmax_ctl.Bind(wx.EVT_TEXT, self._onparamEnter ) self.qmax_ctl.SetValue(format_number(self.qmax_x, True)) sizer.Add(self.qmax_ctl, (iy, ix), (1, 1), wx.EXPAND) ## add unit ix += 1 unit = wx.StaticText(self, -1, '[1/A]') sizer.Add(unit, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) self.qrange_sizer.Add(sizer, 0, wx.LEFT, 10) def _layout_button(self): """ Do the layout for the button widgets """ self.est_time = '*Estimated Computation time :\n %s' self.time_text = wx.StaticText(self, -1, self.est_time% str('2 sec') ) self.orient_combo = self._fill_orient_combo() self.orient_combo.Show(False) self.bt_compute = wx.Button(self, wx.NewId(),'Compute') self.bt_compute.Bind(wx.EVT_BUTTON, self.on_compute) self.bt_compute.SetToolTipString("Compute 2D Scattering Pattern.") self.button_sizer.AddMany([(self.time_text , 0, wx.LEFT, 20), (self.orient_combo , 0, wx.LEFT, 40), (self.bt_compute, 0, wx.LEFT, 20)]) def estimate_ctime(self): """ Calculation time estimation """ # magic equation: not very accurate factor = 1 n_qbins = float(self.npt_ctl.GetValue()) n_qbins *= n_qbins n_pixs = float(self.parent.get_npix()) if self.is_avg: factor = 6 n_pixs *= (n_pixs / 200) x_in = n_qbins * n_pixs / 100000 etime = factor + 0.085973 * x_in return int(etime) def set_est_time(self): """ Set text for est. computation time """ unit = 'sec' if self.time_text != None: self.time_text.SetForegroundColour('black') etime = self.estimate_ctime() if etime > 60: etime /= 60 unit = 'min' self.time_text.SetForegroundColour('red') time_str = str(etime) + ' ' + unit self.time_text.SetLabel(self.est_time% time_str) def _do_layout(self): """ Draw window content """ self._define_structure() self._layout_data_name() self._layout_param_size() self._layout_qrange() self._layout_hint() self._layout_shape() self._layout_button() self.boxsizer_source.AddMany([(self.data_name_sizer, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5), (self.hint_sizer, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5), (self.shape_sizer, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)]) self.boxsizer_parameters.AddMany([(self.param_sizer, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5),]) self.boxsizer_qrange.AddMany([(self.qrange_sizer, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5),]) self.main_sizer.AddMany([(self.boxsizer_source, 0, wx.EXPAND|wx.ALL, 10), (self.boxsizer_parameters, 0, wx.EXPAND|wx.ALL, 10), (self.boxsizer_qrange, 0, wx.EXPAND|wx.ALL, 10), (self.button_sizer, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)]) self.SetSizer(self.main_sizer) self.SetAutoLayout(True) def _create_default_sld_data(self): """ Making default sld-data """ sld_n_default = 6.97e-06 omfdata = sans_gen.OMFData() omf2sld = sans_gen.OMF2SLD() omf2sld.set_data(omfdata, self.default_shape) self.sld_data = omf2sld.output self.sld_data.is_data = False self.sld_data.filename = "Default SLD Profile" self.sld_data.set_sldn(sld_n_default) self.data_name_tcl.SetValue(self.sld_data.filename) def choose_data_file(self, location=None): """ Choosing a dtata file """ path = None filename = '' if location == None: location = os.getcwd() exts = "*" + self.omfreader.ext[0] exts += ", *" + self.sldreader.ext[0] exts += ", *" + self.pdbreader.ext[0] all_type = "All GEN files (%s, %s) | %s"% (exts.upper(), exts.lower(), exts.lower().replace(',', ';')) wildcard = [all_type] omf_type = self.omfreader.type sld_type = self.sldreader.type pdb_type = self.pdbreader.type for type in sld_type: wildcard.append(type) for type in omf_type: wildcard.append(type) for type in pdb_type: wildcard.append(type) wildcard = '|'.join(wildcard) dlg = wx.FileDialog(self, "Choose a file", location, "", wildcard, wx.OPEN) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() filename = os.path.basename(path) dlg.Destroy() return path def on_load_data(self, event): """ Open a file dialog to allow the user to select a given file. The user is only allow to load file with extension .omf, .txt, .sld. Display the slit size corresponding to the loaded data. """ location = self.parent.get_path() path = self.choose_data_file(location=location) if path is None: return self.shape_sizer.ShowItems(False) self.default_shape = 'rectangular' self.parent.set_omfpanel_default_shap(self.default_shape) self.parent.set_file_location(os.path.dirname(path)) try: #Load data self.ext = os.path.splitext(path)[-1] if self.ext in self.omfreader.ext: loader = self.omfreader elif self.ext in self.sldreader.ext: loader = self.sldreader elif self.ext in self.pdbreader.ext: loader = self.pdbreader else: loader = None if self.reader is not None and self.reader.isrunning(): self.reader.stop() self.browse_button.Enable(False) self.browse_button.SetLabel("Loading...") if self.parent.parent is not None: wx.PostEvent(self.parent.parent, StatusEvent(status="Loading...", type="progress")) self.reader = GenReader(path=path, loader=loader, completefn=self.complete_loading, updatefn=self.load_update) self.reader.queue() #self.load_update() except: self.ext = None if self.parent.parent is None: return msg = "Generic SANS Calculator: %s" % (sys.exc_value) wx.PostEvent(self.parent.parent, StatusEvent(status=msg, type='stop')) self.SetFocus() return def load_update(self): """ print update on the status bar """ if self.parent.parent is None: return if self.reader.isrunning(): type = "progress" else: type = "stop" wx.PostEvent(self.parent.parent, StatusEvent(status="", type=type)) def complete_loading(self, data=None, filename=''): """ Complete the loading """ #compute the slit size self.browse_button.Enable(True) self.browse_button.SetLabel('Load') try: is_pdbdata = False filename = data.filename self.data_name_tcl.SetValue(str(filename)) self.file_name = filename.split('.')[0] self.orient_combo.SetSelection(0) self.is_avg = False if self.ext in self.omfreader.ext: gen = sans_gen.OMF2SLD() gen.set_data(data) #omf_data = data self.sld_data = gen.get_magsld() elif self.ext in self.sldreader.ext: self.sld_data = data elif self.ext in self.pdbreader.ext: self.sld_data = data is_pdbdata = True #omf_data = None else: raise self.orient_combo.Show(is_pdbdata) self.button_sizer.Layout() self._set_sld_data_helper(True) except: if self.parent.parent is None: raise msg = "Loading Error: This file format is not supported " msg += "for GenSANS." wx.PostEvent(self.parent.parent, StatusEvent(status=msg, type='stop', info='Error')) self.SetFocus() return if self.parent.parent is None: return msg = "Load Complete" wx.PostEvent(self.parent.parent, StatusEvent(status=msg, type='stop')) self.SetFocus() def _set_sld_data_helper(self, is_draw=False): """ Set sld data helper """ #is_avg = self.orient_combo.GetCurrentSelection() == 1 self.model.set_is_avg(self.is_avg) self.model.set_sld_data(self.sld_data) self.draw_button.Enable(self.sld_data!=None) wx.CallAfter(self.parent.set_sld_data, self.sld_data) self._update_model_params() if is_draw: wx.CallAfter(self.sld_draw, None, False) def _update_model_params(self): """ Update the model parameter values """ for list in self.parameters: param_name = list[0].GetLabelText() val = str(self.model.params[param_name]) list[1].SetValue(val) def set_volume_ctl_val(self, val): """ Set volume txtctrl value """ for list in self.parameters: param_name = list[0].GetLabelText() if param_name.lower() == 'total_volume': list[1].SetValue(val) list[1].Refresh() break def _onparamEnter(self, event): """ On param enter """ try: item = event.GetEventObject() self._check_value() item.Refresh() except: pass def sld_draw(self, event=None, has_arrow=True): """ Draw 3D sld profile """ flag = self.parent.check_omfpanel_inputs() if not flag: infor = 'Error' msg = 'Error: Wrong inputs in the SLD info panel.' # inform msg to wx wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info=infor)) self.SetFocus() return self.sld_data = self.parent.get_sld_from_omf() output = self.sld_data #frame_size = wx.Size(470, 470) self.plot_frame = PlotFrame(self, -1, 'testView') frame = self.plot_frame frame.Show(False) add_icon(self.parent, frame) panel = frame.plotpanel try: # mpl >= 1.0.0 ax = panel.figure.gca(projection='3d') except: # mpl < 1.0.0 try: from mpl_toolkits.mplot3d import Axes3D ax = Axes3D(panel.figure) except: logging.error("PlotPanel could not import Axes3D") raise panel.dimension = 3 graph_title = self._sld_plot_helper(ax, output, has_arrow) # Use y, z axes (in mpl 3d) as z, y axes # that consistent with our SANS detector coords. ax.set_xlabel('x ($\A%s$)'% output.pos_unit) ax.set_ylabel('z ($\A%s$)'% output.pos_unit) ax.set_zlabel('y ($\A%s$)'% output.pos_unit) panel.subplot.figure.subplots_adjust(left=0.05, right=0.95, bottom=0.05, top=0.96) if output.pix_type == 'atom': ax.legend(loc='upper left', prop={'size':10}) num_graph = str(self.graph_num) frame.SetTitle('Graph %s: %s'% (num_graph, graph_title)) wx.CallAfter(frame.Show, True) self.graph_num += 1 def _sld_plot_helper(self, ax, output, has_arrow=False): """ Actual plot definition happens here :Param ax: axis3d :Param output: sld_data [MagSLD] :Param has_arrow: whether or not draws M vector [bool] """ # Set the locals color_dic = {'H':'blue', 'D':'purple', 'N': 'orange', 'O':'red', 'C':'green', 'P':'cyan', 'Other':'k'} marker = ',' m_size = 2 graph_title = self.file_name graph_title += " 3D SLD Profile " pos_x = output.pos_x pos_y = output.pos_y pos_z = output.pos_z sld_mx = output.sld_mx sld_my = output.sld_my sld_mz = output.sld_mz pix_symbol = output.pix_symbol if output.pix_type == 'atom': marker = 'o' m_size = 3.5 sld_tot = (numpy.fabs(sld_mx) + numpy.fabs(sld_my) + \ numpy.fabs(sld_mz) + numpy.fabs(output.sld_n)) is_nonzero = sld_tot > 0.0 is_zero = sld_tot == 0.0 # I. Plot null points if is_zero.any(): ax.plot(pos_x[is_zero], pos_z[is_zero], pos_y[is_zero], marker, c="y", alpha=0.5, markeredgecolor='y', markersize=m_size) pos_x = pos_x[is_nonzero] pos_y = pos_y[is_nonzero] pos_z = pos_z[is_nonzero] sld_mx = sld_mx[is_nonzero] sld_my = sld_my[is_nonzero] sld_mz = sld_mz[is_nonzero] pix_symbol = output.pix_symbol[is_nonzero] # II. Plot selective points in color other_color = numpy.ones(len(pix_symbol), dtype='bool') for key in color_dic.keys(): chosen_color = pix_symbol == key if numpy.any(chosen_color): other_color = other_color & (chosen_color != True) color = color_dic[key] ax.plot(pos_x[chosen_color], pos_z[chosen_color], pos_y[chosen_color], marker, c=color, alpha=0.5, markeredgecolor=color, markersize=m_size, label=key) # III. Plot All others if numpy.any(other_color): a_name = '' if output.pix_type == 'atom': # Get atom names not in the list a_names = [symb for symb in pix_symbol \ if symb not in color_dic.keys()] a_name = a_names[0] for name in a_names: new_name = ", " + name if a_name.count(name) == 0: a_name += new_name # plot in black ax.plot(pos_x[other_color], pos_z[other_color], pos_y[other_color], marker, c="k", alpha=0.5, markeredgecolor="k", markersize=m_size, label=a_name) # IV. Draws atomic bond with grey lines if any if output.has_conect: for ind in range(len(output.line_x)): ax.plot(output.line_x[ind], output.line_z[ind], output.line_y[ind], '-', lw=0.6, c="grey", alpha=0.3) # V. Draws magnetic vectors if has_arrow and len(pos_x) > 0: graph_title += " - Magnetic Vector as Arrow -" panel = self.plot_frame.plotpanel def _draw_arrow(input=None, update=None): """ draw magnetic vectors w/arrow """ max_mx = max(numpy.fabs(sld_mx)) max_my = max(numpy.fabs(sld_my)) max_mz = max(numpy.fabs(sld_mz)) max_m = max(max_mx, max_my, max_mz) try: max_step = max(output.xstepsize, output.ystepsize, output.zstepsize) except: max_step = 0 if max_step <= 0: max_step = 5 try: if max_m != 0: unit_x2 = sld_mx / max_m unit_y2 = sld_my / max_m unit_z2 = sld_mz / max_m # 0.8 is for avoiding the color becomes white=(1,1,1)) color_x = numpy.fabs(unit_x2 * 0.8) color_y = numpy.fabs(unit_y2 * 0.8) color_z = numpy.fabs(unit_z2 * 0.8) x2 = pos_x + unit_x2 * max_step y2 = pos_y + unit_y2 * max_step z2 = pos_z + unit_z2 * max_step x_arrow = numpy.column_stack((pos_x, x2)) y_arrow = numpy.column_stack((pos_y, y2)) z_arrow = numpy.column_stack((pos_z, z2)) colors = numpy.column_stack((color_x, color_y, color_z)) arrows = Arrow3D(panel, x_arrow, z_arrow, y_arrow, colors, mutation_scale=10, lw=1, arrowstyle="->", alpha = 0.5) ax.add_artist(arrows) except: pass msg = "Arrow Drawing completed.\n" status_type = 'stop' self._status_info(msg, status_type) msg = "Arrow Drawing is in progress..." status_type = 'progress' self._status_info(msg, status_type) draw_out = CalcGen(input=ax, completefn=_draw_arrow, updatefn=self._update) draw_out.queue() return graph_title def set_input_params(self): """ Set model parameters """ for list in self.parameters: param_name = list[0].GetLabelText() param_value = float(list[1].GetValue()) self.model.setParam(param_name, param_value) def on_compute(self, event): """ Compute I(qx, qy) """ flag = self.parent.check_omfpanel_inputs() if not flag and self.parent.parent != None: infor = 'Error' msg = 'Error: Wrong inputs in the SLD info panel.' # inform msg to wx wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info=infor)) self.SetFocus() return self.sld_data = self.parent.get_sld_from_omf() if self.sld_data == None: if self.parent.parent != None: infor = 'Error' msg = 'Error: No data has been selected.' # inform msg to wx wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info=infor)) self.SetFocus() return flag = self._check_value() if not flag: _set_error(self, None, True) return try: self.model.set_sld_data(self.sld_data) self.set_input_params() if self.is_avg or self.is_avg == None: self._create_default_1d_data() i_out = numpy.zeros(len(self.data.y)) inputs = [self.data.x, [], i_out] else: self._create_default_2d_data() i_out = numpy.zeros(len(self.data.data)) inputs=[self.data.qx_data, self.data.qy_data, i_out] msg = "Computation is in progress..." status_type = 'progress' self._status_info(msg, status_type) cal_out = CalcGen(input=inputs, completefn=self.complete, updatefn=self._update) cal_out.queue() except: msg = "%s."% sys.exc_value status_type = 'stop' self._status_info(msg, status_type) wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info='Error')) self.SetFocus() def _check_value(self): """ Check input values if float """ flag = True self.npt_ctl.SetBackgroundColour("white") self.qmax_ctl.SetBackgroundColour("white") try: npt_val = float(self.npt_ctl.GetValue()) if npt_val < 2 or npt_val > 1000: raise self.npt_ctl.SetValue(str(int(npt_val))) self.set_est_time() except: flag = _set_error(self, self.npt_ctl) try: qmax_val = float(self.qmax_ctl.GetValue()) if qmax_val <= 0 or qmax_val > 1000: raise except: flag = _set_error(self, self.qmax_ctl) for list in self.parameters: list[1].SetBackgroundColour("white") param_name = list[0].GetLabelText() try: param_val = float(list[1].GetValue()) if param_name.count('frac') > 0: if param_val < 0 or param_val > 1: raise except: flag = _set_error(self, list[1]) return flag def _status_info(self, msg = '', type = "update"): """ Status msg """ if type == "stop": label = "Compute" able = True else: label = "Wait..." able = False self.bt_compute.Enable(able) self.bt_compute.SetLabel(label) self.bt_compute.SetToolTipString(label) if self.parent.parent != None: wx.PostEvent(self.parent.parent, StatusEvent(status = msg, type = type )) def _update(self, time=None): """ Update the progress bar """ if self.parent.parent == None: return type = "progress" msg = "Please wait. Computing... (Note: Window may look frozen.)" wx.PostEvent(self.parent.parent, StatusEvent(status=msg, type=type)) def complete(self, input, update=None): """ Gen compute complete function :Param input: input list [qx_data, qy_data, i_out] """ out = numpy.empty(0) #s = time.time() for ind in range(len(input[0])): if self.is_avg: if ind % 1 == 0 and update != None: update() time.sleep(0.1) inputi = [input[0][ind:ind+1], [], input[2][ind:ind+1]] outi = self.model.run(inputi) out = numpy.append(out, outi) else: if ind % 50 == 0 and update != None: update() time.sleep(0.001) inputi = [input[0][ind:ind+1], input[1][ind:ind+1], input[2][ind:ind+1]] outi = self.model.runXY(inputi) out = numpy.append(out, outi) #print time.time() - s if self.is_avg or self.is_avg == None: self._draw1D(out) else: #out = self.model.runXY(input) self._draw2D(out) msg = "Gen computation completed.\n" status_type = 'stop' self._status_info(msg, status_type) 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.qmax_x = float(self.qmax_ctl.GetValue()) self.npts_x = int(float(self.npt_ctl.GetValue())) self.data = Data2D() qmax = self.qmax_x #/ numpy.sqrt(2) self.data.xaxis('\\rm{Q_{x}}', '\AA^{-1}') self.data.yaxis('\\rm{Q_{y}}', '\AA^{-1}') self.data.is_data = False self.data.id = str(self.uid) + " GenData" 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 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) # store x and y bin centers in q space x_bins = x y_bins = y 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 def _create_default_1d_data(self): """ Create 2D data by default Only when the page is on theory mode. :warning: This data is never plotted. residuals.x = data_copy.x[index] residuals.dy = numpy.ones(len(residuals.y)) residuals.dx = None residuals.dxl = None residuals.dxw = None """ self.qmax_x = float(self.qmax_ctl.GetValue()) self.npts_x = int(float(self.npt_ctl.GetValue())) qmax = self.qmax_x #/ numpy.sqrt(2) ## Default values xmax = qmax xmin = qmax * _Q1D_MIN qstep = self.npts_x x = numpy.linspace(start=xmin, stop=xmax, num=qstep, endpoint=True) # store x and y bin centers in q space #self.data.source = Source() y = numpy.ones(len(x)) dy = numpy.zeros(len(x)) dx = numpy.zeros(len(x)) self.data = Data1D(x=x, y=y) self.data.dx = dx self.data.dy = dy def _draw1D(self, y_out): """ Complete get the result of modelthread and create model 2D that can be plot. """ page_id = self.id data = self.data model = self.model state = None new_plot = Data1D(x=data.x, y=y_out) new_plot.dx = data.dx new_plot.dy = data.dy new_plot.xaxis('\\rm{Q_{x}}', '\AA^{-1}') new_plot.yaxis('\\rm{Intensity}', 'cm^{-1}') new_plot.is_data = False new_plot.id = str(self.uid) + " GenData1D" new_plot.group_id = str(self.uid) + " Model1D" new_plot.name = model.name + '1d' new_plot.title = "Generic model1D " new_plot.id = str(page_id) + ': ' + self.file_name \ + ' #%s'% str(self.graph_num) + "_1D" new_plot.group_id = str(page_id) + " Model1D" +\ ' #%s'% str(self.graph_num) + "_1D" new_plot.is_data = False title = new_plot.title _yaxis, _yunit = new_plot.get_yaxis() _xaxis, _xunit = new_plot.get_xaxis() new_plot.xaxis(str(_xaxis), str(_xunit)) new_plot.yaxis(str(_yaxis), str(_yunit)) if new_plot.is_data: data_name = str(new_plot.name) else: data_name = str(model.__class__.__name__) + '1d' if len(title) > 1: new_plot.title = "Gen Theory for %s "% model.name + data_name new_plot.name = new_plot.id new_plot.label = new_plot.id #theory_data = deepcopy(new_plot) if self.parent.parent != None: self.parent.parent.update_theory(data_id=new_plot.id, theory=new_plot, state=state) title = new_plot.title num_graph = str(self.graph_num) wx.CallAfter(self.parent.draw_graph, new_plot, title="GEN Graph %s: "% num_graph + new_plot.id ) self.graph_num += 1 def _draw2D(self, image): """ Complete get the result of modelthread and create model 2D that can be plot. """ page_id = self.id data = self.data model = self.model qmin = 0.0 state = None numpy.nan_to_num(image) new_plot = Data2D(image=image, err_image=data.err_data) new_plot.name = model.name + '2d' new_plot.title = "Generic model 2D " new_plot.id = str(page_id) + ': ' + self.file_name \ + ' #%s'% str(self.graph_num) + "_2D" new_plot.group_id = str(page_id) + " Model2D" \ + ' #%s'% str(self.graph_num) + "_2D" new_plot.detector = data.detector new_plot.source = data.source new_plot.is_data = False new_plot.qx_data = data.qx_data new_plot.qy_data = data.qy_data new_plot.q_data = data.q_data new_plot.mask = data.mask ## plot boundaries new_plot.ymin = data.ymin new_plot.ymax = data.ymax new_plot.xmin = data.xmin new_plot.xmax = data.xmax title = data.title _yaxis, _yunit = data.get_yaxis() _xaxis, _xunit = data.get_xaxis() new_plot.xaxis(str(_xaxis), str(_xunit)) new_plot.yaxis(str(_yaxis), str(_yunit)) new_plot.is_data = False if data.is_data: data_name = str(data.name) else: data_name = str(model.__class__.__name__) + '2d' if len(title) > 1: new_plot.title = "Gen Theory for %s "% model.name + data_name new_plot.name = new_plot.id new_plot.label = new_plot.id #theory_data = deepcopy(new_plot) if self.parent.parent != None: self.parent.parent.update_theory(data_id=data.id, theory=new_plot, state=state) title = new_plot.title num_graph = str(self.graph_num) wx.CallAfter(self.parent.draw_graph, new_plot, title="GEN Graph %s: "% num_graph + new_plot.id ) self.graph_num += 1 def set_scale2d(self, scale): """ Set SLD plot scale """ self.scale2d = None def on_panel_close(self, event): """ On Close SLD panel """ #Not implemented class OmfPanel(ScrolledPanel, PanelBase): """ Provides the sas gen calculator GUI. """ ## Internal nickname for the window, used by the AUI manager window_name = "SLD Pixel Info" ## Name to appear on the window title bar window_caption = "SLD Pixel Info " ## Flag to tell the AUI manager to put this panel in the center pane CENTER_PANE = False def __init__(self, parent, *args, **kwds): ScrolledPanel.__init__(self, parent, style=wx.RAISED_BORDER, *args, **kwds) PanelBase.__init__(self) #Font size self.SetWindowVariant(variant=FONT_VARIANT) self.SetupScrolling() # Object that receive status event self.parent = parent self.sld_data = sans_gen.MagSLD([0], [0], [0]) self.sld_ctl = None self.default_shape = 'rectangular' self._do_layout() def set_slddata(self, slddata): """ Set sld data related items """ self.sld_data = slddata self._set_slddata_ctr_val(slddata) # Make sure that self._set_slddata_ctr_val() is finished wx.CallAfter(self._set_omfdata_ctr, slddata) def get_sld_val(self): """ Set sld_n of slddata on sld input """ sld_sets = {} if not self.sld_data.is_data: self._get_other_val() for list in self.slds: if list[1].IsEnabled(): list[1].SetBackgroundColour("white") list[1].Refresh() try: val = float(list[1].GetValue()) sld_sets[list[0]] = val except: flag = _set_error(self, list[1]) if not flag: return self.sld_data else: sld_sets[list[0]] = None for key in sld_sets.keys(): key_low = key.lower() if key_low.count('mx') > 0: if sld_sets[key] == None: sld_sets[key] = self.sld_data.sld_mx mx = sld_sets[key] elif key_low.count('my') > 0: if sld_sets[key] == None: sld_sets[key] = self.sld_data.sld_my my = sld_sets[key] elif key_low.count('mz') > 0: if sld_sets[key] == None: sld_sets[key] = self.sld_data.sld_mz mz = sld_sets[key] else: if sld_sets[key] != None: self.sld_data.set_sldn(sld_sets[key]) self.sld_data.set_sldms(mx, my, mz) self._set_slddata_ctr_val(self.sld_data) return self.sld_data def get_pix_volumes(self): """ Get the pixel volume """ vol = self.sld_data.vol_pix return vol def _get_other_val(self): """ """ omfdata = sans_gen.OMFData() sets = {} try: for lst in self.stepsize: if lst[1].IsEnabled(): val = float(lst[1].GetValue()) sets[lst[0]] = val else: sets[lst[0]] = None return for lst in self.nodes: if lst[1].IsEnabled(): val = float(lst[1].GetValue()) sets[lst[0]] = val else: sets[lst[0]] = None return for key in sets.keys(): exec "omfdata.%s = sets['%s']"% (key, key) omf2sld = sans_gen.OMF2SLD() omf2sld.set_data(omfdata, self.default_shape) self.sld_data = omf2sld.output self.sld_data.is_data = False self.sld_data.filename = "Default SLD Profile" except: msg = "OMF Panel: %s"% sys.exc_value infor = 'Error' #logging.error(msg) if self.parent.parent != None: # inform msg to wx wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info=infor)) self.SetFocus() def _set_slddata_ctr_val(self, slddata): """ Set slddata crl """ try: val = str(len(slddata.sld_n)) except: val = 'Unknown' self.npix_ctl.SetValue(val) def _set_omfdata_ctr(self, omfdata): """ Set the textctr box values """ if omfdata == None: self._set_none_text() return nodes_list = self._get_nodes_key_list(omfdata) step_list = self._get_step_key_list(omfdata) for ctr_list in self.nodes: for key in nodes_list.keys(): if ctr_list[0] == key: ctr_list[1].SetValue(format_number(nodes_list[key], True)) ctr_list[1].Enable(not omfdata.is_data) break for ctr_list in self.stepsize: for key in step_list.keys(): if ctr_list[0] == key: ctr_list[1].SetValue(format_number(step_list[key], True)) ctr_list[1].Enable(not omfdata.is_data) break def _set_none_text(self): """ Set Unknown in textctrls """ val = 'Unknown' for ctr_list in self.nodes: ctr_list[1].SetValue(val) for ctr_list in self.stepsize: ctr_list[1].SetValue(val) def _define_structure(self): """ Define the main sizers building to build this application. """ self.main_sizer = wx.BoxSizer(wx.VERTICAL) self.npixels_sizer = wx.BoxSizer(wx.HORIZONTAL) self.box_sld = wx.StaticBox(self, -1, str("Mean SLD")) self.box_node = wx.StaticBox(self, -1, str("Nodes")) self.boxsizer_sld = wx.StaticBoxSizer(self.box_sld, wx.VERTICAL) self.box_stepsize = wx.StaticBox(self, -1, str("Step Size")) self.boxsizer_node = wx.StaticBoxSizer(self.box_node, wx.VERTICAL) self.boxsizer_stepsize = wx.StaticBoxSizer(self.box_stepsize, wx.VERTICAL) self.sld_sizer = wx.BoxSizer(wx.HORIZONTAL) self.node_sizer = wx.BoxSizer(wx.HORIZONTAL) self.step_sizer = wx.BoxSizer(wx.HORIZONTAL) self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL) self.button_sizer = wx.BoxSizer(wx.HORIZONTAL) def _layout_npix(self): """ Build No of pixels sizer """ num_pix_text = wx.StaticText(self, -1, "No. of Pixels: ") self.npix_ctl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=wx.TE_PROCESS_ENTER) self._set_slddata_ctr_val(self.sld_data) self._set_omfdata_ctr(self.sld_data) self.npixels_sizer.AddMany([(num_pix_text, 0, wx.EXPAND|wx.LEFT|wx.TOP, 5), (self.npix_ctl, 0, wx.EXPAND|wx.TOP, 5)]) def _layout_slds(self): """ Build nuclear sld sizer """ self.slds = [] omfdata = self.sld_data if omfdata == None: raise sld_key_list = self._get_slds_key_list(omfdata) # Dic is not sorted key_list = [key for key in sld_key_list.keys()] # Sort here key_list.sort() is_data = self.sld_data.is_data sizer = wx.GridBagSizer(2, 3) ix = 0 iy = -1 for key in key_list: value = sld_key_list[key] iy += 1 ix = 0 name = wx.StaticText(self, -1, key) sizer.Add(name, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) ## add parameter value ix += 1 ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=wx.TE_PROCESS_ENTER) ctl.SetValue(format_number(value, True)) ctl.Enable(not is_data) sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND) ## add unit ix += 1 s_unit = '[' + omfdata.sld_unit + ']' unit = wx.StaticText(self, -1, s_unit) sizer.Add(unit, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) self.slds.append([key, ctl, unit]) self.sld_sizer.Add(sizer, 0, wx.LEFT, 10) def _layout_nodes(self): """ Fill the sizer containing data's name """ self.nodes = [] omfdata = self.sld_data if omfdata == None: raise key_list = self._get_nodes_key_list(omfdata) is_data = self.sld_data.is_data sizer = wx.GridBagSizer(2, 3) ix = 0 iy = -1 for key, value in key_list.iteritems(): iy += 1 ix = 0 name = wx.StaticText(self, -1, key) sizer.Add(name, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) ## add parameter value ix += 1 ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=wx.TE_PROCESS_ENTER) ctl.Bind(wx.EVT_TEXT, self._onparamEnter ) ctl.SetValue(format_number(value, True)) ctl.Enable(not is_data) sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND) ## add unit ix += 1 unit = wx.StaticText(self, -1, '') sizer.Add(unit, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) self.nodes.append([key, ctl, unit]) self.node_sizer.Add(sizer, 0, wx.LEFT, 10) def _layout_stepsize(self): """ Fill the sizer containing slit size information """ self.stepsize = [] omfdata = self.sld_data if omfdata == None: raise key_list = self._get_step_key_list(omfdata) is_data = self.sld_data.is_data sizer = wx.GridBagSizer(2, 3) ix = 0 iy = -1 #key_list.sort() for key, value in key_list.iteritems(): iy += 1 ix = 0 name = wx.StaticText(self, -1, key) sizer.Add(name, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) ## add parameter value ix += 1 ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=wx.TE_PROCESS_ENTER) ctl.Bind(wx.EVT_TEXT, self._onstepsize ) ctl.SetValue(format_number(value, True)) ctl.Enable(not is_data) sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND) ## add unit ix += 1 p_unit = '[' + omfdata.pos_unit + ']' unit = wx.StaticText(self, -1, p_unit) sizer.Add(unit, (iy, ix), (1, 1), \ wx.EXPAND | wx.ADJUST_MINSIZE, 0) self.stepsize.append([key, ctl, unit]) self.step_sizer.Add(sizer, 0, wx.LEFT, 10) def _layout_hint(self): """ Fill the sizer containing hint """ hint_msg = "Load an omf or 3d sld profile data file." self.hint_txt = wx.StaticText(self, -1, hint_msg) self.hint_sizer.AddMany([(self.hint_txt, 0, wx.LEFT, 15)]) def _layout_button(self): """ Do the layout for the button widgets """ self.bt_draw = wx.Button(self, wx.NewId(),'Draw Points') self.bt_draw.Bind(wx.EVT_BUTTON, self.on_sld_draw) self.bt_draw.SetToolTipString("Draw a scatter plot for sld profile.") self.bt_save = wx.Button(self, wx.NewId(),'Save SLD Data') self.bt_save.Bind(wx.EVT_BUTTON, self.on_save) self.bt_save.Enable(False) self.bt_save.SetToolTipString("Save SLD data.") self.button_sizer.AddMany([(self.bt_draw, 0, wx.LEFT, 10), (self.bt_save, 0, wx.LEFT, 10)]) def _do_layout(self): """ Draw window content """ self._define_structure() self._layout_nodes() self._layout_stepsize() self._layout_npix() self._layout_slds() #self._layout_hint() self._layout_button() self.boxsizer_node.AddMany([(self.node_sizer, 0, wx.EXPAND|wx.TOP, 5), (self.hint_sizer, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)]) self.boxsizer_stepsize.AddMany([(self.step_sizer, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5),]) self.boxsizer_sld.AddMany([(self.sld_sizer, 0, wx.EXPAND|wx.BOTTOM, 5),]) self.main_sizer.AddMany([(self.npixels_sizer, 0, wx.EXPAND|wx.ALL, 10), (self.boxsizer_sld, 0, wx.EXPAND|wx.ALL, 10), (self.boxsizer_node, 0, wx.EXPAND|wx.ALL, 10), (self.boxsizer_stepsize, 0, wx.EXPAND|wx.ALL, 10), (self.button_sizer, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)]) self.SetSizer(self.main_sizer) self.SetAutoLayout(True) def _get_nodes_key_list(self, data): """ Return nodes key list :Param data: OMFData """ key_list = {'xnodes' : data.xnodes, 'ynodes' : data.ynodes, 'znodes' : data.znodes} return key_list def _get_slds_key_list(self, data): """ Return nodes key list :Param data: OMFData """ key_list = {'Nucl.' : data.sld_n, 'Mx' : data.sld_mx, 'My' : data.sld_my, 'Mz' : data.sld_mz} return key_list def _get_step_key_list(self, data): """ Return step key list :Param data: OMFData """ key_list = {'xstepsize' : data.xstepsize, 'ystepsize' : data.ystepsize, 'zstepsize' : data.zstepsize} return key_list def set_sld_ctr(self, sld_data): """ Set sld textctrls """ if sld_data == None: for ctr_list in self.slds: ctr_list[1].Enable(False) #break return self.sld_data = sld_data sld_list = self._get_slds_key_list(sld_data) for ctr_list in self.slds: for key in sld_list.keys(): if ctr_list[0] == key: min_val = numpy.min(sld_list[key]) max_val = numpy.max(sld_list[key]) mean_val = numpy.mean(sld_list[key]) enable = (min_val == max_val) and \ sld_data.pix_type == 'pixel' ctr_list[1].SetValue(format_number(mean_val, True)) ctr_list[1].Enable(enable) #ctr_list[2].SetLabel("[" + sld_data.sld_unit + "]") break def on_sld_draw(self, event): """ Draw sld profile as scattered plot """ self.parent.sld_draw() def on_save(self, event): """ Close the window containing this panel """ flag = True flag = self.check_inputs() if not flag: return self.sld_data = self.get_sld_val() self.parent.set_main_panel_sld_data(self.sld_data) reader = sans_gen.SLDReader() extension = '*.sld' path = None data= None location = self.parent.get_path() dlg = wx.FileDialog(self, "Save sld file", location, "sld_file", extension, wx.SAVE) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.parent.set_file_location(os.path.dirname(path)) else: return None dlg.Destroy() try: if path is None: return data = self.parent.get_sld_data() fName = os.path.splitext(path)[0] + '.' + extension.split('.')[-1] if data != None: try: reader.write(fName, data) except: raise else: msg = "%s cannot write %s\n" % ('Generic Scattering', str(path)) infor = 'Error' #logging.error(msg) if self.parent.parent != None: # inform msg to wx wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info=infor)) self.SetFocus() return except: msg = "Error occurred while saving. " infor = 'Error' if self.parent.parent != None: # inform msg to wx wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info=infor)) self.SetFocus() def _onparamEnter(self, event): """ """ flag = True if event != None: event.Skip() ctl = event.GetEventObject() ctl.SetBackgroundColour("white") #_set_error(self, ctl) try: float(ctl.GetValue()) except: flag = _set_error(self, ctl) if flag: npts = 1 for item in self.nodes: n_val = float(item[1].GetValue()) if n_val <= 0: item[1].SetBackgroundColour("pink") npts = -1 break if numpy.isfinite(n_val): npts *= int(n_val) if npts > 0: nop = self.set_npts_from_slddata() if nop == None: nop = npts self.display_npts(nop) ctl.Refresh() return flag def _set_volume_ctr_val(self, npts): """ Set total volume """ total_volume = npts * self.sld_data.vol_pix[0] self.parent.set_volume_ctr_val(total_volume) def _onstepsize(self, event): """ On stepsize event """ flag = True if event != None: event.Skip() ctl = event.GetEventObject() ctl.SetBackgroundColour("white") if flag and not self.sld_data.is_data:#ctl.IsEnabled(): s_size = 1.0 try: for item in self.stepsize: s_val = float(item[1].GetValue()) if s_val <= 0: item[1].SetBackgroundColour("pink") ctl.Refresh() return if numpy.isfinite(s_val): s_size *= s_val self.sld_data.set_pixel_volumes(s_size) if ctl.IsEnabled(): total_volume = sum(self.sld_data.vol_pix) self.parent.set_volume_ctr_val(total_volume) except: pass ctl.Refresh() def set_npts_from_slddata(self): """ Set total n. of points form the sld data """ try: sld_data = self.parent.get_sld_from_omf() #nop = (nop * numpy.pi) / 6 nop = len(sld_data.sld_n) except: nop = None return nop def display_npts(self, nop): """ Displays Npts ctrl """ try: self.npix_ctl.SetValue(str(nop)) self.npix_ctl.Refresh() self.parent.set_etime() wx.CallAfter(self._set_volume_ctr_val, nop) except: # On Init pass def check_inputs(self): """ check if the inputs are valid """ flag = self._check_input_helper(self.slds) if flag: flag = self._check_input_helper(self.nodes) if flag: flag = self._check_input_helper(self.stepsize) return flag def _check_input_helper(self, list): """ Check list values """ flag = True for item in list: item[1].SetBackgroundColour("white") item[1].Refresh() try: float(item[1].GetValue()) except: flag = _set_error(self, item[1]) break return flag class SasGenWindow(widget.CHILD_FRAME): """ GEN SAS main window """ def __init__(self, parent=None, manager= None, title="Generic Scattering Calculator", size=(PANEL_WIDTH * 1.3, PANEL_HEIGHT * 1.65), *args, **kwds): """ Init """ kwds['size'] = size kwds['title'] = title widget.CHILD_FRAME.__init__(self, parent, *args, **kwds) self.parent = parent self.base = manager self.omfpanel = OmfPanel(parent=self) self.panel = SasGenPanel(parent=self) self.data = None self.omfdata = sans_gen.OMFData() self.sld_data = None self._default_save_location = os.getcwd() self._mgr = aui.AuiManager(self) self._mgr.SetDockSizeConstraint(0.5, 0.5) self._plot_title = '' self.scale2d = 'log_{10}' self.Bind(wx.EVT_CLOSE, self.on_close) self._build_toolbar() self.build_panels() self.SetPosition((25, 150)) self.Show(True) def _build_toolbar(self): """ Build toolbar """ tsize = (20, 20) # The legacy code doesn't work well for wx 3.0 # but the old code produces better results with wx 2.8 if wx.VERSION_STRING >= '3.0.0.0': tb = wx.ToolBar(self, style=wx.TB_HORIZONTAL | wx.TB_FLAT) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(tb, 0, wx.EXPAND) self.SetSizer(sizer) else: tb = self.CreateToolBar(wx.TB_HORIZONTAL | wx.TB_FLAT) open_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, tsize) save_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS, wx.ART_TOOLBAR, tsize) close_bmp = wx.ArtProvider.GetBitmap(wx.ART_QUIT, wx.ART_TOOLBAR, tsize) help_bmp = wx.ArtProvider.GetBitmap(wx.ART_HELP, wx.ART_TOOLBAR, (17, 20)) id = wx.NewId() tb.AddLabelTool(id, "Open", open_bmp, shortHelp="Open", longHelp="Open sld/omf file") self.Bind(wx.EVT_TOOL, self.on_open_file, id=id) id = wx.NewId() tb.AddSimpleTool(id, save_bmp, "Save", "Save as sld file") self.Bind(wx.EVT_TOOL, self.on_save_file, id=id) tb.AddSeparator() id = wx.NewId() tb.AddSimpleTool(id, close_bmp, "Quit", "Quit") self.Bind(wx.EVT_TOOL, self.on_close, id=id) tb.AddSeparator() id = wx.NewId() tb.AddSimpleTool(id, help_bmp, "Help", "Help") self.Bind(wx.EVT_TOOL, self.on_help, id=id) tb.Realize() def _build_menubar(self): """ Build menubar """ tsize = (13, 13) open_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, tsize) save_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS, wx.ART_TOOLBAR, tsize) quit_bmp = wx.ArtProvider.GetBitmap(wx.ART_QUIT, wx.ART_TOOLBAR, tsize) help_bmp = wx.ArtProvider.GetBitmap(wx.ART_HELP, wx.ART_TOOLBAR, (13, 15)) menu_bar = wx.MenuBar() menu = wx.Menu() id = wx.NewId() item = wx.MenuItem(menu, id, "&Open sld/omf file") item.SetBitmap(open_bmp) menu.AppendItem(item) wx.EVT_MENU(self, id, self.on_open_file) id = wx.NewId() item = wx.MenuItem(menu, id, "&Save as sld file") item.SetBitmap(save_bmp) menu.AppendItem(item) wx.EVT_MENU(self, id, self.on_save_file) menu.AppendSeparator() id = wx.NewId() item = wx.MenuItem(menu, id, "&Quit") item.SetBitmap(quit_bmp) menu.AppendItem(item) menu_bar.Append(menu, "&File") wx.EVT_MENU(self, id, self.on_close) menu_help = wx.Menu() id = wx.NewId() item = wx.MenuItem(menu_help, id, "&Theory and GUI") item.SetBitmap(help_bmp) menu_help.AppendItem(item) wx.EVT_MENU(self, id, self.on_help) menu_bar.Append(menu_help, "&Help") self.SetMenuBar(menu_bar) def build_panels(self): """ """ self.set_sld_data(self.sld_data) self._mgr.AddPane(self.panel, aui.AuiPaneInfo(). Name(self.panel.window_name). CenterPane(). # This is where we set the size of # the application window BestSize(wx.Size(PANEL_WIDTH, PANEL_HEIGHT)). Show()) self._mgr.AddPane(self.omfpanel, aui.AuiPaneInfo(). Name(self.omfpanel.window_name). Caption(self.omfpanel.window_caption). CloseButton(False). Right(). Floatable(False). BestSize(wx.Size(PANEL_WIDTH/2.5, PANEL_HEIGHT)). Show()) self._mgr.Update() def get_sld_data(self): """ Return slddata """ return self.sld_data def get_sld_from_omf(self): """ """ self.sld_data = self.omfpanel.get_sld_val() return self.sld_data def set_sld_n(self, sld): """ """ self.panel.sld_data = sld self.panel.model.set_sld_data(sld) def set_sld_data(self, data): """ Set omfdata """ if data == None: return self.sld_data = data enable = (not data==None) self._set_omfpanel_sld_data(self.sld_data) self.omfpanel.bt_save.Enable(enable) self.set_etime() def set_omfpanel_npts(self): """ Set Npts in omf panel """ nop = self.omfpanel.set_npts_from_slddata() self.omfpanel.display_npts(nop) def _set_omfpanel_sld_data(self, data): """ Set sld_data in omf panel """ self.omfpanel.set_slddata(data) self.omfpanel.set_sld_ctr(data) def check_omfpanel_inputs(self): """ Check OMF panel inputs """ return self.omfpanel.check_inputs() def set_main_panel_sld_data(self, sld_data): """ """ self.sld_data = sld_data def set_file_location(self, path): """ File location """ self._default_save_location = path def get_path(self): """ File location """ return self._default_save_location def draw_graph(self, plot, title=''): """ """ try: wx.PostEvent(self.parent, NewPlotEvent(plot=plot, title=title)) except: # standalone frame = PlotFrame(self, -1, 'testView', self.scale2d) #add_icon(self.parent, frame) frame.add_plot(plot) frame.SetTitle(title) frame.Show(True) frame.SetFocus() def set_schedule_full_draw(self, panel=None, func='del'): """ Send full draw to gui frame """ if self.parent != None: self.parent.set_schedule_full_draw(panel, func) def get_npix(self): """ Get no. of pixels from omf panel """ n_pix = self.omfpanel.npix_ctl.GetValue() return n_pix def get_pix_volumes(self): """ Get a pixel volume """ vol = self.omfpanel.get_pix_volumes() return vol def set_volume_ctr_val(self, val): """ Set volume txtctl value """ try: self.panel.set_volume_ctl_val(str(val)) except: print "self.panel is not initialized yet" def set_omfpanel_default_shap(self, shape): """ Set default_shape in omfpanel """ self.omfpanel.default_shape = shape def set_etime(self): """ Sets est. computation time on panel """ self.panel.set_est_time() def get_sld_data_from_omf(self): """ """ data = self.omfpanel.get_sld_val() return data def set_scale2d(self, scale): """ """ self.scale2d = scale def on_panel_close(self, event): """ """ #Not implemented def on_open_file(self, event): """ On Open """ self.panel.on_load_data(event) def sld_draw(self): """ sld draw """ self.panel.sld_draw(event=None, has_arrow=False) def on_save_file(self, event): """ On Close """ self.omfpanel.on_save(event) def on_close(self, event): """ Close """ if self.base != None: self.base.gen_frame = None self.Destroy() def on_help(self, event): """ Gen scatter angle help panel """ from sas.perspectives.calculator.help_panel import HelpWindow # Get models help model_function path import sas.perspectives.calculator as calmedia media = calmedia.get_data_path(media='media') path = os.path.join(media,"gen_sans_help.html") name = "Generic Scattering Calculator" frame = HelpWindow(self, -1, title=' Help: GenSANS', pageToOpen=path, size=(865, 450)) try: frame.splitter.DetachWindow(frame.lpanel) # Display only the right side one frame.lpanel.Hide() frame.Show(True) add_icon(self.parent, frame) except: frame.Destroy() msg = 'Display Error\n' info = "Info" wx.MessageBox(msg, info) if __name__ == "__main__": app = wx.PySimpleApp() widget.CHILD_FRAME = wx.Frame SGframe = SasGenWindow() SGframe.Show(True) app.MainLoop()