1 """Charts and stats
2
3 Copyright 2008-2011 Research Foundation State University of New York
4 This file is part of QUB Express.
5
6 QUB Express is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 QUB Express is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License,
17 named LICENSE.txt, in the QUB Express program directory. If not, see
18 <http://www.gnu.org/licenses/>.
19
20 """
21
22 import collections
23 import operator
24
25 import gobject
26 import gtk
27
28 import qubx.faces
29 import qubx.fast.clickmap
30 import qubx.fast.kmeans
31 import qubx.fit
32 import qubx.fit_space
33 import qubx.modelGTK
34 import qubx.notebook
35 import qubx.notebookGTK
36 import qubx.pyenv
37 import qubx.settings
38 import qubx.settingsGTK
39 import qubx.table
40 import qubx.toolspace
41 import qubx.tree
42 from qubx.accept import *
43 from qubx.types import *
44
45 from itertools import *
46 from numpy import *
47 import __builtin__
48
49 COLOR_ACTIONS = ('select.actions', (0,1,0,1))
50 COLOR_PRESETS = ('select.presets', (.3,.3,1,1))
51 COLOR_EMPTY_BG = ('select.empty.bg', (1,1,1,1))
52 COLOR_EMPTY_TEXT = ('select.empty.text', (.1,0,0,1))
53 COLOR_EMPTY_BTN = ('select.empty.btn', (.7,0,.1,1))
54
55 CENTROID_ALPHA = 0.2
56 DRAG_ALPHA = 0.25
57 DRAG_BORDER_ALPHA = 0.5
58
59 MENU_TIMEOUT = 360
60 MENU_STRAYDIUS = 2
61
62 RECENT_COUNT = 5
63
66 super(SelectFace, self).__init__(name)
67 self.__ref = Reffer()
68 self.presets = qubx.settings.SettingsMgr['Select']
69 self.presets.OnSet = self.__onPreSet
70 self.__profile = self.presets.active
71 self.__recent_criteria = self.__profile['RecentCriteria']
72 self.__recent_weights = self.__profile['RecentWeights']
73 self.__fit_ix = None
74 self.__xmeans_fit_ix = None
75 self.__actionlist = []
76 self.plots = []
77 self.plots_showing = set()
78 self.x_means_plots = []
79 self.x_means = {}
80 self.table_names = []
81 self.table_events = []
82 self.tb_by_name = {}
83 self.__colors = collections.defaultdict(lambda: [])
84 self.__fields = collections.defaultdict(lambda: set())
85 self.__plots_using_field = collections.defaultdict(lambda: collections.defaultdict(lambda: []))
86 self.missing = memoize(self.__missing)
87 self.vals = collections.defaultdict(lambda: collections.defaultdict(lambda: self.missing))
88 self.mean = collections.defaultdict(lambda: collections.defaultdict(lambda: self.missing))
89 self.std = collections.defaultdict(lambda: collections.defaultdict(lambda: self.missing))
90 self.median = collections.defaultdict(lambda: collections.defaultdict(lambda: self.missing))
91 self.mode = collections.defaultdict(lambda: collections.defaultdict(lambda: self.missing))
92 self.v_fields = {}
93 self.v_names = {}
94 self.vvv = {}
95
96 self.panLeftRight = gtk.HBox()
97 self.panLeftRight.show()
98 self.pack_start(self.panLeftRight, True, True)
99 self.panLeft = gtk.VBox()
100 self.panLeft.show()
101 self.panLeftRight.pack_start(self.panLeft, False, True)
102 self.popupActions = gtk.Menu()
103 self.mnuActions = qubx.toolspace.Button_Popup(self.popupActions, color=COLOR_ACTIONS, tooltip='Click for Charts menu',
104 on_popup=self.__onPopupActions)
105 self.mnuActions.show()
106 self.panLeft.pack_start(self.mnuActions, False, True)
107 self.palette = qubx.toolspace.Palette()
108 self.palette.set_tooltip_text('Pick a color, click points to make groups')
109 self.palette.show()
110 self.panLeft.pack_start(self.palette, True, True)
111
112 QubX = qubx.pyenv.env.globals['QubX']
113
114 self.empty_msg = qubx.toolspace.ToolSpace()
115 self.empty_msg.OnDraw += self.__ref(lambda ctx, w, h: ctx.set_source_rgba(1,1,1,1) or ctx.paint())
116 layer = qubx.toolspace.Layer(x=0, y=0, w=-.01, h=27, cBG=COLOR_EMPTY_BG)
117 layer.add_sublayer(qubx.toolspace.SubLayer_Label("To read a table from disk, or create a new one, use the main menu",
118 -1, 1, x=6, y=2, w=50, h=1.5,
119 color=COLOR_EMPTY_TEXT, hover_color=COLOR_EMPTY_TEXT))
120 layer.add_sublayer(qubx.toolspace.SubLayer_Label("(triangle at the upper-left of the window).",
121 -1, 1, x=8, y=3.5, w=50, h=1.5,
122 color=COLOR_EMPTY_TEXT, hover_color=COLOR_EMPTY_TEXT))
123 layer.add_sublayer(qubx.toolspace.SubLayer_Label("New Table...", 0, 1, x=15, y=6, w=12, h=1.5, color=COLOR_EMPTY_BTN,
124 border=1, action=lambda x,y,e: QubX.new_table()))
125 layer.add_sublayer(qubx.toolspace.SubLayer_Label("Open Table...", 0, 1, x=30, y=6, w=12, h=1.5, color=COLOR_EMPTY_BTN,
126 border=1, action=lambda x,y,e: QubX.open_table()))
127 layer.add_sublayer(qubx.toolspace.SubLayer_Label("To plot columns from the Tables panel, use the Charts menu",
128 -1, 1, x=6, y=9, w=50, h=1.5,
129 color=COLOR_EMPTY_TEXT, hover_color=COLOR_EMPTY_TEXT))
130 layer.add_sublayer(qubx.toolspace.SubLayer_Label("(triangle at the upper-left of this panel).",
131 -1, 1, x=8, y=10.5, w=50, h=1.5,
132 color=COLOR_EMPTY_TEXT, hover_color=COLOR_EMPTY_TEXT))
133 layer.add_sublayer(qubx.toolspace.SubLayer_Label("Add a chart...", 0, 1, x=30, y=13, w=12, h=1.5, color=COLOR_EMPTY_BTN,
134 border=1, action=lambda x,y,e: self.add_plot()))
135 layer.add_sublayer(qubx.toolspace.SubLayer_Label("To fit large files of sampled data, open them in the Data panel",
136 -1, 1, x=6, y=16, w=50, h=1.5,
137 color=COLOR_EMPTY_TEXT, hover_color=COLOR_EMPTY_TEXT))
138 layer.add_sublayer(qubx.toolspace.SubLayer_Label("(use its blue triangle File menu).",
139 -1, 1, x=8, y=17.5, w=50, h=1.5,
140 color=COLOR_EMPTY_TEXT, hover_color=COLOR_EMPTY_TEXT))
141 layer.add_sublayer(qubx.toolspace.SubLayer_Label("Show the Data panel...", 0, 1, x=24, y=20, w=18, h=1.5, color=COLOR_EMPTY_BTN,
142 border=1, action=lambda x,y,e: QubX.Layout.show_face(' Data')))
143 layer.add_sublayer(qubx.toolspace.SubLayer_Label("To curve-fit any figure, click its fitting icon:",
144 -1, 1, x=6, y=23, w=32, h=1.5,
145 color=COLOR_EMPTY_TEXT, hover_color=COLOR_EMPTY_TEXT))
146 layer.add_sublayer(qubx.fit_space.SubLayer_FitIcon(x=44, y=22, w=3, h=3))
147
148 self.empty_msg.add_layer(layer)
149 self.panLeftRight.pack_start(self.empty_msg, True, True)
150 self.empty_msg.show()
151
152 self.grid = qubx.GTK.AspectGrid()
153
154 self.panLeftRight.pack_start(self.grid, True, True)
155
156 Tables = QubX.Tables
157 Tables.OnAddTable += self.__ref(self.__onAddTable)
158 Tables.OnRemoveTable += self.__ref(self.__onRemoveTable)
159 for tablerec in Tables.tables:
160 self.__onAddTable(tablerec.table)
161
162 self.actions.append(('Add a chart...', self.add_plot))
163 self.actions.append(('Select all', self.select_all))
164 self.actions.append(('Unselect all (black)', lambda: self.select_all(0)))
165 self.actions.append(('Select by criteria...', self.select_by_criteria))
166 self.actions.append(('Trim...', self.trim))
167 self.actions.append(('K-Means clustering', self.cluster_k_means))
168 self.actions.append(('X-Means clustering...', self.cluster_x_means))
169
170 self.nbCharts = qubx.notebook.NbItems("All charts")
171 self.nbPictures = qubx.notebook.NbItems("All pictures")
172 self.nbStats = qubx.notebook.NbTable("All group stats", self.nb_group_caption, self.nb_group_shape, self.nb_group_headers, self.nb_group_row)
173 qubx.notebook.Notebook.register_auto('Select.XMeans.Chart', 'XMeans Chart, on XMeans')
174 qubx.notebook.Notebook.register_auto('Select.XMeans.Picture', 'XMeans Picture, on XMeans')
175 qubx.notebook.Notebook.register_auto('Select.XMeans.Charts', 'All Charts, on XMeans', True)
176 qubx.notebook.Notebook.register_auto('Select.XMeans.Pictures', 'All Pictures, on XMeans')
177 qubx.notebook.Notebook.register_auto('Select.XMeans.Stats', 'All group stats, on XMeans', True)
178 qubx.notebook.Notebook.register_auto('Select.Parameters', 'Chart fitting Parameters, on Fit', True)
179 qubx.notebook.Notebook.register_auto('Select.Results', 'Chart fitting Results, on Fit', True)
180 qubx.notebook.Notebook.register_auto('Select.Chart', 'Chart, on Fit')
181 qubx.notebook.Notebook.register_auto('Select.Picture', 'Chart Picture, on Fit', True)
182
183 setaside = self.__profile.clone()
184
185 self.__profile.remove(self.__profile['Plots'])
186 self.__onPreSet(self.presets, setaside)
187
188
189 if not self.__profile['BinCount'].data:
190 self.__profile['BinCount'].data = 12
191 if not self.__profile['TrialsPerK'].data:
192 self.__profile['TrialsPerK'].data = 300
193
194 self.__trim_stds = 1.0
195 self.__criteria_expr = ""
196 self.__xmeans_klo = 1
197 self.__xmeans_khi = None
198 self.__xmeans_weight_expr = ""
199 self.__add_table_name = "Segments"
200 actions = property(lambda self: self.__actionlist, None, "to add an item to the Actions menu, insert a tuple ('label', lambda: action())")
202 def build_item(caption, action=None):
203 item = gtk.MenuItem(caption)
204 if action:
205 item.connect('activate', lambda item: action())
206 else:
207 item.set_sensitive(False)
208 item.show()
209 return item
210 menu = self.popupActions
211 menu.foreach(lambda item: menu.remove(item))
212 for lbl, func in self.actions:
213 menu.append(build_item(lbl, func))
214
215 menu_presets = gtk.Menu()
216 for name in sorted(self.presets.listNames(), key=lambda x: x.lower()):
217 menu_presets.append(build_item(name, bind(self.__use_preset, name)))
218 menu_presets.append(build_item('Manage...', self.__onClickManagePresets))
219 menu_presets.append(build_item('Add to menu...', self.__onClickAddPreset))
220 item_presets = build_item('Chart sets')
221 item_presets.set_sensitive(True)
222 item_presets.set_submenu(menu_presets)
223 menu.append(item_presets)
224 return True
226 self.remove_all()
227 for node in qubx.tree.children(updates.find('Plots')):
228 try:
229 if node.name == 'OnePlot':
230 self.add_one_plot(str(node['Table'].data),
231 str(node['Field'].data),
232 bool(node['IsLog'].data[0]),
233 str(node['YLabel'].data),
234 str(node['Ind'].data),
235 bool(node['IndIsLog'].data[0]),
236 str(node['XLabel'].data))
237 elif node.name == 'TwoPlot':
238 self.add_two_plot(str(node['Table'].data),
239 str(node['FieldX'].data),
240 str(node['FieldY'].data),
241 bool(node['IsLogX'].data[0]),
242 bool(node['IsLogY'].data[0]),
243 str(node['XLabel'].data),
244 str(node['YLabel'].data))
245 elif node.name == 'HistPlot':
246 self.add_hist_plot(str(node['Table'].data),
247 str(node['Field'].data),
248 bool(node['IsLog'].data[0]),
249 node['BinCount'].data[0],
250 str(node['YLabel'].data))
251 except:
252 traceback.print_exc()
269 """Makes table_name the default choice for "add a chart", xmeans etc."""
270 self.__add_table_name = table_name
272 QubX = qubx.pyenv.env.globals['QubX']
273 if table_name in self.tb_by_name:
274 tbn = table_name
275 elif QubX.Tables.find_table(self.__add_table_name):
276 tbn = self.__add_table_name
277 else:
278 tbn = 'Segments'
279 dlg = gtk.Dialog("%s - Add a chart"%QubX.appname, QubX, gtk.DIALOG_MODAL)
280 line = gtk.HBox()
281 line.show()
282 dlg.vbox.pack_start(line, False, True)
283 lbl = gtk.Label('Table:')
284 lbl.show()
285 line.pack_start(lbl, False, True)
286 self.mnuTable = qubx.GTK.StaticComboList(sorted([trec.table.label for trec in QubX.Tables.tables]))
287 self.mnuTable.active_text = tbn
288 self.mnuTable.show()
289 line.pack_start(self.mnuTable, False, True)
290 lbl = gtk.Label('Show')
291 lbl.show()
292 line.pack_start(lbl, False, True)
293 self.mnuType = qubx.GTK.StaticComboList(['Plot', 'Histogram'])
294 self.mnuType.OnChange += self.__ref(self.__onChangeType)
295 self.mnuType.show()
296 line.pack_start(self.mnuType, False, True)
297 self.panVarX = gtk.HBox()
298 self.panVarX.show()
299 line.pack_start(self.panVarX, False, True)
300 self.chkLogX = gtk.CheckButton('log')
301 self.chkLogX.show()
302 self.panVarX.pack_start(self.chkLogX, False, True)
303 self.mnuVarX = qubx.GTK.DynamicComboBox()
304 self.mnuVarX.OnPopulate += self.__ref(self.__onPopulateVar)
305 self.mnuVarX.active_text = 'Index'
306 self.mnuVarX.show()
307 self.panVarX.pack_start(self.mnuVarX, False, True)
308 lbl = gtk.Label('vs.')
309 lbl.show()
310 self.panVarX.pack_start(lbl, False, True)
311 self.chkLogY = gtk.CheckButton('log')
312 self.chkLogY.show()
313 line.pack_start(self.chkLogY, False, True)
314 self.mnuVarY = qubx.GTK.DynamicComboBox()
315 self.mnuVarY.OnPopulate += self.__ref(self.__onPopulateVar)
316 self.mnuVarY.show()
317 line.pack_start(self.mnuVarY, False, True)
318 self.panHist = gtk.HBox()
319
320 line.pack_start(self.panHist, False, True)
321 lbl = gtk.Label('Bins:')
322 lbl.show()
323 self.panHist.pack_start(lbl, False, True)
324 self.txtHistBins = qubx.GTK.NumEntry(self.__profile['BinCount'].data[0], acceptIntGreaterThan(2))
325 self.txtHistBins.set_width_chars(3)
326 self.txtHistBins.show()
327 self.panHist.pack_start(self.txtHistBins, False, True)
328 dlg.add_button('Cancel', gtk.RESPONSE_REJECT)
329 dlg.add_button('Plot', gtk.RESPONSE_ACCEPT)
330 response = dlg.run()
331 dlg.destroy()
332 if response == gtk.RESPONSE_ACCEPT:
333 self.__profile['BinCount'].data[0] = self.txtHistBins.value
334 self.__add_table_name = self.mnuTable.active_text
335 self.__onClickPlot()
337 if typ == 'Plot':
338 self.panVarX.show()
339 self.panHist.hide()
340 else:
341 self.panVarX.hide()
342 self.panHist.show()
350 Tables = qubx.pyenv.env.globals['QubX'].Tables
351 table = Tables.find_table(self.mnuTable.active_text)
352 if not table:
353 qubx.GTK.ShowMessage("There is no longer a %s table. Please pick another." % self.mnuTable.active_text)
354 return
355 if self.mnuType.active_text == 'Plot':
356 for field_name in (self.mnuVarX.active_text, self.mnuVarY.active_text):
357 if not (field_name in table.fields):
358 qubx.GTK.ShowMessage("The %s table doesn't have a field %s. Please pick another." % (self.mnuTable.active_text, field_name))
359 return
360 if self.mnuVarX.active_text in table.fields_independent:
361 self.add_one_plot(table.label, self.mnuVarY.active_text, self.chkLogY.get_active(),
362 FieldLabel(table, self.mnuVarY.active_text, self.chkLogY.get_active()),
363 self.mnuVarX.active_text, self.chkLogX.get_active(),
364 FieldLabel(table, self.mnuVarX.active_text, self.chkLogX.get_active()))
365 else:
366 self.add_two_plot(table.label, self.mnuVarX.active_text, self.mnuVarY.active_text,
367 self.chkLogX.get_active(), self.chkLogY.get_active(),
368 FieldLabel(table, self.mnuVarX.active_text, self.chkLogX.get_active()),
369 FieldLabel(table, self.mnuVarY.active_text, self.chkLogY.get_active()))
370 else:
371 if not (self.mnuVarY.active_text in table.fields):
372 qubx.GTK.ShowMessage("The %s table doesn't have a field %s. Please pick another." % (self.mnuTable.active_text, self.mnuVarY.active_text))
373 return
374 self.add_hist_plot(table.label, self.mnuVarY.active_text, self.chkLogY.get_active(),
375 self.txtHistBins.value, FieldLabel(table, self.mnuVarY.active_text, self.chkLogY.get_active()))
377 return list(self.__fields[table_name])
378 - def colors_in(self, table_name, include_zero=False):
379 try:
380 return self.tb_by_name[table_name].groups_occupied(include_zero)
381 except:
382 traceback.print_exc()
383 return []
385 return self.__colors[table_name][ix]
387 if not (table_name in self.tb_by_name):
388 return
389 colors = self.__colors[table_name]
390 if colors[ix] != color:
391 colors[ix] = color
392 self.tb_by_name[table_name].set(ix, 'Group', color)
394 return self.__colors[table_name]
395 - def set_colors(self, table_name, color_list, index_list=None):
396 if not (table_name in self.tb_by_name):
397 return
398 table = self.tb_by_name[table_name]
399 colors_cache = self.get_colors(table_name)
400 indices = index_list or count()
401 for i, c in izip(indices, color_list):
402 if c != colors_cache[i]:
403 colors_cache[i] = c
404 table.set(i, 'Group', c)
448 - def trim(self, num_std=None):
449 stds = num_std
450 if stds == None:
451 QubX = qubx.pyenv.env.globals['QubX']
452 dlg = qubx.GTK.NumEntryDialog('%s - Trim'%QubX.appname, QubX,
453 "Unselect points outside this many std devs:",
454 self.__trim_stds,
455 acceptFloatGreaterThan(0.0), '%.5g')
456 response = dlg.run()
457 dlg.destroy()
458 if response == gtk.RESPONSE_ACCEPT:
459 stds = self.__trim_stds = dlg.value
460 else:
461 return
462 def trim_fields(table, fields):
463 colors = self.__colors[table.label][:]
464 for field in fields:
465 for color in table.groups_occupied():
466 ixs = table.rows_in_group(color)
467 vals = self.vals[table.label][field](color)
468 mean = self.mean[table.label][field](color)
469 std = self.std[table.label][field](color)
470 for i,v in izip(ixs, vals):
471 if abs(v - mean) > std:
472 colors[i] = 0
473 self.set_colors(table.label, colors)
474 if self.__fit_ix == None:
475 for table in self.tb_by_name.values():
476 trim_fields(table, self.__fields[table.label])
477 else:
478 plot = self.plots[self.__fit_ix]
479 trim_fields(plot.table, plot.fields)
481 if (table_name == None) and (self.__fit_ix != None):
482 table_names = [self.plots[self.__fit_ix].table_name]
483 fields = {table_names[0] : self.plots[self.__fit_ix].fields}
484 elif table_name:
485 table_names = [table_name]
486 fields = self.__fields
487 else:
488 table_names = self.tb_by_name.keys()
489 fields = self.__fields
490 for table_name in table_names:
491 table = self.tb_by_name[table_name]
492 if table_name in self.x_means:
493 wgt = self.x_means[table_name].weight_expr
494 else:
495 wgt = ""
496 colors = self.__colors[table_name][:]
497 color_set = set(colors)
498 k = len(color_set)
499 if 0 in color_set:
500 k -= 1
501 if k <= 0:
502 k = 1
503
504
505 try:
506 ww = self.__evalXMeansWeight(wgt, table=table)
507 except:
508 ww = array([1.0]*table.size, dtype='float32')
509 clusterer = qubx.fast.kmeans.Clusterer([vv for vv in [self.vals[table_name][field]() for field in fields[table_name]] if len(vv)],
510 ww)
511 ssd = clusterer.cluster(colors)
512 self.set_colors(table_name, colors)
513 self.get_x_means_plot(table_name).set_ssd(k, ssd)
515 if not self.plots:
516 return 0.0
517
518
519
520
521 clust = clusterer
522 if clusterer == None:
523 if (self.__fit_ix != None) and (table_name == self.plots[self.__fit_ix].table_name):
524 fields = {table_name : self.plots[self.__fit_ix].fields}
525 else:
526 fields = self.__fields
527 table = self.tb_by_name[table_name]
528 wgt = self.x_means[table_name].weight_expr
529 try:
530 ww = self.__evalXMeansWeight(wgt, table=table)
531 except:
532 ww = array([1.0]*table.size, dtype='float32')
533 clust = qubx.fast.kmeans.Clusterer([vv for vv in [self.vals[table_name][field]() for field in fields[table_name]] if len(vv)],
534 ww)
535 tpk = trials_per_k
536 if tpk == None:
537 tpk = self.x_means[table_name].trials_per_k
538
539 colors = self.__colors[table_name][:]
540 ssd = clust.cluster_trials(colors, k, tpk)
541
542 self.set_colors(table_name, colors)
543 if not clusterer:
544 self.get_x_means_plot(table_name).set_ssd(k, ssd)
545 return ssd
546 - def cluster_x_means(self, table_name=None, k_min=None, k_max=None, trials_per_k=None, weight=None):
547 if not self.plots:
548 return
549 tbn = table_name
550 klo = k_min
551 khi = k_max
552 tpk = trials_per_k
553 wgt = weight
554 if (table_name == None) or (k_min == None) or (k_max == None) or (trials_per_k == None) or (weight == None):
555 if tbn == None:
556 if self.__add_table_name in self.tb_by_name:
557 tbn = self.__add_table_name
558 else:
559 tbn = self.tb_by_name.keys()[0]
560 if klo == None: klo = self.__xmeans_klo
561 if khi == None: khi = self.__xmeans_khi or int(round(sqrt(self.tb_by_name[tbn].size)))
562 if tpk == None: tpk = self.__profile['TrialsPerK'].data[0]
563 if wgt == None: wgt = self.__xmeans_weight_expr
564
565 QubX = qubx.pyenv.env.globals['QubX']
566 dlg = gtk.Dialog("%s - Charts - X-Means Clustering"%QubX.appname, QubX, gtk.DIALOG_MODAL)
567 line = gtk.HBox(True)
568 line.show()
569 dlg.vbox.pack_start(line, False, True)
570 lbl = gtk.Label('Table:')
571 lbl.show()
572 line.pack_start(lbl, False, True)
573 mnuTable = self.mnuXMeansTable = qubx.GTK.StaticComboList(sorted([x for x in self.tb_by_name.keys()]))
574 mnuTable.show()
575 line.pack_start(mnuTable, False, True)
576 line = gtk.HBox(True)
577 line.show()
578 dlg.vbox.pack_start(line, False, True)
579 lbl = gtk.Label('Min K:')
580 lbl.show()
581 line.pack_start(lbl, False, True)
582 txtKlo = qubx.GTK.NumEntry(klo, acceptIntGreaterThan(0))
583 txtKlo.show()
584 line.pack_start(txtKlo, False, True)
585 line = gtk.HBox(True)
586 line.show()
587 dlg.vbox.pack_start(line, False, True)
588 lbl = gtk.Label('Max K:')
589 lbl.show()
590 line.pack_start(lbl, False, True)
591 txtKhi = qubx.GTK.NumEntry(khi, acceptIntGreaterThan(0))
592 txtKhi.show()
593 line.pack_start(txtKhi)
594 line = gtk.HBox(True)
595 line.show()
596 dlg.vbox.pack_start(line, False, True)
597 lbl = gtk.Label('Trials/K:')
598 lbl.show()
599 line.pack_start(lbl, False, True)
600 txtTrials = qubx.GTK.NumEntry(tpk, acceptIntGreaterThan(0))
601 txtTrials.show()
602 line.pack_start(txtTrials, False, True)
603 line = gtk.HBox()
604 line.show()
605 dlg.vbox.pack_start(line, False, True)
606 lbl = gtk.Label('Weight:')
607 lbl.show()
608 line.pack_start(lbl, False, True)
609 txtWeight = self.txtXMeansWeight = qubx.GTK.NumEntry(wgt, self.__acceptXMeansWeight)
610 txtWeight.onParse(True)
611 txtWeight.show()
612 line.pack_start(txtWeight, True, True)
613 btnHelp = qubx.pyenvGTK.HelpTestButton(txtWeight)
614 btnHelp.caption = "Enter an expression in terms of field_name"
615 btnHelp.help_msg = XMEANS_WEIGHT_HELP
616 btnHelp.bind = lambda expr: qubx.pyenv.env.globals.__setitem__('xmeans_weight', lambda i: self.__evalXMeansWeight(expr=expr, indices=[i])[0])
617 btnHelp.write_test = lambda expr: 'xmeans_weight(0)'
618 btnHelp.show()
619 line.pack_start(btnHelp, False, True)
620 self.mnuRecent = gtk.Menu()
621 for node in qubx.tree.children(self.__recent_weights):
622 entry = node.name
623 item = gtk.MenuItem(entry)
624 item.connect('activate', bind(self.txtXMeansWeight.setValue, entry, parse=True))
625 item.show()
626 self.mnuRecent.append(item)
627 self.btnRecent = qubx.toolspace.Button_Popup(self.mnuRecent, tooltip='Recent...')
628 self.btnRecent.show()
629 line.pack_start(self.btnRecent, False, True)
630
631 dlg.add_button('Cancel', gtk.RESPONSE_REJECT)
632 dlg.add_button('OK', gtk.RESPONSE_ACCEPT)
633 response = dlg.run()
634 dlg.destroy()
635 if response != gtk.RESPONSE_ACCEPT:
636 return
637 tbn = mnuTable.active_text
638 klo = txtKlo.value
639 khi = txtKhi.value
640 tpk = txtTrials.value
641 wgt = txtWeight.value
642 self.__profile['TrialsPerK'].data[0] = tpk
643 self.__add_table_name = tbn
644 self.__xmeans_klo = klo
645 self.__xmeans_khi = khi
646 self.__xmeans_weight_expr = wgt
647
648 if (self.__fit_ix != None) and (tbn == self.plots[self.__fit_ix].table_name):
649 fields = {tbn : self.plots[self.__fit_ix].fields}
650 else:
651 fields = self.__fields
652 table = self.tb_by_name[tbn]
653 try:
654 ww = self.__evalXMeansWeight(wgt, table=table)
655 self.__add_recent(self.__recent_weights, wgt)
656 except:
657 ww = array([1.0]*table.size, dtype='float32')
658
659 colors = self.__colors[tbn][:]
660 color_set = set(colors)
661 orig_k = len(color_set)
662 if 0 in color_set:
663 orig_k -= 1
664
665 clusterer = qubx.fast.kmeans.Clusterer([vv for vv in [self.vals[tbn][field]() for field in fields[tbn]] if len(vv)], ww)
666
667 k_ssd = [(k, self.cluster_x_means_k(tbn, k, trials_per_k=tpk, clusterer=clusterer)) for k in xrange(klo, khi+1)]
668
669 plot = self.get_x_means_plot(tbn)
670 plot.weight_expr = wgt
671 plot.trials_per_k = tpk
672 for k, ssd in k_ssd:
673 plot.set_ssd(k, ssd)
674 if orig_k > 0:
675 self.cluster_x_means_k(tbn, orig_k, trials_per_k=tpk, clusterer=clusterer)
676 gobject.idle_add(self.__nb_auto_xmeans, plot)
706 - def __reset_stats(self, table_name, field_name=None, is_log=False):
707 if field_name == None:
708 fields = self.vals[table_name].keys()
709 else:
710 fields = [(field_name, is_log)]
711 for field_name, is_log in fields:
712 if (field_name, is_log) in self.vals[table_name]:
713 self.vals[table_name][field_name, is_log].reset()
714 if (field_name, is_log) in self.mean[table_name]:
715 self.mean[table_name][field_name, is_log].reset()
716 self.std[table_name][field_name, is_log].reset()
717 self.median[table_name][field_name, is_log].reset()
718 self.mode[table_name][field_name, is_log].reset()
719 self.v_fields[table_name].reset()
720 self.v_names[table_name].reset()
721 self.vvv[table_name].reset()
723 return array([], dtype='float32')
724 - def __vals(self, table_name, field_name, is_log, group=None):
725 table = qubx.pyenv.env.globals['QubX'].Tables.find_table(table_name)
726 if (not table) or not (field_name in table.fields):
727 return self.__missing()
728 vals = array([table.get(i, field_name) for i in table.rows_in_group(group)], dtype='float32')
729 if is_log:
730 for i,v in enumerate(vals):
731 if v > 0.0:
732 vals[i] = log(v)
733 else:
734 vals[i] = 0.0
735 return vals
736 - def __mean(self, table_name, field_name, is_log, group=None):
737 tot = 0.0
738 cnt = 0
739 for v in self.vals[table_name][field_name, is_log](group):
740 try:
741 tot += v
742 cnt += 1
743 except:
744 pass
745 return cnt and (tot / cnt) or 0.0
746 - def __std(self, table_name, field_name, is_log, group=None):
747 tot = 0.0
748 cnt = 0
749 mean = self.mean[table_name][field_name, is_log](group)
750 for v in self.vals[table_name][field_name, is_log](group):
751 try:
752 tot += (mean - v)**2
753 cnt += 1
754 except:
755 pass
756 return cnt and sqrt(tot / cnt) or 0.0
769 - def __mode(self, table_name, field_name, is_log, group=None):
770 counter = collections.defaultdict(lambda: 0)
771 for v in self.vals[table_name][field_name, is_log](group):
772 counter[v] += 1
773 counted = collections.defaultdict(lambda: [])
774 maxcnt = 0
775 for val, cnt in counter.iteritems():
776 counted[cnt].append(val)
777 if cnt > maxcnt:
778 maxcnt = cnt
779 modes = counted[maxcnt]
780 if len(modes) > 1:
781 return sum(modes) / len(modes)
782 elif modes:
783 return modes[0]
784 else:
785 return 0.0
787 if not (table_name in self.tb_by_name):
788 return []
789 table = self.tb_by_name[table_name]
790 if not table:
791 return []
792 names = []
793 for name in table.fields:
794 try:
795 float(table.get(0, name))
796 names.append(name)
797 except:
798 pass
799 return sorted(names, key=lambda x: x.lower())
802 - def __vvv(self, table_name):
803 if not (table_name in self.tb_by_name):
804 return []
805 table = self.tb_by_name[table_name]
806 if not table:
807 return []
808 return [self.vals[table_name][field_name, False]() for field_name in self.v_fields[table_name]()]
810 return 'Charts group stats'
812 sum = __builtin__.sum
813 return list(set(sum((self.colors_in(tbn) for tbn in self.tb_by_name.keys()), [])))
815 sum = __builtin__.sum
816 return (sum(len(self.__fields[tbn]) for tbn in self.tb_by_name.keys()), 1+4*len(self.nb_group_colors()))
818 sum = __builtin__.sum
819 return ["Name"] + sum((["Mean %d"%c, "Std %d"%c, "Median %d"%c, "Mode %d"%c]
820 for c in self.nb_group_colors()), [])
822 sum = __builtin__.sum
823 tb_order = sorted(self.tb_by_name.keys())
824 order = sorted(sum(([(tbn, field) for field in self.__fields[tbn]] for tbn in tb_order), []), key=lambda x: x[1][0].lower())
825 tbn, field = order[i]
826 return [field[0]] + sum(([stat[tbn][field](c) for stat in (self.mean, self.std, self.median, self.mode)]
827 for c in self.nb_group_colors()), [])
828 - def add_one_plot(self, table_name, field_name, is_log=False, ylabel="", ind_name='Index', ind_is_log=False, xlabel=""):
829 if (table_name, field_name, is_log, ind_name, ind_is_log) in self.plots_showing:
830 return
831 self.plots_showing.add((table_name, field_name, is_log, ind_name, ind_is_log))
832 table = self.__bind_plot(table_name, [(field_name, is_log)])
833 if self.vals[table_name][ind_name, ind_is_log] == self.missing:
834 self.vals[table_name][ind_name, ind_is_log] = memoize(bind_with_args(self.__vals, table_name, ind_name, ind_is_log))
835 plot = OnePlot(table_name, field_name, is_log, ylabel, ind_name, ind_is_log, xlabel,
836 self.v_names[table_name], self.vvv[table_name],
837 self.vals[table_name][ind_name, ind_is_log],
838 self.vals[table_name][field_name, is_log],
839 self.mean[table_name][field_name, is_log],
840 self.std[table_name][field_name, is_log])
841 plot.table = table
842 self.__plots_using_field[table_name][field_name].append(plot)
843 self.__plots_using_field[table_name][ind_name].append(plot)
844 return self.__show_plot(plot)
845 - def add_two_plot(self, table_name, field_name_x, field_name_y, is_log_x=False, is_log_y=False, xlabel="", ylabel=""):
846 if (table_name, field_name_x, field_name_y, is_log_x, is_log_y) in self.plots_showing:
847 return
848 self.plots_showing.add((table_name, field_name_x, field_name_y, is_log_x, is_log_y))
849 table = self.__bind_plot(table_name, [(field_name_x, is_log_x), (field_name_y, is_log_y)])
850 plot = TwoPlot(table_name, field_name_x, field_name_y, is_log_x, is_log_y, xlabel, ylabel,
851 self.v_names[table_name], self.vvv[table_name],
852 self.vals[table_name][field_name_x, is_log_x],
853 self.vals[table_name][field_name_y, is_log_y],
854 self.mean[table_name][field_name_x, is_log_x],
855 self.mean[table_name][field_name_y, is_log_y],
856 self.std[table_name][field_name_x, is_log_x],
857 self.std[table_name][field_name_y, is_log_y])
858 plot.table = table
859 self.__plots_using_field[table_name][field_name_x].append(plot)
860 self.__plots_using_field[table_name][field_name_y].append(plot)
861 return self.__show_plot(plot)
862 - def add_hist_plot(self, table_name, field_name, is_log=False, bin_count=12, ylabel=""):
863 if (table_name, field_name, is_log, bin_count) in self.plots_showing:
864 return
865 self.plots_showing.add((table_name, field_name, is_log, bin_count))
866 table = self.__bind_plot(table_name, [(field_name, is_log)])
867 plot = HistPlot(table_name, field_name, is_log, bin_count, ylabel,
868 self.vals[table_name][field_name, is_log],
869 self.mean[table_name][field_name, is_log],
870 self.std[table_name][field_name, is_log])
871 plot.table = table
872 self.__plots_using_field[table_name][field_name].append(plot)
873 return self.__show_plot(plot)
875 if table_name in self.table_names:
876 table = self.tb_by_name[table_name]
877 else:
878 self.table_names.append(table_name)
879 self.table_events.append( (self.__ref(bind_with_args(self.__onInsert, table_name)),
880 self.__ref(bind_with_args(self.__onRemoved, table_name)),
881 self.__ref(bind_with_args(self.__onSet, table_name)),
882 self.__ref(bind_with_args(self.__onAddField, table_name))) )
883 self.v_fields[table_name] = memoize(bind(self.__v_fields, table_name))
884 self.v_names[table_name] = memoize(bind(self.__v_names, table_name))
885 self.vvv[table_name] = memoize(bind(self.__vvv, table_name))
886 table = qubx.pyenv.env.globals['QubX'].Tables.find_table(table_name)
887 if table:
888 self.__attach_table(table)
889 for field_name, is_log in fields:
890 self.__fields[table_name].add((field_name, is_log))
891 if self.vals[table_name][field_name, is_log] == self.missing:
892 self.vals[table_name][field_name, is_log] = memoize(bind_with_args(self.__vals, table_name, field_name, is_log))
893 if self.mean[table_name][field_name, is_log] == self.missing:
894 self.mean[table_name][field_name, is_log] = memoize(bind_with_args(self.__mean, table_name, field_name, is_log))
895 if self.std[table_name][field_name, is_log] == self.missing:
896 self.std[table_name][field_name, is_log] = memoize(bind_with_args(self.__std, table_name, field_name, is_log))
897 if self.median[table_name][field_name, is_log] == self.missing:
898 self.median[table_name][field_name, is_log] = memoize(bind_with_args(self.__median, table_name, field_name, is_log))
899 if self.mode[table_name][field_name, is_log] == self.missing:
900 self.mode[table_name][field_name, is_log] = memoize(bind_with_args(self.__mode, table_name, field_name, is_log))
901 return table
926 self.nbPictures.items.remove(plot.nbPicture)
927 self.nbCharts.items.remove(plot.nbChart)
928 if isinstance(plot, OnePlot):
929 self.plots_showing.remove((plot.table_name, plot.field_name, plot.is_log, plot.ind_name, plot.ind_is_log))
930 self.__plots_using_field[plot.table_name][plot.field_name].remove(plot)
931 self.__plots_using_field[plot.table_name][plot.ind_name].remove(plot)
932 elif isinstance(plot, TwoPlot):
933 self.plots_showing.remove((plot.table_name, plot.field_name_x, plot.field_name_y, plot.is_log_x, plot.is_log_y))
934 self.__plots_using_field[plot.table_name][plot.field_name_x].remove(plot)
935 self.__plots_using_field[plot.table_name][plot.field_name_y].remove(plot)
936 elif isinstance(plot, HistPlot):
937 self.plots_showing.remove((plot.table_name, plot.field_name, plot.is_log, plot.bin_count))
938 self.__plots_using_field[plot.table_name][plot.field_name].remove(plot)
939 self.plots.remove(plot)
940 self.__profile['Plots'].remove(plot.as_preset)
941 self.grid.remove(plot)
942 tables_remain = set(plot.table_name for plot in self.plots)
943 if not (plot.table_name in tables_remain):
944 if plot.table:
945 self.__detach_table(plot.table)
946 tbi = self.table_names.index(plot.table_name)
947 del self.table_names[tbi]
948 del self.table_events[tbi]
949 del self.__colors[plot.table_name]
950 del self.__fields[plot.table_name]
951 del self.vals[plot.table_name]
952 del self.mean[plot.table_name]
953 del self.std[plot.table_name]
954 del self.median[plot.table_name]
955 del self.mode[plot.table_name]
956 del self.v_fields[plot.table_name]
957 del self.v_names[plot.table_name]
958 del self.vvv[plot.table_name]
959 else:
960 self.__fields[plot.table_name] = set(reduce(operator.add, [p.fields for p in self.plots if p.table_name == plot.table_name], []))
961 if not self.plots:
962 self.grid.hide()
963 self.empty_msg.show()
998 plot = self.x_means[table_name]
999 self.nbPictures.items.remove(plot.nbPicture)
1000 self.nbCharts.items.remove(plot.nbChart)
1001 del self.x_means[table_name]
1002 self.x_means_plots.remove(plot)
1069 - def __onSet(self, table_name, i, field_name, val, prev, undoing):
1084 if self.vals[table_name][field_name, False] == self.missing:
1085 self.vals[table_name][field_name, False] = memoize(bind_with_args(self.__vals, table_name, field_name, False))
1086 else:
1087 self.vals[table_name][field_name, False].reset()
1088 for is_log in (False, True):
1089 if (field_name, is_log) in self.__fields[table_name]:
1090 self.__reset_stats(table_name, field_name, is_log)
1091 for plot in self.__plots_using_field[table_name][field_name]:
1092 plot.invalidate()
1110 if ix != None:
1111 self.grid.hide()
1112 self.__fit_grid_ix = self.grid.remove(self.plots[ix], temporary=True)
1113 self.panLeftRight.pack_start(self.plots[ix], True, True)
1114 else:
1115 self.panLeftRight.remove(self.plots[self.__fit_ix])
1116 self.grid.pack_aspect(self.plots[self.__fit_ix], self.__fit_grid_ix)
1117 self.grid.show_all()
1118 self.__fit_ix = ix
1119 fit_ix = property(lambda self: self.__fit_ix, lambda self, ix: self.set_fit_ix(ix),
1120 "warning: must alternate between None and a legit index")
1127 if ix != None:
1128 self.grid.hide()
1129 self.__xmeans_fit_grid_ix = self.grid.remove(self.x_means_plots[ix], temporary=True)
1130 self.panLeftRight.pack_start(self.x_means_plots[ix], True, True)
1131 else:
1132 self.panLeftRight.remove(self.x_means_plots[self.__xmeans_fit_ix])
1133 self.grid.pack_aspect(self.x_means_plots[self.__xmeans_fit_ix], self.__xmeans_fit_grid_ix)
1134 self.grid.show_all()
1135 self.__xmeans_fit_ix = ix
1136 xmeans_fit_ix = property(lambda self: self.__xmeans_fit_ix, lambda self, ix: self.set_xmeans_fit_ix(ix),
1137 "warning: must alternate between None and a legit index")
1139 if not showing:
1140 if self.__fit_ix != None:
1141 self.plots[self.__fit_ix].layerset = self.plots[self.__fit_ix].controlsHidden
1142 if self.__xmeans_fit_ix != None:
1143 self.x_means_plots[self.__xmeans_fit_ix].layerset = self.x_means_plots[self.__xmeans_fit_ix].controlsHidden
1149 if len(plot.xx):
1150 klo = min(plot.xx)
1151 khi = max(plot.xx)
1152 else:
1153 klo = self.__xmeans_klo
1154 khi = self.__xmeans_khi
1155 self.cluster_x_means(plot.table_name, klo, khi, plot.trials_per_k, plot.weight_expr)
1156
1157
1159 if x0 > x1:
1160 x0, x1 = x1, x0
1161 if y0 > y1:
1162 y0, y1 = y1, y0
1163 return x0, y0, x1, y1
1164
1166 """Returns the Euclidean distance between (x1, y1) and (x2, y2)."""
1167 return sqrt((x2 - x1)**2 + (y2 - y1)**2)
1168
1171 qubx.fit_space.FitSpaceCursor.__init__(self, space)
1172 self.sel_rect = None
1173 self.mnuDot = gtk.Menu()
1174 item = gtk.MenuItem('Show in Tables')
1175 item.connect('activate', lambda item: self.space.OnShowOne(self.space, self.press_ix))
1176 item.show()
1177 self.mnuDot.append(item)
1184 qubx.fit_space.FitSpaceCursor.onPress(self, x, y, e)
1185 self.press_ix = self.space.dotmap.find(x, y, self.space.dot_rad_pix)
1186 self.press_pt = (x, y)
1187 if self.press_ix >= 0:
1188 self.__menuWaiting = True
1189 gobject.timeout_add(MENU_TIMEOUT, self.__onMenuTimeout,
1190 Anon(x=e.x, y=e.y, button=e.button, time=e.time))
1192 qubx.fit_space.FitSpaceCursor.onDrag(self, x, y, e)
1193 xpress, ypress = self.press_pt
1194 if self.press_ix >= 0:
1195 self.__menuWaiting = self.__menuWaiting and (distance(xpress, ypress, x, y) <= MENU_STRAYDIUS)
1196 else:
1197 self.sel_rect = rect_increasing(xpress, ypress, x, y)
1198 self.space.redraw_canvas()
1200 qubx.fit_space.FitSpaceCursor.onRelease(self, x, y, e)
1201 if self.press_ix >= 0:
1202 self.space.OnSelectOne(self.space, self.press_ix)
1203 elif self.sel_rect:
1204 indices = self.space.dotmap.in_rect(*self.sel_rect)
1205 if indices:
1206 self.space.OnSelectMany(self.space, indices)
1207 self.space.redraw_canvas()
1208 self.press_ix = -1
1209 self.sel_rect = None
1210 self.__menuWaiting = False
1217 self.press_ix = self.space.dotmap.find(x, y, self.space.dot_rad_pix)
1218 if self.press_ix >= 0:
1219 self.mnuDot.popup(None, None, None, e.button, e.time)
1228
1229
1232 qubx.fit_space.FitSpace.__init__(self, label=label)
1233 self.__ref = Reffer()
1234 self.layerset = self.controlsHidden
1235 self.tool = SelectCursor(self)
1236 self.data_width = 0.0
1237 self.draw_fit_when_hidden = False
1238 self.extra_rad = self.extra_width = 0
1239 self.subCaption.w = -3
1240 self.OnClickClose = WeakEvent()
1241 self.OnShowOne = WeakEvent()
1242 self.OnSelectOne = WeakEvent()
1243 self.OnSelectMany = WeakEvent()
1244 self.OnDraw += self.__ref(self.on_overlay)
1245 self.as_preset = qubx.tree.Node('SelectPlot')
1246 self.__colors = []
1247 self.__serial = 0
1248 self.fields = []
1249 self.palette = None
1250 self.dot_rad_pix = 1
1251 self.dotmap = qubx.fast.clickmap.DotMap()
1252 self.table = None
1253 self.subClose = qubx.toolspace.SubLayer_Label('X', 0, 1, x=-1.5, w=1.5, h=qubx.fit_space.LINE_EMS,
1254 color=qubx.fit_space.COLOR_FITSPACE_BUTTON,
1255 action=self.__onClickClose)
1256 self.layCaption.add_sublayer(self.subClose)
1257
1258 self.layNotebook = qubx.toolspace.Layer(x=1, y=-5.5-qubx.fit_space.LINE_EMS, w=2, h=2, cBG=qubx.toolspace.COLOR_CLEAR)
1259 self.subNotebook = qubx.notebookGTK.SubLayer_Notebook(x=0, y=0, w=2, h=2)
1260 self.layNotebook.add_sublayer(self.subNotebook)
1261 self.add_layer(self.layNotebook)
1262 self.nbChart = qubx.notebook.NbChart('Chart', lambda: self.caption,
1263 self.nb_get_shape, self.nb_get_headers,
1264 get_col=self.nb_get_col, get_type=lambda: float,
1265 get_series=self.nb_get_series,
1266 get_colors=self.nb_get_colors, get_color_indices=self.nb_get_color_indices)
1267 self.subNotebook.items.append(self.nbChart)
1268 self.nbPicture = qubx.notebookGTK.NbPicture('Picture', self.nb_picture_get_shape,
1269 self.nb_picture_draw)
1270 self.subNotebook.items.append(self.nbPicture)
1271 self.nbStats = qubx.notebook.NbDynText('Group stats', self.nb_get_group_stats)
1272 self.subNotebook.items.append(self.nbStats)
1273 self.nbParams = qubx.notebook.NbDynText('Parameters', self.controls.nb_get_param_text)
1274 self.nbParams.std_err_est = None
1275 self.controls.robot.OnExpr += self.__ref(self.__onExpr)
1276 self.controls.robot.OnParam += self.__ref(self.__onParam)
1277 self.controls.robot.OnStats += self.__ref(self.__onStats)
1278 self.controls.robot.OnIteration += self.__ref(self.__onIteration)
1279 self.controls.robot.OnEndFit += self.__ref(self.__onEndFit)
1280 self.OnChangeLayerset += self.__ref(self.__onChangeLayerset)
1281 self.__nb_next_stats = False
1283 self.OnClickClose(self)
1287 colors = property(lambda self: self.__colors, lambda self, x: self.set_colors(x))
1289 self.__serial += 1
1290 gobject.idle_add(self.__update_plot, self.__serial)
1292 if serial != self.__serial:
1293 return
1294 self.update_plot()
1296 if layerset == self.controls:
1297 self.subNotebook.items.append(self.nbParams)
1298 else:
1299 self.subNotebook.items.remove(self.nbParams)
1300 - def __onExpr(self, curve_name, expr, params, param_vals, lo, hi, can_fit):
1301 self.__param_names = params
1302 self.__param_vals = param_vals
1303 self.__param_active = can_fit
1304 - def __onParam(self, index, name, value, lo, hi, can_fit):
1309 self.__param_vals = param_vals
1311 self.__nb_next_stats = True
1312 - def __onStats(self, correlation, is_pseudo, std_err_est, ssr, r2, runs_prob):
1313 if self.__nb_next_stats:
1314 self.__nb_next_stats = False
1315 n = len(self.get_yy())
1316 caption = self.caption
1317 qubx.notebook.Notebook.send(qubx.notebook.NbText("""%(caption)s fitting finished.
1318 \tN: %(n)i
1319 \tSSR: %(ssr).6g
1320 \tR^2: %(r2).6g
1321 \tWald-Wolfowitz runs probability: %(runs_prob).6g
1322 \tCorrelation:
1323 %(correlation)s
1324 """ % locals()), auto_id='Select.Results')
1325 self.nbParams.std_err_est = std_err_est
1326 qubx.notebook.Notebook.send(self.nbParams, auto_id='Select.Parameters')
1327 qubx.notebook.Notebook.send(self.nbChart, auto_id='Select.Chart')
1328 qubx.notebook.Notebook.send(self.nbPicture, auto_id='Select.Picture')
1329 self.nbParams.std_err_est = None
1331 raise Exception('unimplemented abstract method')
1345 raise Exception('unimplemented abstract method')
1346
1347
1349 - def __init__(self, table_name, field_name, is_log, ylabel, ind_name, ind_is_log, xlabel, get_v_names, get_vvv, get_xx, get_yy, get_mean, get_std):
1350 SelectPlot.__init__(self, 'Chart.%s'%ylabel)
1351 self.as_preset.name = 'OnePlot'
1352 self.as_preset['Table'].data = self.table_name = table_name
1353 self.as_preset['Field'].data = self.field_name = field_name
1354 self.as_preset['IsLog'].data = self.is_log = is_log
1355 self.as_preset['YLabel'].data = self.ylabel = ylabel
1356 self.as_preset['Ind'].data = self.ind_name = ind_name
1357 self.as_preset['IndIsLog'].data = self.ind_is_log = ind_is_log
1358 self.as_preset['XLabel'].data = self.xlabel = xlabel
1359 self.get_v_names = get_v_names
1360 self.get_vvv = get_vvv
1361 self.get_xx = get_xx
1362 self.get_yy = get_yy
1363 self.get_mean = get_mean
1364 self.get_std = get_std
1365 if xlabel == 'Index':
1366 self.caption = ylabel
1367 else:
1368 self.caption = '%s v. %s' % (xlabel, ylabel)
1369 self.fields = [(field_name, is_log)]
1370 self.invalidate()
1372 xx, yy = self.get_xx(), self.get_yy()
1373 if len(xx) != len(yy):
1374 xx = yy = []
1375 self.controls.robot.set_data(xx, yy, self.get_vvv(), self.get_v_names())
1377 context.set_source_rgb(.1,.1,.1)
1378 context.set_line_width(2.0)
1379 context.rectangle(0,0,w,h)
1380 context.stroke()
1381 lookup = self.appearance.color
1382 color = qubx.modelGTK.COLOR_CLASS
1383 t2x, d2y = self.t2x, self.d2y
1384 rad = self.dot_rad_pix = self.data_rad*self.appearance.emsize
1385 twopi = 2*pi
1386 xx, yy = self.get_xx(), self.get_yy()
1387 for x, y, c in izip(xx, yy, self.colors):
1388 context.set_source_rgba(*lookup(color(c)))
1389 context.arc(t2x(x), d2y(y), rad, 0, twopi)
1390 context.fill()
1391 if self.table:
1392 for c in self.table.groups_occupied():
1393 mean, std = self.get_mean(c), self.get_std(c)
1394 context.set_source_rgba(*qubx.toolspace.SETALPHA(lookup(color(c)), CENTROID_ALPHA))
1395 context.move_to(0, d2y(mean-std))
1396 context.line_to(w, d2y(mean-std))
1397 context.line_to(w, d2y(mean+std))
1398 context.line_to(0, d2y(mean+std))
1399 context.fill()
1400 self.dotmap.reset([t2x(x) for x in xx], [d2y(y) for y in yy])
1401
1402
1403
1405 - def __init__(self, table_name, field_name_x, field_name_y, is_log_x, is_log_y, xlabel, ylabel, get_v_names, get_vvv, get_xx, get_yy, get_mean_x, get_mean_y, get_std_x, get_std_y):
1406 SelectPlot.__init__(self, 'Chart.%s.v.%s' % (xlabel, ylabel))
1407 self.as_preset.name = 'TwoPlot'
1408 self.as_preset['Table'].data = self.table_name = table_name
1409 self.as_preset['FieldX'].data = self.field_name_x = field_name_x
1410 self.as_preset['FieldY'].data = self.field_name_y = field_name_y
1411 self.as_preset['IsLogX'].data = self.is_log_x = is_log_x
1412 self.as_preset['IsLogY'].data = self.is_log_y = is_log_y
1413 self.as_preset['XLabel'].data = self.xlabel = xlabel
1414 self.as_preset['YLabel'].data = self.ylabel = ylabel
1415 self.get_v_names = get_v_names
1416 self.get_vvv = get_vvv
1417 self.get_xx = get_xx
1418 self.get_yy = get_yy
1419 self.get_mean_x = get_mean_x
1420 self.get_mean_y = get_mean_y
1421 self.get_std_x = get_std_x
1422 self.get_std_y = get_std_y
1423 self.caption = '%s v. %s' % (xlabel, ylabel)
1424 self.fields = [(field_name_x, is_log_x), (field_name_y, is_log_y)]
1425 self.invalidate()
1427 xx, yy = self.get_xx(), self.get_yy()
1428 if len(xx) != len(yy):
1429 xx = yy = []
1430 self.controls.robot.set_data(xx, yy, self.get_vvv(), self.get_v_names())
1432 context.set_source_rgb(.1,.1,.1)
1433 context.set_line_width(2.0)
1434 context.rectangle(0,0,w,h)
1435 context.stroke()
1436 lookup = self.appearance.color
1437 color = qubx.modelGTK.COLOR_CLASS
1438 t2x, d2y = self.t2x, self.d2y
1439 rad = self.dot_rad_pix = self.data_rad*self.appearance.emsize
1440 twopi = 2*pi
1441 xx, yy = self.get_xx(), self.get_yy()
1442 for x, y, c in izip(xx, yy, self.colors):
1443 context.set_source_rgba(*lookup(color(c)))
1444 context.arc(t2x(x), d2y(y), rad, 0, twopi)
1445 context.fill()
1446 if self.table:
1447 for c in self.table.groups_occupied():
1448 mean_x, std_x = self.get_mean_x(c), self.get_std_x(c)
1449 mean_y, std_y = self.get_mean_y(c), self.get_std_y(c)
1450 if std_x and std_y:
1451 context.save()
1452 context.translate(t2x(mean_x), d2y(mean_y))
1453 context.scale(t2x(mean_x+std_x)-t2x(mean_x),
1454 d2y(mean_y-std_y)-d2y(mean_y))
1455 context.set_source_rgba(*qubx.toolspace.SETALPHA(lookup(color(c)), CENTROID_ALPHA))
1456 context.arc(0, 0, 1.0, 0, 2*pi)
1457 context.fill()
1458 context.restore()
1459 self.dotmap.reset([t2x(x) for x in xx], [d2y(y) for y in yy])
1461 return self.caption+":\n"+"\n".join(["%4d: %.6g +/- %.6g\t,\t%.6g +/- %.6g" %
1462 (c, self.get_mean_x(c), self.get_std_x(c), self.get_mean_y(c), self.get_std_y(c))
1463 for c in sorted(list(set(self.colors)))])
1464
1466 - def __init__(self, table_name, field_name, is_log, bin_count, ylabel, get_yy, get_mean, get_std):
1467 SelectPlot.__init__(self, 'Chart.Hist.%s'%ylabel)
1468 self.draw_hist = True
1469 self.hist_width = 0.95
1470 self.as_preset.name = 'HistPlot'
1471 self.as_preset['Table'].data = self.table_name = table_name
1472 self.as_preset['Field'].data = self.field_name = field_name
1473 self.as_preset['IsLog'].data = self.is_log = is_log
1474 self.as_preset['BinCount'].data = self.bin_count = bin_count
1475 self.as_preset['YLabel'].data = self.ylabel = ylabel
1476 self.get_yy = get_yy
1477 self.get_mean = get_mean
1478 self.get_std = get_std
1479 self.caption = ylabel
1480 self.xx = self.yy = self.stacking = []
1481 self.fields = [(field_name, is_log)]
1482 self.invalidate()
1487 context.set_source_rgb(.1,.1,.1)
1488 context.set_line_width(2.0)
1489 context.rectangle(0,0,w,h)
1490 context.stroke()
1491 if not len(self.xx):
1492 return
1493 lookup = self.appearance.color
1494 color = qubx.modelGTK.COLOR_CLASS
1495 t2x, d2y = self.t2x, self.d2y
1496 em = self.appearance.emsize
1497 rad = self.dot_rad_pix = min(self.data_rad*em, w/(2*len(self.xx)))
1498 twopi = 2*pi
1499 for x, y, c in izip(self.get_yy(), self.stacking, self.colors):
1500 context.set_source_rgba(*lookup(color(c)))
1501 context.arc(t2x(x), d2y(y), rad, 0, twopi)
1502 context.fill()
1503 if self.table:
1504 border = qubx.fit_space.LINE_EMS*em
1505 for c in self.table.groups_occupied():
1506 mean, std = self.get_mean(c), self.get_std(c)
1507 context.set_source_rgba(*qubx.toolspace.SETALPHA(lookup(color(c)), CENTROID_ALPHA))
1508 context.move_to(t2x(mean-std), border)
1509 context.line_to(t2x(mean-std), h-border)
1510 context.line_to(t2x(mean+std), h-border)
1511 context.line_to(t2x(mean+std), border)
1512 context.fill()
1513 self.dotmap.reset([t2x(x) for x in self.get_yy()], [d2y(y) for y in self.stacking])
1515 nr, nc = self.controls.nb_get_shape()
1516 return (max(nr, len(self.stacking)), nc+3)
1518 return ['X', 'Y', 'Color', 'Bins', 'Bars'] + self.controls.nb_get_headers()[2:]
1520 if c == 0:
1521 return self.get_yy()
1522 elif c == 1:
1523 return self.stacking
1524 elif c == 2:
1525 return self.colors
1526 else:
1527 return self.controls.nb_get_col(c-3)
1529 return [qubx.notebook.NbChartSeries(0, 1, ser_type=qubx.notebook.DOTS, nrow=len(self.stacking)),
1530 qubx.notebook.NbChartSeries(3, 4, ser_type=self.draw_hist and qubx.notebook.HISTOGRAM or qubx.notebook.DOTS, nrow=len(self.yy)),
1531 qubx.notebook.NbChartSeries(3, 5, ser_type=qubx.notebook.LINES, nrow=len(self.yy))]
1532
1533
1535 """Returns (bins, bin_width) as (numpy.array[n], float)."""
1536 d = (hi - lo)
1537 one = d/n
1538 bins = arange(n, dtype='float64')
1539 bins *= one
1540 bins += lo + one/2
1541 return bins, one
1542
1544 if len(yy) < 2:
1545 return [], [], []
1546 lo = min(yy)
1547 bins, bin_width = make_bins(lo, max(yy), bin_count)
1548 bars = zeros(shape=(bin_count,))
1549 stacking = zeros(shape=(len(yy),))
1550 if len(yy):
1551 one = 1.0 / len(yy)
1552 last = bin_count - 1
1553 data = array(yy)
1554 data -= lo
1555 data /= bin_width
1556 for i,x in enumerate(data.astype('int32')):
1557 ibar = min(last, x)
1558 stacking[i] = bars[ibar] + one/2
1559 bars[ibar] += one
1560 return bins, bars, stacking
1561
1563 field_label = field_name
1564 if is_log:
1565 field_label = 'log(%s)' % field_label
1566 if table.units[field_name]:
1567 return '%s [%s]' % (field_label, table.units[field_name])
1568 return field_label
1569
1570
1573 QubX = qubx.pyenv.env.globals['QubX']
1574 gtk.Dialog.__init__(self, "%s - Select by criteria"%QubX.appname, QubX, gtk.DIALOG_MODAL)
1575 self.set_size_request(500, -1)
1576 self.tables = tables
1577 self.table = tables[0]
1578 self.__ref = Reffer()
1579 line = gtk.HBox(True)
1580 line.show()
1581 self.vbox.pack_start(line, False, True)
1582 lbl = gtk.Label('Table:')
1583 lbl.show()
1584 line.pack_start(lbl)
1585 self.mnuTable = qubx.GTK.StaticComboList([table.label for table in tables])
1586 self.mnuTable.OnChange += self.__ref(self.__onChangeTable)
1587 self.mnuTable.show()
1588 line.pack_start(self.mnuTable)
1589 line = gtk.HBox()
1590 line.show()
1591 lbl = gtk.Label('Color rows which have')
1592 lbl.show()
1593 line.pack_start(lbl, False, True)
1594 self.vbox.pack_start(line, False, True)
1595 self.txtCriteria = qubx.GTK.NumEntry('', self.acceptCriteria)
1596 self.txtCriteria.show()
1597 line.pack_start(self.txtCriteria, True, True)
1598 self.btnHelp = qubx.pyenvGTK.HelpTestButton(self.txtCriteria)
1599 self.btnHelp.caption = "Enter an expression in terms of field_name which evaluates True or False"
1600 self.btnHelp.help_msg = CRITERIA_HELP
1601 self.btnHelp.bind = lambda expr: qubx.pyenv.env.globals.__setitem__('rows_meeting_criteria', lambda: rows_meeting_criteria(self.table, expr))
1602 self.btnHelp.write_test = lambda expr: 'print rows_meeting_criteria()'
1603 self.btnHelp.show()
1604 line.pack_start(self.btnHelp, False, True)
1605 self.mnuRecent = gtk.Menu()
1606 for entry in recent:
1607 item = gtk.MenuItem(entry)
1608 item.connect('activate', bind(self.txtCriteria.setValue, entry, parse=True))
1609 item.show()
1610 self.mnuRecent.append(item)
1611 self.btnRecent = qubx.toolspace.Button_Popup(self.mnuRecent, tooltip='Recent...')
1612 self.btnRecent.show()
1613 line.pack_start(self.btnRecent, False, True)
1614
1615 self.add_button('Cancel', gtk.RESPONSE_REJECT)
1616 self.add_button('Select', gtk.RESPONSE_ACCEPT)
1617 - def run(self, expr):
1629
1645 return [i for i in xrange(row_count or table.size) if test_row(table.get_row(i, safenames=True))]
1646
1647 CRITERIA_HELP = """Enter a boolean expression such as
1648 (Group == 1) and (Amp_1 > 2.0)
1649
1650 These names are available:
1651 field_name -- val. of field in this row; replace spaces with underscores; match capitalization
1652 row["field name"] -- value of field in this row
1653 field_mean("field name") -- mean value of field
1654 field_std("field name") -- standard deviation of field
1655 field_median("field name") -- median value of field
1656 field_mode("field name") -- most common value of field
1657 group_mean("field name", c) -- mean value of field, group (color) c only
1658 group_std("field name", c) -- standard deviation of field, group (color) c only
1659 group_median("field name", c) -- median value of field, group (color) c only
1660 group_mode("field name", c) -- most common value of field, group (color) c only
1661
1662 Expressions use Python syntax. Full documentation is available at www.python.org.
1663 """ + qubx.pyenv.PYTHON_HELP
1664
1665
1675
1678 qubx.fit_space.FitSpace.__init__(self, label='X-Means SSD')
1679 self.caption = '%s: X-Means SSD' % table_name
1680 self.table_name = table_name
1681 self.__ref = Reffer()
1682 self.layerset = self.controlsHidden
1683 self.tool = XMeansCursor(self)
1684 self.data_width = 0.0
1685 self.draw_fit_when_hidden = False
1686 self.subCaption.w = -3
1687 self.OnClickClose = WeakEvent()
1688 self.OnClickPoint = WeakEvent()
1689 self.OnClickRefresh = WeakEvent()
1690 self.OnDraw += self.__ref(self.on_overlay)
1691 self.dot_rad_pix = 1
1692 self.dotmap = qubx.fast.clickmap.DotMap()
1693 self.subClose = qubx.toolspace.SubLayer_Label('X', 0, 1, x=-1.5, w=1.5, h=qubx.fit_space.LINE_EMS,
1694 color=qubx.fit_space.COLOR_FITSPACE_BUTTON,
1695 action=self.__onClickClose)
1696 self.layCaption.add_sublayer(self.subClose)
1697
1698 self.layRefresh = qubx.toolspace.Layer(x=-9, y=5, w=8, h=1+qubx.fit_space.LINE_EMS, cBG=self.controls.cLayer)
1699 self.subRefresh = qubx.toolspace.SubLayer_Label('Refresh', 0, 1, y=.5, w=8, h=qubx.fit_space.LINE_EMS, color=self.controls.cButton,
1700 action=lambda x,y,e: self.OnClickRefresh(self))
1701 self.layRefresh.add_sublayer(self.subRefresh)
1702 self.add_layer(self.layRefresh)
1703
1704 self.layHint = qubx.toolspace.Layer(x=-33, y=2.5, w=32, h=qubx.fit_space.LINE_EMS, cBG=qubx.toolspace.COLOR_CLEAR)
1705 self.subHint = qubx.toolspace.SubLayer_Label('Click a point to show the k-clustering', 1, 1, w=32, h=qubx.fit_space.LINE_EMS,
1706 color=self.controls.cText, hover_color=self.controls.cText)
1707 self.layHint.add_sublayer(self.subHint)
1708 self.add_layer(self.layHint)
1709
1710 self.layNotebook = qubx.toolspace.Layer(x=1, y=-5.5-qubx.fit_space.LINE_EMS, w=2, h=2, cBG=qubx.toolspace.COLOR_CLEAR)
1711 self.subNotebook = qubx.notebookGTK.SubLayer_Notebook(x=0, y=0, w=2, h=2)
1712 self.layNotebook.add_sublayer(self.subNotebook)
1713 self.add_layer(self.layNotebook)
1714 self.nbChart = qubx.notebook.NbChart('Chart', lambda: self.caption,
1715 self.controls.nb_get_shape, self.controls.nb_get_headers,
1716 get_col=self.controls.nb_get_col, get_type=lambda: float,
1717 get_series=self.nb_get_series)
1718 self.subNotebook.items.append(self.nbChart)
1719 self.nbPicture = qubx.notebookGTK.NbPicture('Picture', self.nb_picture_get_shape,
1720 self.nb_picture_draw)
1721 self.subNotebook.items.append(self.nbPicture)
1722 self.ssd = collections.defaultdict(lambda: 0.0)
1723 self.__xx = self.__yy = []
1724 self.weight_expr = ""
1725 self.trials_per_k = 300
1726 xx = property(lambda self: self.__xx)
1727 yy = property(lambda self: self.__yy)
1729 self.OnClickClose(self)
1733 - def clear(self, detach=False):
1734 if detach:
1735 self.ssd = collections.defaultdict(lambda: 0.0)
1736 else:
1737 self.ssd.clear()
1738 self.update_plot()
1740 keys = self.ssd.keys()
1741 if keys:
1742 self.__xx = list(range(min(keys), max(keys)+1))
1743 self.__yy = [self.ssd[x] for x in self.__xx]
1744 else:
1745 self.__xx = self.__yy = []
1746 self.controls.robot.set_data(self.__xx, self.__yy)
1748 context.set_source_rgb(.1,.1,.1)
1749 context.set_line_width(2.0)
1750 context.rectangle(0,0,w,h)
1751 context.stroke()
1752
1753 self.dot_rad_pix = self.data_rad*self.appearance.emsize
1754 t2x, d2y = self.t2x, self.d2y
1755 xx, yy = self.__xx, self.__yy
1756 self.dotmap.reset([t2x(x) for x in xx], [d2y(y) for y in yy])
1757
1758 XMEANS_WEIGHT_HELP = """Enter an expression such as
1759 Weight
1760 or 1.0 / Std_1
1761 or Std_1 and (1.0 / Std_1) or 0.0 (avoids division by zero)
1762
1763 These names are available:
1764 field_name -- val. of field in this row; replace spaces with underscores; match capitalization
1765 row["field name"] -- value of field in this row
1766
1767 Expressions use Python syntax. Full documentation is available at www.python.org.
1768 """ + qubx.pyenv.PYTHON_HELP
1769