class DataSourcePanel(wx.Panel): ''' A panel with controls for selecting the source data for a histogramplot ''' def __init__(self, parent, figpanel, **kwargs): wx.Panel.__init__(self, parent, **kwargs) # the panel to draw charts on self.SetBackgroundColour('white') # color for the background of panel self.figpanel = figpanel sizer = wx.BoxSizer(wx.VERTICAL) self.table_choice = ui.TableComboBox(self, -1, style=wx.CB_READONLY) self.x_choice = ComboBox(self, -1, size=(200, -1), choices=[''], style=wx.CB_READONLY) self.x_choice.Select(0) self.bins_input = wx.SpinCtrl(self, -1, '100') self.bins_input.SetRange(1, 400) self.x_scale_choice = ComboBox( self, -1, choices=[LINEAR_SCALE, LOG_SCALE, LOG2_SCALE], style=wx.CB_READONLY) self.x_scale_choice.Select(0) self.y_scale_choice = ComboBox(self, -1, choices=[LINEAR_SCALE, LOG_SCALE], style=wx.CB_READONLY) self.y_scale_choice.Select(0) self.filter_choice = ui.FilterComboBox(self, style=wx.CB_READONLY) self.filter_choice.Select(0) self.gate_choice = ui.GateComboBox(self, style=wx.CB_READONLY) self.gate_choice.set_gatable_columns([self.x_column]) self.update_chart_btn = wx.Button(self, -1, "Update Chart") self.update_column_fields() sz = wx.BoxSizer(wx.HORIZONTAL) sz.Add(wx.StaticText(self, -1, "x-axis:"), 0, wx.TOP, 4) sz.AddSpacer((2, -1)) sz.Add(self.table_choice, 1, wx.EXPAND) sz.AddSpacer((3, -1)) sz.Add(self.x_choice, 2, wx.EXPAND) sizer.Add(sz, 1, wx.EXPAND) sizer.AddSpacer((-1, 2)) sz = wx.BoxSizer(wx.HORIZONTAL) sz.Add(wx.StaticText(self, -1, "x-scale:"), 0, wx.TOP, 4) sz.AddSpacer((2, -1)) sz.Add(self.x_scale_choice, 1, wx.EXPAND) sz.AddSpacer((5, -1)) sz.Add(wx.StaticText(self, -1, "y-scale:"), 0, wx.TOP, 4) sz.AddSpacer((2, -1)) sz.Add(self.y_scale_choice, 1, wx.EXPAND) sz.AddSpacer((5, -1)) sz.Add(wx.StaticText(self, -1, "bins:"), 0, wx.TOP, 4) sz.AddSpacer((2, -1)) sz.Add(self.bins_input) sizer.Add(sz, 1, wx.EXPAND) sizer.AddSpacer((-1, 2)) sz = wx.BoxSizer(wx.HORIZONTAL) sz.Add(wx.StaticText(self, -1, "filter:"), 0, wx.TOP, 4) sz.AddSpacer((2, -1)) sz.Add(self.filter_choice, 1, wx.EXPAND) sz.AddSpacer((5, -1)) sz.Add(wx.StaticText(self, -1, "gate:"), 0, wx.TOP, 4) sz.AddSpacer((2, -1)) sz.Add(self.gate_choice, 1, wx.EXPAND) sizer.Add(sz, 1, wx.EXPAND) sizer.AddSpacer((-1, 2)) sizer.Add(self.update_chart_btn) wx.EVT_COMBOBOX(self.table_choice, -1, self.on_table_selected) wx.EVT_BUTTON(self.update_chart_btn, -1, self.update_figpanel) self.gate_choice.addobserver(self.on_gate_selected) self.SetSizer(sizer) self.Show(1) @property def x_column(self): return sql.Column( self.table_choice.GetString(self.table_choice.GetSelection()), self.x_choice.GetString(self.x_choice.GetSelection())) @property def filter(self): return self.filter_choice.get_filter_or_none() def on_table_selected(self, evt): table = self.table_choice.Value if table == ui.TableComboBox.OTHER_TABLE: t = ui.get_other_table_from_user(self) if t is not None: self.table_choice.Items = self.table_choice.Items[:-1] + [ t ] + self.table_choice.Items[-1:] self.table_choice.Select(self.table_choice.Items.index(t)) else: self.table_choice.Select(0) return self.update_column_fields() def on_gate_selected(self, gate_name): self.update_gate_helper() def update_gate_helper(self): gate_name = self.gate_choice.get_gatename_or_none() if gate_name: self.figpanel.gate_helper.set_displayed_gate( p.gates[gate_name], self.x_column, None) else: self.figpanel.gate_helper.disable() def update_column_fields(self): tablename = self.table_choice.GetString( self.table_choice.GetSelection()) fieldnames = self.get_numeric_columns_from_table(tablename) self.x_choice.Clear() self.x_choice.AppendItems(fieldnames) self.x_choice.SetSelection(0) def get_numeric_columns_from_table(self, table): ''' Fetches names of numeric columns for the given table. ''' measurements = db.GetColumnNames(table) types = db.GetColumnTypes(table) return [ m for m, t in zip(measurements, types) if t in [float, int, long] ] def _plotting_per_object_data(self): return (p.object_table and p.object_table in [self.x_column.table, self.x_column.table] or (self.x_column.table != p.image_table and db.adjacent(p.object_table, self.x_column.table))) def update_figpanel(self, evt=None): self.gate_choice.set_gatable_columns([self.x_column]) points = self._load_points() bins = int(self.bins_input.GetValue()) self.figpanel.set_x_label(self.x_column.col) self.figpanel.set_x_scale( self.x_scale_choice.GetString(self.x_scale_choice.GetSelection())) self.figpanel.set_y_scale( self.y_scale_choice.GetString(self.y_scale_choice.GetSelection())) self.figpanel.setpoints(points, bins) self.update_gate_helper() self.figpanel.draw() def _load_points(self): q = sql.QueryBuilder() select = [self.x_column] q.set_select_clause(select) if self.filter is not None: q.add_filter(self.filter) return np.array(db.execute(str(q))).T[0] def save_settings(self): '''save_settings is called when saving a workspace to file. returns a dictionary mapping setting names to values encoded as strings ''' d = { 'table': self.table_choice.GetString(self.table_choice.GetSelection()), 'x-axis': self.x_choice.GetString(self.x_choice.GetSelection()), 'bins': self.bins_input.GetValue(), 'x-scale': self.x_scale_choice.GetString(self.x_scale_choice.GetSelection()), 'y-scale': self.y_scale_choice.GetString(self.y_scale_choice.GetSelection()), 'filter': self.filter_choice.GetString(self.filter_choice.GetSelection()), 'x-lim': self.figpanel.subplot.get_xlim(), 'y-lim': self.figpanel.subplot.get_ylim(), } if self.gate_choice.get_gatename_or_none(): d['gate'] = self.gate_choice.GetString( self.gate_choice.GetSelection()) return d def load_settings(self, settings): '''load_settings is called when loading a workspace from file. settings - a dictionary mapping setting names to values encoded as strings. ''' if 'table' in settings: self.table_choice.SetStringSelection(settings['table']) self.update_column_fields() if 'x-axis' in settings: self.x_choice.SetStringSelection(settings['x-axis']) if 'bins' in settings: self.bins_input.SetValue(int(settings['bins'])) if 'x-scale' in settings: self.x_scale_choice.SetStringSelection(settings['x-scale']) if 'y-scale' in settings: self.y_scale_choice.SetStringSelection(settings['y-scale']) if 'filter' in settings: self.filter_choice.SetStringSelection(settings['filter']) self.update_figpanel() if 'x-lim' in settings: self.figpanel.subplot.set_xlim(eval(settings['x-lim'])) if 'y-lim' in settings: self.figpanel.subplot.set_ylim(eval(settings['y-lim'])) if 'gate' in settings: self.gate_choice.SetStringSelection(settings['gate']) self.figpanel.gate_helper.set_displayed_gate( p.gates[settings['gate']], self.x_column, None) self.figpanel.draw()
class DataSourcePanel(wx.Panel): ''' A panel with controls for selecting the source data for a boxplot ''' def __init__(self, parent, figpanel, **kwargs): wx.Panel.__init__(self, parent, **kwargs) # the panel to draw charts on self.SetBackgroundColour('white') # color for the background of panel self.figpanel = figpanel sizer = wx.BoxSizer(wx.VERTICAL) self.x_columns = [] # column names to plot if selecting multiple columns self.table_choice = ui.TableComboBox(self, -1, style=wx.CB_READONLY) self.x_choice = ComboBox(self, -1, size=(200,-1)) self.x_multiple = wx.Button(self, -1, 'select multiple') self.group_choice = ComboBox(self, -1, choices=[NO_GROUP]+p._groups_ordered, style=wx.CB_READONLY) self.group_choice.Select(0) self.filter_choice = ui.FilterComboBox(self, style=wx.CB_READONLY) self.filter_choice.Select(0) self.update_chart_btn = wx.Button(self, -1, "Update Chart") self.update_column_fields() sz = wx.BoxSizer(wx.HORIZONTAL) sz.Add(wx.StaticText(self, -1, "table:"), 0, wx.TOP, 4) sz.AddSpacer((3,-1)) sz.Add(self.table_choice, 1, wx.EXPAND) sz.AddSpacer((3,-1)) sz.Add(wx.StaticText(self, -1, "measurement:"), 0, wx.TOP, 4) sz.AddSpacer((3,-1)) sz.Add(self.x_choice, 2, wx.EXPAND) sz.AddSpacer((3,-1)) sz.Add(self.x_multiple, 0, wx.EXPAND|wx.TOP, 2) sizer.Add(sz, 1, wx.EXPAND) sizer.AddSpacer((-1,3)) sz = wx.BoxSizer(wx.HORIZONTAL) sz.Add(wx.StaticText(self, -1, "group x-axis by:"), 0, wx.TOP, 4) sz.AddSpacer((3,-1)) sz.Add(self.group_choice, 1, wx.EXPAND) sizer.Add(sz, 1, wx.EXPAND) sizer.AddSpacer((-1,3)) sz = wx.BoxSizer(wx.HORIZONTAL) sz.Add(wx.StaticText(self, -1, "filter:"), 0, wx.TOP, 4) sz.AddSpacer((3,-1)) sz.Add(self.filter_choice, 1, wx.EXPAND) sizer.Add(sz, 1, wx.EXPAND) sizer.AddSpacer((-1,3)) sizer.Add(self.update_chart_btn) wx.EVT_BUTTON(self.x_multiple, -1, self.on_select_multiple) wx.EVT_COMBOBOX(self.table_choice, -1, self.on_table_selected) wx.EVT_COMBOBOX(self.x_choice, -1, self.on_column_selected) wx.EVT_BUTTON(self.update_chart_btn, -1, self.update_figpanel) self.SetSizer(sizer) self.Show(1) def on_select_multiple(self, evt): tablename = self.table_choice.GetString(self.table_choice.GetSelection()) column_names = self.get_numeric_columns_from_table(tablename) dlg = wx.MultiChoiceDialog(self, 'Select the columns you would like to plot', 'Select Columns', column_names) dlg.SetSelections([column_names.index(v) for v in self.x_columns]) if (dlg.ShowModal() == wx.ID_OK): self.x_choice.SetValue(SELECT_MULTIPLE) self.x_columns = [column_names[i] for i in dlg.GetSelections()] self.group_choice.Disable() self.group_choice.SetStringSelection(NO_GROUP) def on_table_selected(self, evt): table = self.table_choice.Value if table == ui.TableComboBox.OTHER_TABLE: t = ui.get_other_table_from_user(self) if t is not None: self.table_choice.Items = self.table_choice.Items[:-1] + [t] + self.table_choice.Items[-1:] self.table_choice.Select(self.table_choice.Items.index(t)) else: self.table_choice.Select(0) return self.group_choice.Enable() self.x_columns = [] self.update_column_fields() def on_column_selected(self, evt): self.group_choice.Enable() def update_column_fields(self): tablename = self.table_choice.GetString(self.table_choice.GetSelection()) fieldnames = self.get_numeric_columns_from_table(tablename) self.x_choice.Clear() self.x_choice.AppendItems(fieldnames) self.x_choice.SetSelection(0) def get_numeric_columns_from_table(self, table): ''' Fetches names of numeric columns for the given table. ''' measurements = db.GetColumnNames(table) types = db.GetColumnTypes(table) return [m for m,t in zip(measurements, types) if t in [float, int, long]] def update_figpanel(self, evt=None): table = self.table_choice.Value fltr = self.filter_choice.get_filter_or_none() grouping = self.group_choice.Value if self.x_choice.Value == SELECT_MULTIPLE: points_dict = {} for col in self.x_columns: pts = self.loadpoints(table, col, fltr, NO_GROUP) for k in pts.keys(): assert k not in points_dict.keys() points_dict.update(pts) else: col = self.x_choice.Value points_dict = self.loadpoints(table, col, fltr, grouping) # Check if the user is creating a plethora of plots by accident if 100 >= len(points_dict) > 25: res = wx.MessageDialog(self, 'Are you sure you want to show %s box ' 'plots on one axis?'%(len(points_dict)), 'Warning', style=wx.YES_NO|wx.NO_DEFAULT ).ShowModal() if res != wx.ID_YES: return elif len(points_dict) > 100: wx.MessageBox('Sorry, boxplot can not show more than 100 plots on\n' 'a single axis. Your current settings would plot %d.\n' 'Try using a filter to narrow your query.' %(len(points_dict)), 'Too many groups to plot') return self.figpanel.setpoints(points_dict) if self.group_choice.Value != NO_GROUP: self.figpanel.set_x_axis_label(grouping) self.figpanel.set_y_axis_label(self.x_choice.Value) self.figpanel.draw() def loadpoints(self, tablename, col, fltr=None, grouping=NO_GROUP): ''' Returns a dict mapping x label values to lists of values from col ''' q = sql.QueryBuilder() select = [sql.Column(tablename, col)] if grouping != NO_GROUP: dm = datamodel.DataModel.getInstance() group_cols = dm.GetGroupColumnNames(grouping, include_table_name=True) select += [sql.Column(*col.split('.')) for col in group_cols] q.set_select_clause(select) if fltr is not None: q.add_filter(fltr) res = db.execute(str(q)) res = np.array(res, dtype=object) # replaces Nones with NaNs for row in res: if row[0] is None: row[0] = np.nan points_dict = {} if self.group_choice.Value != NO_GROUP: for row in res: groupkey = tuple(row[1:]) points_dict[groupkey] = points_dict.get(groupkey, []) + [row[0]] else: points_dict = {col : [r[0] for r in res]} return points_dict def save_settings(self): ''' Called when saving a workspace to file. returns a dictionary mapping setting names to values encoded as strings ''' if self.x_choice.Value == SELECT_MULTIPLE: cols = self.x_columns else: cols = [self.x_choice.GetString(self.x_choice.GetSelection())] return {'table' : self.table_choice.Value, 'x-axis' : ','.join(cols), 'filter' : self.filter_choice.Value, 'x-lim' : self.figpanel.subplot.get_xlim(), 'y-lim' : self.figpanel.subplot.get_ylim(), ## 'grouping': self.group_choice.Value, ## 'version': '1', } def load_settings(self, settings): '''load_settings is called when loading a workspace from file. settings - a dictionary mapping setting names to values encoded as strings. ''' ## if 'version' not in settings: ## settings['grouping'] = NO_GROUP ## settings['version'] = '1' if 'table' in settings: self.table_choice.SetStringSelection(settings['table']) self.update_column_fields() if 'x-axis' in settings: cols = map(str.strip, settings['x-axis'].split(',')) if len(cols) == 1: self.x_choice.SetStringSelection(cols[0]) else: self.x_choice.SetValue(SELECT_MULTIPLE) self.x_columns = cols if 'filter' in settings: self.filter_choice.SetStringSelection(settings['filter']) self.update_figpanel() if 'x-lim' in settings: self.figpanel.subplot.set_xlim(eval(settings['x-lim'])) if 'y-lim' in settings: self.figpanel.subplot.set_ylim(eval(settings['y-lim'])) self.figpanel.draw()