"""
Implement grid used to store data
"""
import wx
import numpy
import math
import re
import os
import sys
import copy
from wx.lib.scrolledpanel import ScrolledPanel
import wx.grid as Grid
import wx.aui
from wx.aui import AuiNotebook as nb
import wx.lib.sheet as sheet
from sas.guiframe.panel_base import PanelBase
from sas.guiframe.events import NewPlotEvent
from sas.guiframe.events import StatusEvent
from sas.plottools import plottables
from sas.guiframe.dataFitting import Data1D
FUNC_DICT = {"sqrt": "math.sqrt",
"pow": "math.sqrt"}
[docs]class BatchCell:
"""
Object describing a cell in the grid.
"""
def __init__(self):
self.label = ""
self.value = None
self.col = -1
self.row = -1
self.object = []
[docs]def parse_string(sentence, list):
"""
Return a dictionary of column label and index or row selected
:param sentence: String to parse
:param list: list of columns label
"""
toks = []
p2 = re.compile(r'\d+')
p = re.compile(r'[\+\-\*\%\/]')
labels = p.split(sentence)
col_dict = {}
for elt in labels:
rang = None
temp_arr = []
for label in list:
label_pos = elt.find(label)
separator_pos = label_pos + len(label)
if label_pos != -1 and len(elt) >= separator_pos and\
elt[separator_pos]== "[":
# the label contain , meaning the range selected is not
# continuous
if elt.count(',') > 0:
new_temp = []
temp = elt.split(label)
for item in temp:
range_pos = item.find(":")
if range_pos != -1:
rang = p2.findall(item)
for i in xrange(int(rang[0]), int(rang[1])+1 ):
new_temp.append(i)
temp_arr += new_temp
else:
# continuous range
temp = elt.split(label)
for item in temp:
if item.strip() != "":
range_pos = item.find(":")
if range_pos != -1:
rang = p2.findall(item)
for i in xrange(int(rang[0]), int(rang[1])+1 ):
temp_arr.append(i)
col_dict[elt] = (label, temp_arr)
return col_dict
[docs]class SPanel(ScrolledPanel):
def __init__(self, parent, *args, **kwds):
ScrolledPanel.__init__(self, parent , *args, **kwds)
self.SetupScrolling()
[docs]class GridPage(sheet.CSheet):
"""
"""
def __init__(self, parent, panel=None):
"""
"""
sheet.CSheet.__init__(self, parent)
self.AdjustScrollbars()
#self.SetLabelBackgroundColour('#DBD4D4')
self.uid = wx.NewId()
self.parent = parent
self.panel = panel
self.col_names = []
self.data_inputs = {}
self.data_outputs = {}
self.data = None
self.details = ""
self.file_name = None
self._cols = 50
self._rows = 3001
self.last_selected_row = -1
self.last_selected_col = -1
self.col_width = 30
self.row_height = 20
self.max_row_touse = 0
self.axis_value = []
self.axis_label = ""
self.selected_cells = []
self.selected_cols = []
self.selected_rows = []
self.plottable_cells = []
self.plottable_flag = False
self.SetColMinimalAcceptableWidth(self.col_width)
self.SetRowMinimalAcceptableHeight(self.row_height)
self.SetNumberRows(self._rows)
self.SetNumberCols(self._cols)
color = self.parent.GetBackgroundColour()
for col in range(self._cols):
self.SetCellBackgroundColour(0, col, color)
self.AutoSize()
self.list_plot_panels = {}
self.default_col_width = 75
self.EnableEditing(True)
if self.GetNumberCols() > 0:
self.default_col_width = self.GetColSize(0)
self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.on_left_click)
self.Bind(wx.grid.EVT_GRID_LABEL_RIGHT_CLICK, self.on_right_click)
self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.on_selected_cell)
self.Bind(wx.grid.EVT_GRID_CMD_CELL_CHANGE, self.on_edit_cell)
self.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, self.onContextMenu)
[docs] def on_edit_cell(self, event):
"""
"""
row, col = event.GetRow(), event.GetCol()
if row > self.max_row_touse:
self.max_row_touse = row
if self.data == None:
self.data = {}
event.Skip()
[docs] def on_selected_cell(self, event):
"""
Handler catching cell selection
"""
flag = event.CmdDown() or event.ControlDown()
flag_shift = event.ShiftDown()
row, col = event.GetRow(), event.GetCol()
cell = (row, col)
event.Skip()
if not flag and not flag_shift:
self.selected_cols = []
self.selected_rows = []
self.selected_cells = []
self.axis_label = ""
self.axis_value = []
self.plottable_list = []
self.plottable_cells = []
self.plottable_flag = False
self.last_selected_col = col
self.last_selected_row = row
if col >= 0:
if flag:
label_row = row
else:
label_row = 0
self.axis_label = self.GetCellValue(label_row, col)
self.selected_cols.append(col)
if flag_shift:
if not self.selected_rows:
min_r = 1
else:
min_r = min(self.selected_rows)
for row_s in range(min_r, row+1):
cel = (row_s, col)
if cel not in self.selected_cells:
if row > 0:
self.selected_cells.append(cel)
self.selected_rows.append(row)
for row_s in self.selected_rows:
cel = (row_s, col)
if row_s > row:
try:
self.selected_cells.remove(cel)
except:
pass
try:
self.selected_rows.remove(row_s)
except:
pass
elif flag:
if cell not in self.selected_cells:
if row > 0 :
self.selected_cells.append(cell)
self.selected_rows.append(row)
else:
try:
self.selected_cells.remove(cell)
except:
pass
try:
self.selected_rows.remove(row)
except:
pass
else:
self.selected_cells.append(cell)
self.selected_rows.append(row)
self.axis_value = []
for cell_row, cell_col in self.selected_cells:
if cell_row > 0 and cell_row < self.max_row_touse:
self.axis_value.append(self.GetCellValue(cell_row, cell_col))
[docs] def on_left_click(self, event):
"""
Catch the left click on label mouse event
"""
event.Skip()
flag = event.CmdDown() or event.ControlDown()
col = event.GetCol()
row = event.GetRow()
if not (flag):
self.selected_cols = []
self.selected_rows = []
self.selected_cells = []
self.axis_label = ""
self.axis_value = []
self.plottable_list = []
self.plottable_cells = []
self.plottable_flag = False
self.last_selected_col = col
self.last_selected_row = row
if row != -1 and row not in self.selected_rows:
self.selected_rows.append(row)
if col != -1:
for row in range(1, self.GetNumberRows()+ 1):
cell = (row, col)
if row > 0 and row < self.max_row_touse:
if cell not in self.selected_cells:
self.selected_cells.append(cell)
else:
if flag:
self.selected_cells.remove(cell)
self.selected_cols.append(col)
self.axis_value = []
for cell_row, cell_col in self.selected_cells:
val = self.GetCellValue(cell_row, cell_col)
if not val:
self.axis_value.append(self.GetCellValue(cell_row, cell_col))
self.axis_label = self.GetCellValue(0, col)
if not self.axis_label:
self.axis_label = " "
[docs] def on_right_click(self, event):
"""
Catch the right click mouse
"""
col = event.GetCol()
row = event.GetRow()
# Ignore the index column
if col < 0 or row != -1:
return
self.selected_cols = []
self.selected_cols.append(col)
# Slicer plot popup menu
slicerpop = wx.Menu()
col_label_menu = wx.Menu()
c_name = self.GetCellValue(0, col)
label = "Insert column before %s " % str(c_name)
slicerpop.AppendSubMenu(col_label_menu ,
'&%s' % str(label), str(label))
col_name = [self.GetCellValue(0, c)
for c in range(self.GetNumberCols())]
row = 0
label = self.GetCellValue(row, col)
self.insert_col_menu(col_label_menu, label, self)
col_after_menu = wx.Menu()
label = "Insert column after %s " % str(c_name)
slicerpop.AppendSubMenu(col_after_menu ,
'&%s' % str(label), str(label))
col_name = [self.GetCellValue(0, c)
for c in range(self.GetNumberCols())]
self.insert_after_col_menu(col_after_menu, label, self)
id = wx.NewId()
hint = 'Remove selected column %s'
slicerpop.Append(id, '&Remove Column', hint)
wx.EVT_MENU(self, id, self.on_remove_column)
pos = wx.GetMousePosition()
pos = self.ScreenToClient(pos)
self.PopupMenu(slicerpop, pos)
event.Skip()
[docs] def on_remove_column(self, event=None):
"""
"""
if self.selected_cols is not None or len(self.selected_cols) > 0:
col = self.selected_cols[0]
self.remove_column(col=col, numCols=1)
[docs] def remove_column(self, col, numCols=1):
"""
Remove column to the current grid
"""
# add data to the grid
row = 0
col_name = self.GetCellValue(row, col)
self.data[col_name] = []
for row in range(1, self.GetNumberRows() + 1):
if row < self.max_row_touse:
value = self.GetCellValue(row, col)
self.data[col_name].append(value)
for k , value_list in self.data.iteritems():
if k != col_name:
length = len(value_list)
if length < self.max_row_touse:
diff = self.max_row_touse - length
for i in range(diff):
self.data[k].append("")
self.DeleteCols(pos=col, numCols=numCols, updateLabels=True)
[docs] def on_insert_column(self, event):
"""
"""
if self.selected_cols is not None or len(self.selected_cols) > 0:
col = self.selected_cols[0]
# add data to the grid
row = 0
id = event.GetId()
col_name = event.GetEventObject().GetLabelText(id)
self.insert_column(col=col, col_name=col_name)
if not issubclass(event.GetEventObject().__class__ , wx.Menu):
col += 1
self.selected_cols[0] += 1
[docs] def on_insert_after_column(self, event):
"""
Insert the given column after the highlighted column
"""
if self.selected_cols is not None or len(self.selected_cols) > 0:
col = self.selected_cols[0] + 1
# add data to the grid
row = 0
id = event.GetId()
col_name = event.GetEventObject().GetLabelText(id)
self.insert_column(col=col, col_name=col_name)
if not issubclass(event.GetEventObject().__class__ , wx.Menu):
self.selected_cols[0] += 1
[docs] def insert_column(self, col, col_name):
"""
"""
row = 0
self.InsertCols(pos=col, numCols=1, updateLabels=True)
if col_name.strip() != "Empty":
self.SetCellValue(row, col, str(col_name.strip()))
if col_name in self.data.keys():
value_list = self.data[col_name]
cell_row = 1
for value in value_list:
label = value#format_number(value, high=True)
self.SetCellValue(cell_row, col, str(label))
cell_row += 1
self.AutoSizeColumn(col, True)
width = self.GetColSize(col)
if width < self.default_col_width:
self.SetColSize(col, self.default_col_width)
color = self.parent.GetBackgroundColour()
self.SetCellBackgroundColour(0, col, color)
self.ForceRefresh()
[docs] def on_set_x_axis(self, event):
"""
"""
self.panel.set_xaxis(x=self.axis_value, label=self.axis_label)
[docs] def on_set_y_axis(self, event):
"""
"""
self.panel.set_yaxis(y=self.axis_value, label=self.axis_label)
[docs] def set_data(self, data_inputs, data_outputs, details, file_name):
"""
Add data to the grid
:param data_inputs: data to use from the context menu of the grid
:param data_ouputs: default columns deplayed
"""
self.file_name = file_name
self.details = details
if data_outputs is None:
data_outputs = {}
self.data_outputs = data_outputs
if data_inputs is None:
data_inputs = {}
self.data_inputs = data_inputs
self.data = {}
for item in (self.data_outputs, self.data_inputs):
self.data.update(item)
#if len(self.data) + len(self.data_inputs) +len(self.data_outputs) == 0:
# self.EnableEditing(False)
#else:
# self.EnableEditing(True)
if len(self.data_outputs) > 0:
self._cols = self.GetNumberCols()
self._rows = self.GetNumberRows()
self.col_names = self.data_outputs.keys()
self.col_names.sort()
nbr_user_cols = len(self.col_names)
#Add more columns to the grid if necessary
if nbr_user_cols > self._cols:
new_col_nbr = nbr_user_cols - self._cols + 1
self.AppendCols(new_col_nbr, True)
#Add more rows to the grid if necessary
nbr_user_row = len(self.data_outputs.values()[0])
if nbr_user_row > self._rows + 1:
new_row_nbr = nbr_user_row - self._rows + 1
self.AppendRows(new_row_nbr, True)
# add data to the grid
wx.CallAfter(self.set_grid_values)
self.ForceRefresh()
[docs] def set_grid_values(self):
"""
Set the values in grids
"""
# add data to the grid
row = 0
col = 0
cell_col = 0
for col_name in self.col_names:
# use the first row of the grid to add user defined labels
self.SetCellValue(row, col, str(col_name))
col += 1
cell_row = 1
value_list = self.data_outputs[col_name]
for value in value_list:
label = value
if issubclass(value.__class__, BatchCell):
label = value.label
try:
float(label)
label = str(label)#format_number(label, high=True)
except:
label = str(label)
self.SetCellValue(cell_row, cell_col, label)
self.AutoSizeColumn(cell_col, True)
width = self.GetColSize(cell_col)
if width < self.default_col_width:
self.SetColSize(cell_col, self.default_col_width)
cell_row += 1
cell_col += 1
if cell_row > self.max_row_touse:
self.max_row_touse = cell_row
[docs] def get_grid_view(self):
"""
Return value contained in the grid
"""
grid_view = {}
for col in xrange(self.GetNumberCols()):
label = self.GetCellValue(row=0, col=col)
label = label.strip()
if label != "":
grid_view[label] = []
for row in range(1, self.max_row_touse):
value = self.GetCellValue(row=row, col=col)
if value != "":
grid_view[label].append(value)
else:
grid_view[label].append(None)
return grid_view
[docs] def get_nofrows(self):
"""
Return number of total rows
"""
return self._rows
[docs] def on_copy(self, event):
"""
On copy event from the contextmenu
"""
self.Copy()
[docs] def on_paste(self, event):
"""
On paste event from the contextmenu
"""
if self.data == None:
self.data = {}
if self.file_name == None:
self.file_name = 'copied_data'
self.Paste()
[docs] def on_clear(self, event):
"""
Clear the cells selected
"""
self.Clear()
[docs]class Notebook(nb, PanelBase):
"""
## Internal name for the AUI manager
window_name = "Fit panel"
## Title to appear on top of the window
"""
window_caption = "Notebook "
def __init__(self, parent, manager=None, data=None, *args, **kwargs):
"""
"""
nb.__init__(self, parent, -1,
style=wx.aui.AUI_NB_WINDOWLIST_BUTTON|
wx.aui.AUI_BUTTON_DOWN|
wx.aui.AUI_NB_DEFAULT_STYLE|
wx.CLIP_CHILDREN)
PanelBase.__init__(self, parent)
self.gpage_num = 1
self.enable_close_button()
self.parent = parent
self.manager = manager
self.data = data
#add empty page
self.add_empty_page()
self.pageClosedEvent = wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE
self.Bind(self.pageClosedEvent, self.on_close_page)
[docs] def add_empty_page(self):
"""
"""
grid = GridPage(self, panel=self.parent)
self.AddPage(grid, "", True)
pos = self.GetPageIndex(grid)
title = "Table" + str(self.gpage_num)
self.SetPageText(pos, title)
self.SetSelection(pos)
self.enable_close_button()
self.gpage_num += 1
return grid , pos
[docs] def on_edit_axis(self):
"""
Return the select cell of a given selected column. Check that all cells
are from the same column
"""
pos = self.GetSelection()
grid = self.GetPage(pos)
#grid.selected_cols = [grid.GetSelectedRows()]#
if len(grid.selected_cols) >= 1:
col = grid.selected_cols[0]
for c in grid.selected_cols:
if c != col:
msg = "Edit axis doesn't understand this selection.\n"
msg += "Please select only one column"
raise ValueError, msg
for (cell_row, cell_col) in grid.selected_cells:
if cell_col != col:
msg = "Cannot use cells from different columns for "
msg += "this operation.\n"
msg += "Please select elements of the same col.\n"
raise ValueError, msg
# Finally check the highlighted cell if any cells missing
self.get_highlighted_row(True)
else:
msg = "No item selected.\n"
msg += "Please select only one column or one cell"
raise ValueError, msg
return grid.selected_cells
[docs] def get_highlighted_row(self, is_number=True):
"""
Add highlight rows
"""
pos = self.GetSelection()
grid = self.GetPage(pos)
col = grid.selected_cols[0]
# Finally check the highlighted cell if any cells missing
for row in range(grid.get_nofrows()):
if grid.IsInSelection(row, col):
cel = (row, col)
if row < 1 and not is_number:
continue
# empty cell
if not grid.GetCellValue(row, col).lstrip().rstrip():
if cel in grid.selected_cells:
grid.selected_cells.remove(cel)
continue
if is_number:
try:
float(grid.GetCellValue(row, col))
except:
# non numeric cell
if cel in grid.selected_cells:
grid.selected_cells.remove(cel)
continue
if cel not in grid.selected_cells:
grid.selected_cells.append(cel)
[docs] def get_column_labels(self):
"""
return dictionary of columns labels of the current page
"""
pos = self.GetSelection()
grid = self.GetPage(pos)
labels = {}
row = 0
for col in range(grid.GetNumberCols()):
label = grid.GetColLabelValue(int(col))
#label = grid.GetCellValue(row, col)
if label.strip() != "" :
labels[label.strip()] = col
return labels
[docs] def create_axis_label(self, cell_list):
"""
Receive a list of cells and create a string presenting the selected
cells.
:param cell_list: list of tuple
"""
pos = self.GetSelection()
grid = self.GetPage(pos)
label = ""
col_name = ""
def create_label(col_name, row_min=None, row_max=None):
"""
"""
result = " "
if row_min is not None or row_max is not None:
if row_min is None:
result = str(row_max) + "]"
elif row_max is None:
result = str(col_name) + "[" + str(row_min) + ":"
else:
result = str(col_name) + "[" + str(row_min) + ":"
result += str(row_max) + "]"
return str(result)
if len(cell_list) > 0:
if len(cell_list) == 1:
row_min, col = cell_list[0]
col_name = grid.GetColLabelValue(int(col))
col_title = grid.GetCellValue(0, col)
label = create_label(col_name, row_min+1 , row_min+1)
return label, col_title
else:
temp_list = copy.deepcopy(cell_list)
temp_list.sort()
length = len(temp_list)
row_min, col = temp_list[0]
row_max, _ = temp_list[length-1]
col_name = grid.GetColLabelValue(int(col))
col_title = grid.GetCellValue(0, col)
index = 0
for row in xrange(row_min, row_max + 1):
if index > 0 and index < len(temp_list):
new_row, _ = temp_list[index]
if row != new_row:
temp_list.insert(index, (None, None))
if index -1 >= 0:
new_row, _ = temp_list[index-1]
if not new_row == None and new_row != ' ' :
label += create_label(col_name, None,
int(new_row) +1)
else:
label += "]"
label += ","
if index + 1 < len(temp_list):
new_row, _ = temp_list[index + 1]
if not new_row==None:
label += create_label(col_name,
int(new_row)+1, None)
if row_min != None and row_max != None:
if index == 0:
label += create_label(col_name,
int(row_min)+1, None)
elif index == len(temp_list)-1:
label += create_label(col_name, None,
int(row_max)+1)
index += 1
# clean up the list
label_out = ''
for item in label.split(','):
if item.split(":")[1] == "]":
continue
else:
label_out += item + ","
return label_out, col_title
[docs] def on_close_page(self, event):
"""
close the page
"""
if self.GetPageCount() == 1:
event.Veto()
wx.CallAfter(self.enable_close_button)
[docs] def set_data(self, data_inputs, data_outputs, details="", file_name=None):
if data_outputs is None or data_outputs == {}:
return
inputs, outputs = self.get_odered_results(data_inputs, data_outputs)
for pos in range(self.GetPageCount()):
grid = self.GetPage(pos)
if grid.data is None:
#Found empty page
grid.set_data(data_inputs=inputs,
data_outputs=outputs,
details=details,
file_name=file_name)
self.SetSelection(pos)
return
grid, pos = self.add_empty_page()
grid.set_data(data_inputs=inputs,
data_outputs=outputs,
file_name=file_name,
details=details)
[docs] def get_odered_results(self, inputs, outputs=None):
"""
Get ordered the results
"""
# Let's re-order the data from the keys in 'Data' name.
if outputs == None:
return
try:
# For outputs from batch
to_be_sort = [str(item.label) for item in outputs['Data']]
except:
# When inputs are from an external file
return inputs, outputs
inds = numpy.lexsort((to_be_sort, to_be_sort))
for key in outputs.keys():
key_list = outputs[key]
temp_key = [item for item in key_list]
for ind in inds:
temp_key[ind] = key_list[inds[ind]]
outputs[key] = temp_key
for key in inputs.keys():
key_list = inputs[key]
if len(key_list) == len(inds):
temp_key = [item for item in key_list]
for ind in inds:
temp_key[ind] = key_list[inds[ind]]
inputs[key] = temp_key
else:
inputs[key] = []
#print "Different length in %s: Removed from Listing."% key
return inputs, outputs
[docs] def add_column(self):
"""
Append a new column to the grid
"""
pos = self.GetSelection()
grid = self.GetPage(pos)
grid.AppendCols(1, True)
[docs] def on_remove_column(self):
"""
Remove the selected column from the grid
"""
pos = self.GetSelection()
grid = self.GetPage(pos)
grid.on_remove_column(event=None)
[docs]class GridPanel(SPanel):
def __init__(self, parent, data_inputs=None,
data_outputs=None, *args, **kwds):
SPanel.__init__(self, parent , *args, **kwds)
self.vbox = wx.BoxSizer(wx.VERTICAL)
self.plotting_sizer = wx.FlexGridSizer(3, 7, 10, 5)
self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.grid_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.vbox.AddMany([(self.grid_sizer, 1, wx.EXPAND, 0),
(wx.StaticLine(self, -1), 0, wx.EXPAND, 0),
(self.plotting_sizer),
(self.button_sizer, 0, wx.BOTTOM, 10)])
self.parent = parent
self._data_inputs = data_inputs
self._data_outputs = data_outputs
self.x = []
self.y = []
self.dy = []
self.x_axis_label = None
self.y_axis_label = None
self.dy_axis_label = None
self.x_axis_title = None
self.y_axis_title = None
self.x_axis_unit = None
self.y_axis_unit = None
self.view_button = None
self.plot_button = None
self.notebook = None
self.plot_num = 1
self.layout_grid()
self.layout_plotting_area()
self.SetSizer(self.vbox)
[docs] def set_xaxis(self, label="", x=None):
"""
"""
if x is None:
x = []
self.x = x
self.x_axis_label.SetValue("%s[:]" % str(label))
self.x_axis_title.SetValue(str(label))
[docs] def set_yaxis(self, label="", y=None):
"""
"""
if y is None:
y = []
self.y = y
self.y_axis_label.SetValue("%s[:]" % str(label))
self.y_axis_title.SetValue(str(label))
[docs] def set_dyaxis(self, label="", dy=None):
"""
"""
if dy is None:
dy = []
self.dy = dy
self.dy_axis_label.SetValue("%s[:]" % str(label))
[docs] def get_plot_axis(self, col, list):
"""
"""
axis = []
pos = self.notebook.GetSelection()
grid = self.notebook.GetPage(pos)
for row in list:
label = grid.GetCellValue(0, col)
value = grid.GetCellValue(row - 1, col).strip()
if value != "":
if label.lower().strip() == "data":
axis.append(float(row - 1))
else:
try:
axis.append(float(value))
except:
msg = "Invalid data in row %s column %s" % (str(row),
str(col))
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg, info="error"))
return None
else:
axis.append(None)
return axis
[docs] def on_view(self, event):
"""
Get object represented buy the given cell and plot them.
"""
pos = self.notebook.GetSelection()
grid = self.notebook.GetPage(pos)
title = self.notebook.GetPageText(pos)
self.notebook.get_highlighted_row(False)
if len(grid.selected_cells) == 0:
msg = "Highlight a Data or Chi2 column first..."
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg, info="error"))
return
elif len(grid.selected_cells) > 20:
msg = "Too many data (> 20) to plot..."
msg += "\n Please select no more than 20 data."
dial = wx.MessageDialog(self, msg, 'Plotting', wx.OK)
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg, info="error"))
return
for cell in grid.selected_cells:
row, col = cell
label_row = 0
label = grid.GetCellValue(label_row, col)
if label in grid.data:
values = grid.data[label]
if row > len(values) or row < 1:
msg = "Invalid cell was chosen."
wx.PostEvent(self.parent.parent, StatusEvent(status=msg,
info="error"))
continue
else:
value = values[row -1]
if issubclass(value.__class__, BatchCell):
if value.object is None or len(value.object) == 0:
msg = "Row %s , " % str(row)
msg += "Column %s is NOT " % str(label)
msg += "the results of fits to view..."
#raise ValueError, msg
wx.PostEvent(self.parent.parent, StatusEvent(status=msg,
info="error"))
return
for new_plot in value.object:
if new_plot is None or \
not issubclass(new_plot.__class__,
plottables.Plottable):
msg = "Row %s , " % str(row)
msg += "Column %s is NOT " % str(label)
msg += "the results of fits to view..."
#raise ValueError, msg
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg, info="error"))
return
#continue
#new_plot.name = title + ': ' + new_plot.title
if issubclass(new_plot.__class__, Data1D):
if label in grid.list_plot_panels.keys():
group_id = grid.list_plot_panels[label]
else:
group_id = str(new_plot.group_id) + str(grid.uid)
grid.list_plot_panels[label] = group_id
if group_id not in new_plot.list_group_id:
new_plot.group_id = group_id
new_plot.list_group_id.append(group_id)
else:
if label.lower() in ["data", "chi2"]:
if len(grid.selected_cells) != 1:
msg = "2D View: Please select one data set"
msg += " at a time for View Fit Results."
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg,
info="error"))
return
wx.PostEvent(self.parent.parent,
NewPlotEvent(plot=new_plot,
group_id=str(new_plot.group_id),
title=title))
msg = "Plotting the View Fit Results completed!"
wx.PostEvent( self.parent.parent,
StatusEvent(status=msg))
else:
msg = "Row %s , " % str(row)
msg += "Column %s is NOT " % str(label)
msg += "the results of fits to view..."
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg, info="error"))
return
[docs] def on_plot(self, event):
"""
Evaluate the contains of textcrtl and plot result
"""
pos = self.notebook.GetSelection()
grid = self.notebook.GetPage(pos)
column_names = {}
if grid is not None:
column_names = self.notebook.get_column_labels()
#evaluate x
sentence = self.x_axis_label.GetValue()
try:
if sentence.strip() == "":
msg = "Select column values for x axis"
raise ValueError, msg
except:
msg = "X axis value error."
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg, info="error"))
return
dict = parse_string(sentence, column_names.keys())
try:
sentence = self.get_sentence(dict, sentence, column_names)
x = eval(sentence)
except:
msg = "Need a proper x-range."
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg, info="error"))
return
#evaluate y
sentence = self.y_axis_label.GetValue()
try:
if sentence.strip() == "":
msg = "select value for y axis"
raise ValueError, msg
except:
msg = "Y axis value error."
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg, info="error"))
return
dict = parse_string(sentence, column_names.keys())
try:
sentence = self.get_sentence(dict, sentence, column_names)
y = eval(sentence)
except:
msg = "Need a proper y-range."
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg, info="error"))
return
#evaluate y
sentence = self.dy_axis_label.GetValue()
dy = None
if sentence.strip() != "":
dict = parse_string(sentence, column_names.keys())
sentence = self.get_sentence(dict, sentence, column_names)
try:
dy = eval(sentence)
except:
msg = "Need a proper dy-range."
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg, info="error"))
return
if len(x) != len(y) or (len(x) == 0 or len(y) == 0):
msg = "Need same length for X and Y axis and both greater than 0"
msg += " to plot.\n"
msg += "Got X length = %s, Y length = %s" % (str(len(x)),
str(len(y)))
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg, info="error"))
return
if dy != None and (len(y) != len(dy)):
msg = "Need same length for Y and dY axis and both greater than 0"
msg += " to plot.\n"
msg += "Got Y length = %s, dY length = %s" % (str(len(y)),
str(len(dy)))
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg, info="error"))
return
if dy == None:
dy = numpy.zeros(len(y))
#plotting
new_plot = Data1D(x=x, y=y, dy=dy)
new_plot.id = wx.NewId()
new_plot.is_data = False
new_plot.group_id = wx.NewId()
y_title = self.y_axis_title.GetValue()
x_title = self.x_axis_title.GetValue()
title = "%s_vs_%s" % (y_title,
x_title)
new_plot.xaxis(x_title,
self.x_axis_unit.GetValue())
new_plot.yaxis(y_title,
self.y_axis_unit.GetValue())
try:
title = y_title.strip()
title += "_" + self.notebook.GetPageText(pos)
title += "_" + str(self.plot_num)
self.plot_num += 1
new_plot.name = title
new_plot.xtransform = "x"
new_plot.ytransform = "y"
#new_plot.is_data = False
wx.PostEvent(self.parent.parent,
NewPlotEvent(plot=new_plot,
group_id=str(new_plot.group_id), title =title))
msg = "Plotting completed!"
wx.PostEvent( self.parent.parent,
StatusEvent(status=msg))
self.parent.parent.update_theory(data_id=new_plot.id,
theory=new_plot)
except:
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg, info="error"))
[docs] def get_sentence(self, dict, sentence, column_names):
"""
Get sentence from dict
"""
for tok, (col_name, list) in dict.iteritems():
col = column_names[col_name]
axis = self.get_plot_axis(col, list)
if axis == None:
return None
sentence = sentence.replace(tok,
"numpy.array(%s)" % str(axis))
for key, value in FUNC_DICT.iteritems():
sentence = sentence.replace(key.lower(), value)
return sentence
[docs] def layout_grid(self):
"""
Draw the area related to the grid
"""
self.notebook = Notebook(parent=self)
self.notebook.set_data(self._data_inputs, self._data_outputs)
self.grid_sizer.Add(self.notebook, 1, wx.EXPAND, 0)
[docs] def layout_plotting_area(self):
"""
Draw area containing options to plot
"""
view_description = wx.StaticBox(self, -1, 'Plot Fits/Residuals')
note = "To plot the fits (or residuals), click the 'View Fits' button"
note += "\n after highlighting the Data names (or Chi2 values)."
note_text = wx.StaticText(self, -1, note)
boxsizer1 = wx.StaticBoxSizer(view_description, wx.HORIZONTAL)
self.x_axis_title = wx.TextCtrl(self, -1)
self.y_axis_title = wx.TextCtrl(self, -1)
self.x_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
self.y_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
self.dy_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
self.x_axis_add = wx.Button(self, -1, "Add")
self.x_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis,
id=self.x_axis_add.GetId())
self.y_axis_add = wx.Button(self, -1, "Add")
self.y_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis,
id=self.y_axis_add.GetId())
self.dy_axis_add = wx.Button(self, -1, "Add")
self.dy_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis,
id=self.dy_axis_add.GetId())
self.x_axis_unit = wx.TextCtrl(self, -1)
self.y_axis_unit = wx.TextCtrl(self, -1)
self.view_button = wx.Button(self, -1, "View Fits")
view_tip = "Highlight the data set or the Chi2 column first."
self.view_button.SetToolTipString(view_tip)
wx.EVT_BUTTON(self, self.view_button.GetId(), self.on_view)
self.plot_button = wx.Button(self, -1, "Plot")
plot_tip = "Highlight a column for each axis and \n"
plot_tip += "click the Add buttons first."
self.plot_button.SetToolTipString(plot_tip)
boxsizer1.AddMany([(note_text, 0, wx.LEFT, 10),
(self.view_button, 0, wx.LEFT|wx.RIGHT, 10)])
self.button_sizer.AddMany([(boxsizer1, 0,
wx.LEFT|wx.RIGHT|wx.BOTTOM, 10),
(self.plot_button, 0,
wx.LEFT|wx.TOP|wx.BOTTOM|wx.EXPAND, 12)])
wx.EVT_BUTTON(self, self.plot_button.GetId(), self.on_plot)
self.plotting_sizer.AddMany([
(wx.StaticText(self, -1,
"X-axis Label\nSelection Range"), 1,
wx.TOP|wx.BOTTOM|wx.LEFT, 10),
(self.x_axis_label, 1, wx.TOP|wx.BOTTOM, 10),
(self.x_axis_add, 1, wx.TOP|wx.BOTTOM|wx.RIGHT, 10),
(wx.StaticText(self, -1, "X-axis Label"), 1,
wx.TOP|wx.BOTTOM|wx.LEFT, 10),
(self.x_axis_title, 1, wx.TOP|wx.BOTTOM, 10),
(wx.StaticText(self, -1 , "X-axis Unit"), 1,
wx.TOP|wx.BOTTOM, 10),
(self.x_axis_unit, 1, wx.TOP|wx.BOTTOM, 10),
(wx.StaticText(self, -1,
"Y-axis Label\nSelection Range"), 1,
wx.BOTTOM|wx.LEFT, 10),
(self.y_axis_label, wx.BOTTOM, 10),
(self.y_axis_add, 1, wx.BOTTOM|wx.RIGHT, 10),
(wx.StaticText(self, -1, "Y-axis Label"), 1,
wx.BOTTOM|wx.LEFT, 10),
(self.y_axis_title, wx.BOTTOM, 10),
(wx.StaticText(self, -1 , "Y-axis Unit"), 1, wx.BOTTOM, 10),
(self.y_axis_unit, 1, wx.BOTTOM, 10),
(wx.StaticText(self, -1,
"dY-Bar (Optional)\nSelection Range"),
1, wx.BOTTOM|wx.LEFT, 10),
(self.dy_axis_label, wx.BOTTOM, 10),
(self.dy_axis_add, 1, wx.BOTTOM|wx.RIGHT, 10),
(-1, -1),
(-1, -1),
(-1, -1),
#(-1, -1),
#(-1, -1),
#(-1, -1),
(-1, 1)])
[docs] def on_edit_axis(self, event):
"""
Get the selected column on the visible grid and set values for axis
"""
try:
cell_list = self.notebook.on_edit_axis()
label, title = self.create_axis_label(cell_list)
except:
msg = str(sys.exc_value)
wx.PostEvent(self.parent.parent,
StatusEvent(status=msg, info="error"))
return
tcrtl = event.GetEventObject()
if tcrtl == self.x_axis_add:
self.edit_axis_helper(self.x_axis_label, self.x_axis_title,
label, title)
elif tcrtl == self.y_axis_add:
self.edit_axis_helper(self.y_axis_label, self.y_axis_title,
label, title)
elif tcrtl == self.dy_axis_add:
self.edit_axis_helper(self.dy_axis_label, None,
label, None)
[docs] def create_axis_label(self, cell_list):
"""
Receive a list of cells and create a string presenting the selected
cells.
:param cell_list: list of tuple
"""
if self.notebook is not None:
return self.notebook.create_axis_label(cell_list)
[docs] def edit_axis_helper(self, tcrtl_label, tcrtl_title, label, title):
"""
get controls to modify
"""
if label != None:
tcrtl_label.SetValue(str(label))
if title != None:
tcrtl_title.SetValue(str(title))
[docs] def add_column(self):
"""
"""
if self.notebook is not None:
self.notebook.add_column()
[docs] def on_remove_column(self):
"""
"""
if self.notebook is not None:
self.notebook.on_remove_column()
[docs]class GridFrame(wx.Frame):
def __init__(self, parent=None, data_inputs=None, data_outputs=None, id=-1,
title="Grid Window", size=(800, 500)):
wx.Frame.__init__(self, parent=parent, id=id, title=title, size=size)
self.parent = parent
self.panel = GridPanel(self, data_inputs, data_outputs)
menubar = wx.MenuBar()
self.SetMenuBar(menubar)
self.curr_col = None
self.curr_grid = None
self.curr_col_name = ""
self.file = wx.Menu()
menubar.Append(self.file, "&File")
hint = "Open file containing batch results"
open_menu = self.file.Append(wx.NewId(), 'Open ', hint)
wx.EVT_MENU(self, open_menu.GetId(), self.on_open)
hint = "Open the the current grid into excel"
self.open_excel_menu = self.file.Append(wx.NewId(), 'Open with Excel', hint)
wx.EVT_MENU(self, self.open_excel_menu.GetId(), self.open_with_excel)
self.file.AppendSeparator()
self.save_menu = self.file.Append(wx.NewId(), 'Save As', 'Save into File')
wx.EVT_MENU(self, self.save_menu.GetId(), self.on_save_page)
self.edit = wx.Menu()
add_table_menu = self.edit.Append(-1, 'New Table',
'Add a New Table')
self.edit.AppendSeparator()
wx.EVT_MENU(self, add_table_menu.GetId(), self.add_table)
self.copy_menu = self.edit.Append(-1, 'Copy',
'Copy the selected cells')
wx.EVT_MENU(self, self.copy_menu.GetId(), self.on_copy)
self.paste_menu = self.edit.Append(-1, 'Paste',
'Paste the selected Cells')
wx.EVT_MENU(self, self.paste_menu.GetId(), self.on_paste)
self.clear_menu = self.edit.Append(-1, 'Clear',
'Clear the selected Cells')
wx.EVT_MENU(self, self.clear_menu.GetId(), self.on_clear)
self.edit.AppendSeparator()
hint = "Insert column before the selected column"
self.insert_before_menu = wx.Menu()
self.insertb_sub_menu = self.edit.AppendSubMenu(self.insert_before_menu,
'Insert Before', hint)
hint = "Insert column after the selected column"
self.insert_after_menu = wx.Menu()
self.inserta_sub_menu = self.edit.AppendSubMenu(self.insert_after_menu,
'Insert After', hint)
hint = "Remove the selected column"
self.remove_menu = self.edit.Append(-1, 'Remove Column', hint)
wx.EVT_MENU(self, self.remove_menu.GetId(), self.on_remove_column)
self.Bind(wx.EVT_MENU_OPEN, self.on_menu_open)
menubar.Append(self.edit, "&Edit")
self.Bind(wx.EVT_CLOSE, self.on_close)
[docs] def on_copy(self, event):
"""
On Copy
"""
if event != None:
event.Skip()
pos = self.panel.notebook.GetSelection()
grid = self.panel.notebook.GetPage(pos)
grid.Copy()
[docs] def on_paste(self, event):
"""
On Paste
"""
if event != None:
event.Skip()
pos = self.panel.notebook.GetSelection()
grid = self.panel.notebook.GetPage(pos)
grid.on_paste(None)
[docs] def on_clear(self, event):
"""
On Clear
"""
pos = self.panel.notebook.GetSelection()
grid = self.panel.notebook.GetPage(pos)
grid.Clear()
[docs] def GetLabelText(self, id):
"""
Get Label Text
"""
for item in self.insert_before_menu.GetMenuItems():
m_id = item.GetId()
if m_id == id:
return item.GetLabel()
[docs] def on_remove_column(self, event):
"""
On remove column
"""
pos = self.panel.notebook.GetSelection()
grid = self.panel.notebook.GetPage(pos)
grid.on_remove_column(event=None)
[docs] def on_save_page(self, event):
"""
"""
if self.parent is not None:
pos = self.panel.notebook.GetSelection()
grid = self.panel.notebook.GetPage(pos)
if grid.file_name is None or grid.file_name.strip() == "" or \
grid.data is None or len(grid.data) == 0:
name = self.panel.notebook.GetPageText(pos)
msg = " %s has not data to save" % str(name)
wx.PostEvent(self.parent,
StatusEvent(status=msg, info="error"))
return
reader, ext = os.path.splitext(grid.file_name)
path = None
if self.parent is not None:
location = os.path.dirname(grid.file_name)
dlg = wx.FileDialog(self, "Save Project file",
location, grid.file_name, ext, wx.SAVE)
path = None
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
dlg.Destroy()
if path != None:
if self.parent is not None:
data = grid.get_grid_view()
self.parent.write_batch_tofile(data=data,
file_name=path,
details=grid.details)
[docs] def on_open(self, event):
"""
Open file containg batch result
"""
if self.parent is not None:
self.parent.on_read_batch_tofile(self)
[docs] def open_with_excel(self, event):
"""
open excel and display batch result in Excel
"""
if self.parent is not None:
pos = self.panel.notebook.GetSelection()
grid = self.panel.notebook.GetPage(pos)
data = grid.get_grid_view()
if grid.file_name is None or grid.file_name.strip() == "" or \
grid.data is None or len(grid.data) == 0:
name = self.panel.notebook.GetPageText(pos)
msg = " %s has not data to open on excel" % str(name)
wx.PostEvent(self.parent,
StatusEvent(status=msg, info="error"))
return
self.parent.open_with_externalapp(data=data,
file_name=grid.file_name,
details=grid.details)
[docs] def on_close(self, event):
"""
"""
self.Hide()
[docs] def on_append_column(self, event):
"""
Append a new column to the grid
"""
self.panel.add_column()
[docs] def set_data(self, data_inputs, data_outputs, details="", file_name=None):
"""
Set data
"""
self.panel.notebook.set_data(data_inputs=data_inputs,
file_name=file_name,
details=details,
data_outputs=data_outputs)
[docs] def add_table(self, event):
"""
Add a new table
"""
# DO not event.Skip(): it will make 2 pages
self.panel.notebook.add_empty_page()
[docs]class BatchOutputFrame(wx.Frame):
"""
Allow to select where the result of batch will be displayed or stored
"""
def __init__(self, parent, data_inputs, data_outputs, file_name="",
details="", *args, **kwds):
"""
:param parent: Window instantiating this dialog
:param result: result to display in a grid or export to an external
application.
"""
#kwds['style'] = wx.CAPTION|wx.SYSTEM_MENU
wx.Frame.__init__(self, parent, *args, **kwds)
self.parent = parent
self.panel = wx.Panel(self)
self.file_name = file_name
self.details = details
self.data_inputs = data_inputs
self.data_outputs = data_outputs
self.data = {}
for item in (self.data_outputs, self.data_inputs):
self.data.update(item)
self.flag = 1
self.SetSize((300, 200))
self.local_app_selected = None
self.external_app_selected = None
self.save_to_file = None
self._do_layout()
def _do_layout(self):
"""
Draw the content of the current dialog window
"""
vbox = wx.BoxSizer(wx.VERTICAL)
box_description = wx.StaticBox(self.panel, -1, str("Batch Outputs"))
hint_sizer = wx.StaticBoxSizer(box_description, wx.VERTICAL)
selection_sizer = wx.GridBagSizer(5, 5)
button_sizer = wx.BoxSizer(wx.HORIZONTAL)
text = "Open with %s" % self.parent.application_name
self.local_app_selected = wx.RadioButton(self.panel, -1, text,
style=wx.RB_GROUP)
self.Bind(wx.EVT_RADIOBUTTON, self.onselect,
id=self.local_app_selected.GetId())
text = "Open with Excel"
self.external_app_selected = wx.RadioButton(self.panel, -1, text)
self.Bind(wx.EVT_RADIOBUTTON, self.onselect,
id=self.external_app_selected.GetId())
text = "Save to File"
self.save_to_file = wx.CheckBox(self.panel, -1, text)
self.Bind(wx.EVT_CHECKBOX, self.onselect,
id=self.save_to_file.GetId())
self.local_app_selected.SetValue(True)
self.external_app_selected.SetValue(False)
self.save_to_file.SetValue(False)
button_close = wx.Button(self.panel, -1, "Close")
button_close.Bind(wx.EVT_BUTTON, id=button_close.GetId(),
handler=self.on_close)
button_apply = wx.Button(self.panel, -1, "Apply")
button_apply.Bind(wx.EVT_BUTTON, id=button_apply.GetId(),
handler=self.on_apply)
button_apply.SetFocus()
hint = ""
hint_sizer.Add(wx.StaticText(self.panel, -1, hint))
hint_sizer.Add(selection_sizer)
#draw area containing radio buttons
ix = 0
iy = 0
selection_sizer.Add(self.local_app_selected, (iy, ix),
(1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
iy += 1
selection_sizer.Add(self.external_app_selected, (iy, ix),
(1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
iy += 1
selection_sizer.Add(self.save_to_file, (iy, ix),
(1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
#contruction the sizer contaning button
button_sizer.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
button_sizer.Add(button_close, 0,
wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
button_sizer.Add(button_apply, 0,
wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
vbox.Add(hint_sizer, 0, wx.EXPAND|wx.ALL, 10)
vbox.Add(wx.StaticLine(self.panel, -1), 0, wx.EXPAND, 0)
vbox.Add(button_sizer, 0, wx.TOP|wx.BOTTOM, 10)
self.SetSizer(vbox)
[docs] def on_apply(self, event):
"""
Get the user selection and display output to the selected application
"""
if self.flag == 1:
self.parent.open_with_localapp(data_inputs=self.data_inputs,
data_outputs=self.data_outputs)
elif self.flag == 2:
self.parent.open_with_externalapp(data=self.data,
file_name=self.file_name,
details=self.details)
[docs] def on_close(self, event):
"""
close the Window
"""
self.Close()
[docs] def onselect(self, event=None):
"""
Receive event and display data into third party application
or save data to file.
"""
if self.save_to_file.GetValue():
reader, ext = os.path.splitext(self.file_name)
path = None
location = os.getcwd()
if self.parent is not None:
location = os.path.dirname(self.file_name)
dlg = wx.FileDialog(self, "Save Project file",
location, self.file_name, ext, wx.SAVE)
path = None
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
dlg.Destroy()
if path != None:
if self.parent is not None and self.data is not None:
self.parent.write_batch_tofile(data=self.data,
file_name=path,
details=self.details)
if self.local_app_selected.GetValue():
self.flag = 1
else:
self.flag = 2
return self.flag
if __name__ == "__main__":
app = wx.App()
try:
data = {}
j = 0
for i in range(4):
j += 1
data["index"+str(i)] = [i/j, i*j, i, i+j]
data_input = copy.deepcopy(data)
data_input["index5"] = [10, 20, 40, 50]
frame = GridFrame(data_outputs=data, data_inputs=data_input)
frame.Show(True)
except:
print sys.exc_value
app.MainLoop()