1 """Charts and stats
2
3 Copyright 2008-2014 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 from gtk import gdk
28
29 import qubx.faces
30 import qubx.fast.clickmap
31 import qubx.fast.kmeans
32 import qubx.fit
33 import qubx.fit_space
34 import qubx.modelGTK
35 import qubx.notebook
36 import qubx.notebookGTK
37 import qubx.pyenv
38 import qubx.settings
39 import qubx.settingsGTK
40 import qubx.table
41 import qubx.toolspace
42 import qubx.tree
43 from qubx.accept import *
44 from qubx.GTK import pack_item, pack_space, pack_hsep, pack_vsep, pack_label, pack_button, pack_check, pack_radio, pack_scrolled, build_menuitem
45 from qubx.toolspace import ColorInfo
46 from qubx.util_types import *
47
48 from itertools import *
49 from numpy import *
50 import __builtin__
51
52 COLOR_ACTIONS = ('select.actions', (0,1,0,1))
53 ColorInfo[COLOR_ACTIONS[0]].label = 'Charts menu'
54 COLOR_EMPTY_BG = ('select.empty.bg', (1,1,1,1))
55 ColorInfo[COLOR_EMPTY_BG[0]].label = 'Charts placeholder background'
56 COLOR_EMPTY_TEXT = ('select.empty.text', (.1,0,0,1))
57 ColorInfo[COLOR_EMPTY_TEXT[0]].label = 'Charts placeholder text'
58 COLOR_EMPTY_BTN = ('select.empty.btn', (.7,0,.1,1))
59 ColorInfo[COLOR_EMPTY_BTN[0]].label = 'Charts placeholder button'
60 COLOR_CRITERIA_POPUP = ('select.criteria.popup', (0, 1, 0, .8))
61 ColorInfo[COLOR_CRITERIA_POPUP[0]].label = 'Charts criteria popup'
62
63 CENTROID_ALPHA = 0.2
64 DRAG_ALPHA = 0.25
65 DRAG_BORDER_ALPHA = 0.5
66
67 MENU_TIMEOUT = 360
68 MENU_STRAYDIUS = 2
69
70 RECENT_COUNT = 5
71
73 __explore_featured = ['presets', 'plots', 'plots_showing', 'x_means_plots', 'x_means', 'table_names', 'table_events', 'tb_by_name',
74 'missing', 'vals', 'mean', 'std', 'median', 'mode', 'v_fields', 'v_names', 'vvv', 'popupActions', 'mnuActions',
75 'palette', 'empty_msg', 'grid', 'actions', 'nbCharts', 'nbPictures', 'nbStats',
76 'prefer_table', 'add_plot', 'fields_in', 'colors_in', 'get_color', 'set_color', 'get_colors', 'set_colors',
77 'select_all', 'select_by_criteria', 'trim', 'cluster_k_means', 'cluster_x_means_k', 'cluster_x_means',
78 'nb_group_caption', 'nb_group_colors', 'nb_group_shape', 'nb_group_headers', 'nb_group_row',
79 'add_one_plot', 'add_two_plot', 'add_hist_plot', 'remove_plot', 'remove_all', 'get_x_means_plot',
80 'remove_x_means_plot', 'set_fit_ix', 'set_xmeans_fit_ix']
81 - def __init__(self, name='Charts', global_name='QubX.Figures.Charts'):
82 super(SelectFace, self).__init__(name, global_name)
83 self.__ref = Reffer()
84 self.presets = qubx.settings.SettingsMgr['Select']
85 self.presets.OnSet = self.__ref(self.__onPreSet)
86 self.__profile = self.presets.active
87 self.__recent_criteria = self.__profile['RecentCriteria']
88 self.__recent_weights = self.__profile['RecentWeights']
89 self.__fit_ix = None
90 self.__xmeans_fit_ix = None
91 self.__actionlist = []
92 self.plots = []
93 self.plots_showing = {}
94 self.x_means_plots = []
95 self.x_means = {}
96 self.table_names = []
97 self.table_events = []
98 self.tb_by_name = {}
99 self.__colors = collections.defaultdict(lambda: [])
100 self.__fields = collections.defaultdict(lambda: set())
101 self.__plots_using_field = collections.defaultdict(lambda: collections.defaultdict(lambda: []))
102 self.missing = memoize(self.__missing)
103 self.vals = collections.defaultdict(lambda: collections.defaultdict(lambda: self.missing))
104 self.mean = collections.defaultdict(lambda: collections.defaultdict(lambda: self.missing))
105 self.std = collections.defaultdict(lambda: collections.defaultdict(lambda: self.missing))
106 self.median = collections.defaultdict(lambda: collections.defaultdict(lambda: self.missing))
107 self.mode = collections.defaultdict(lambda: collections.defaultdict(lambda: self.missing))
108 self.v_fields = {}
109 self.v_names = {}
110 self.vvv = {}
111
112 self.panLeftRight = pack_item(gtk.HBox(), self, expand=True)
113 self.panLeft = pack_item(gtk.VBox(), self.panLeftRight)
114 self.popupActions = gtk.Menu()
115 self.mnuActions = pack_item(qubx.toolspace.Button_Popup(self.popupActions, color=COLOR_ACTIONS, tooltip='Click for Charts menu',
116 on_popup=self.__ref(self.__onPopupActions)),
117 self.panLeft)
118 self.palette = pack_item(qubx.toolspace.Palette(columns=2), self.panLeft, expand=True)
119 self.palette.set_tooltip_text('Pick a color, click points to make groups')
120
121 QubX = qubx.pyenv.env.globals['QubX']
122
123 self.empty_msg = pack_item(qubx.toolspace.ToolSpace(), self.panLeftRight, expand=True)
124 self.empty_msg.OnDraw += self.__ref(lambda ctx, w, h: ctx.set_source_rgba(1,1,1,1) or ctx.paint())
125 layer = qubx.toolspace.Layer(x=0, y=0, w=-.01, h=27, cBG=COLOR_EMPTY_BG)
126 layer.add_sublayer(qubx.toolspace.SubLayer_Label("To read a table from disk, or create a new one, use the Tables' file menu",
127 -1, 1, x=6, y=2, w=50, h=1.5,
128 color=COLOR_EMPTY_TEXT, hover_color=COLOR_EMPTY_TEXT))
129 layer.add_sublayer(qubx.toolspace.SubLayer_Label("(blue folder icon in the left-hand sidebar, next to 'Tables').",
130 -1, 1, x=8, y=3.5, w=50, h=1.5,
131 color=COLOR_EMPTY_TEXT, hover_color=COLOR_EMPTY_TEXT))
132 layer.add_sublayer(qubx.toolspace.SubLayer_Label("New Table...", 0, 1, x=15, y=6, w=12, h=1.5, color=COLOR_EMPTY_BTN,
133 border=1, action=self.__ref(lambda x,y,e: QubX.new_table())))
134 layer.add_sublayer(qubx.toolspace.SubLayer_Label("Open Table...", 0, 1, x=30, y=6, w=12, h=1.5, color=COLOR_EMPTY_BTN,
135 border=1, action=self.__ref(lambda x,y,e: QubX.open_table())))
136 layer.add_sublayer(qubx.toolspace.SubLayer_Label("To plot columns from the Tables panel, use the Charts menu",
137 -1, 1, x=6, y=9, w=50, h=1.5,
138 color=COLOR_EMPTY_TEXT, hover_color=COLOR_EMPTY_TEXT))
139 layer.add_sublayer(qubx.toolspace.SubLayer_Label("(triangle at the upper-left of this panel).",
140 -1, 1, x=8, y=10.5, w=50, h=1.5,
141 color=COLOR_EMPTY_TEXT, hover_color=COLOR_EMPTY_TEXT))
142 layer.add_sublayer(qubx.toolspace.SubLayer_Label("Show Plot...", 0, 1, x=30, y=13, w=12, h=1.5, color=COLOR_EMPTY_BTN,
143 border=1, action=self.__ref(lambda x,y,e: self.add_plot())))
144 layer.add_sublayer(qubx.toolspace.SubLayer_Label("To fit large files of sampled data, open them in the Data panel",
145 -1, 1, x=6, y=16, w=50, h=1.5,
146 color=COLOR_EMPTY_TEXT, hover_color=COLOR_EMPTY_TEXT))
147 layer.add_sublayer(qubx.toolspace.SubLayer_Label("(use its blue folder icon [File menu]).",
148 -1, 1, x=8, y=17.5, w=50, h=1.5,
149 color=COLOR_EMPTY_TEXT, hover_color=COLOR_EMPTY_TEXT))
150 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,
151 border=1, action=self.__ref(lambda x,y,e: QubX.Data.request_show())))
152 layer.add_sublayer(qubx.toolspace.SubLayer_Label("To curve-fit any figure, click its fitting icon:",
153 -1, 1, x=6, y=23, w=32, h=1.5,
154 color=COLOR_EMPTY_TEXT, hover_color=COLOR_EMPTY_TEXT))
155 layer.add_sublayer(qubx.fit_space.SubLayer_FitIcon(x=44, y=22, w=3, h=3))
156 self.empty_msg.add_layer(layer)
157
158 self.grid = pack_item(qubx.GTK.AspectGrid(), self.panLeftRight, expand=True, show=False)
159
160 Tables = QubX.Tables
161 Tables.OnAddTable += self.__ref(self.__onAddTable)
162 Tables.OnRemoveTable += self.__ref(self.__onRemoveTable)
163 for tablerec in Tables.tables:
164 self.__onAddTable(tablerec.table)
165
166 self.actions.append(('Plot...', self.add_plot))
167 self.actions.append(('Select all', self.select_all))
168 self.actions.append(('Unselect all (black)', lambda: self.select_all(0)))
169 self.actions.append(('Select by criteria...', self.select_by_criteria))
170 self.actions.append(('Trim...', self.trim))
171 self.actions.append(('K-Means clustering', self.cluster_k_means))
172 self.actions.append(('X-Means clustering...', self.cluster_x_means))
173 self.actions.append(('Edit bounds, all charts...', self.edit_bounds_all))
174
175 self.nbCharts = qubx.notebook.NbItems("All charts", '%s.nbCharts'%self.global_name)
176 self.nbPictures = qubx.notebook.NbItems("All pictures", '%s.nbPictures'%self.global_name)
177 self.nbStats = qubx.notebook.NbTable("All group stats", '%s.nbStats'%self.global_name,
178 self.nb_group_caption, self.nb_group_shape, self.nb_group_headers, self.nb_group_row)
179 qubx.notebook.Notebook.register_auto('Select.XMeans.Chart', 'XMeans Chart, on XMeans')
180 qubx.notebook.Notebook.register_auto('Select.XMeans.Picture', 'XMeans Picture, on XMeans')
181 qubx.notebook.Notebook.register_auto('Select.XMeans.Charts', 'All Charts, on XMeans', True)
182 qubx.notebook.Notebook.register_auto('Select.XMeans.Pictures', 'All Pictures, on XMeans')
183 qubx.notebook.Notebook.register_auto('Select.XMeans.Stats', 'All group stats, on XMeans', True)
184 qubx.notebook.Notebook.register_auto('Select.Parameters', 'Chart fitting Parameters, on Fit', True)
185 qubx.notebook.Notebook.register_auto('Select.Results', 'Chart fitting Results, on Fit', True)
186 qubx.notebook.Notebook.register_auto('Select.Chart', 'Chart, on Fit')
187 qubx.notebook.Notebook.register_auto('Select.Picture', 'Chart Picture, on Fit', True)
188
189 setaside = self.__profile.clone()
190
191 self.__profile.remove(self.__profile['Plots'])
192 self.__onPreSet(self.presets, setaside)
193
194
195 if not self.__profile['BinCount'].data:
196 self.__profile['BinCount'].data = 12
197 if not self.__profile['TrialsPerK'].data:
198 self.__profile['TrialsPerK'].data = 300
199
200 self.__trim_stds = 1.0
201 self.__criteria_expr = ""
202 self.__xmeans_klo = 1
203 self.__xmeans_khi = None
204 self.__xmeans_weight_expr = ""
205 self.__add_table_name = "Segments"
206 actions = property(lambda self: self.__actionlist, None, "to add an item to the Actions menu, insert a tuple ('label', lambda: action())")
213 menu = self.popupActions
214 menu.foreach(lambda item: menu.remove(item))
215 for lbl, func in self.actions:
216 menu.append(build_item(lbl, func))
217
218 menu_presets = gtk.Menu()
219 for name in sorted(self.presets.listNames(), key=lambda x: x.lower()):
220 menu_presets.append(build_item(name, bind(self.__onClickUsePreset, name)))
221 menu_presets.append(build_item('Manage...', self.__onClickManagePresets))
222 menu_presets.append(build_item('Add to menu...', self.__onClickAddPreset))
223 item_presets = build_item('Chart sets')
224 item_presets.set_sensitive(True)
225 item_presets.set_submenu(menu_presets)
226 menu.append(item_presets)
227 return True
229 self.remove_all()
230 for node in qubx.tree.children(updates.find('Plots')):
231 if 'Label' in (str(node.find('Field').data),
232 str(node.find('FieldX').data),
233 str(node.find('FieldY').data)):
234 continue
235 try:
236 if node.name == 'OnePlot':
237 self.add_one_plot(str(node['Table'].data),
238 str(node['Field'].data),
239 bool(node['IsLog'].data[0]),
240 str(node['Ind'].data),
241 bool(node['IndIsLog'].data[0]))
242 elif node.name == 'TwoPlot':
243 self.add_two_plot(str(node['Table'].data),
244 str(node['FieldX'].data),
245 str(node['FieldY'].data),
246 bool(node['IsLogX'].data[0]),
247 bool(node['IsLogY'].data[0]))
248 elif node.name == 'HistPlot':
249 self.add_hist_plot(str(node['Table'].data),
250 str(node['Field'].data),
251 bool(node['IsLog'].data[0]),
252 node['BinCount'].data[0])
253 except:
254 traceback.print_exc()
275 """Makes table_name the default choice for "add a chart", xmeans etc."""
276 self.__add_table_name = table_name
278 QubX = qubx.pyenv.env.globals['QubX']
279 if not (table_name is None):
280 tbn = table_name
281 elif QubX.Tables.find_table(self.__add_table_name):
282 tbn = self.__add_table_name
283 else:
284 tbn = 'Segments'
285 table = QubX.Tables.find_table(tbn)
286 dlg = gtk.Dialog("%s - Add a chart"%QubX.appname, qubx.GTK.get_active_window(), gtk.DIALOG_MODAL)
287 columns = pack_item(gtk.HBox(), dlg.vbox)
288 col = pack_item(gtk.VBox(), columns)
289 pack_label('Table:', col)
290 col = pack_item(gtk.VBox(), columns)
291 self.mnuTable = pack_item(qubx.GTK.StaticComboList(sorted([trec.table.label for trec in QubX.Tables.tables])), col)
292 self.mnuTable.active_text = tbn
293 self.chkTypePlot = pack_radio('Plot', col, on_toggle=self.__ref(self.__onToggleType))
294 self.chkTypeHist = pack_radio('Histogram', col, group=self.chkTypePlot, on_toggle=self.__ref(self.__onToggleType))
295 pack_space(columns, x=20)
296 col = pack_item(gtk.VBox(), columns)
297 line = pack_item(gtk.HBox(), col)
298 self.panVarX = pack_item(gtk.HBox(), line)
299 pack_label('X: ', self.panVarX)
300 self.chkLogX = pack_check('log10', self.panVarX)
301 self.mnuVarX = pack_item(qubx.GTK.DynamicComboBox(), self.panVarX)
302 self.mnuVarX.OnPopulate += self.__ref(self.__onPopulateVar)
303 self.mnuVarX.active_text = 'Index'
304 line = pack_item(gtk.HBox(), col)
305 self.lblYser = pack_label('Y: ', line)
306 self.chkLogY = pack_check('log10', line)
307 self.mnuVarY = pack_item(qubx.GTK.DynamicComboBox(), line)
308 self.mnuVarY.OnPopulate += self.__ref(self.__onPopulateVar)
309 self.mnuVarY.active_text = 'Pick the Y series' if (table is None) else table.fields[-1]
310 self.panHist = pack_item(gtk.HBox(), col, show=False)
311 pack_label('Bins:', self.panHist, expand=True)
312 self.txtHistBins = pack_item(qubx.GTK.NumEntry(self.__profile['BinCount'].data[0], acceptIntGreaterThan(2), width_chars=3), self.panHist)
313 dlg.add_button('Cancel', gtk.RESPONSE_REJECT)
314 dlg.add_button('Plot', gtk.RESPONSE_ACCEPT)
315 response = dlg.run()
316 dlg.destroy()
317 if response == gtk.RESPONSE_ACCEPT:
318 self.__profile['BinCount'].data[0] = self.txtHistBins.value
319 self.__add_table_name = self.mnuTable.active_text
320 self.__onClickPlot()
321 return True
322 else:
323 return False
325 if not chk.get_active():
326 return
327 if chk == self.chkTypePlot:
328 self.panVarX.show()
329 self.lblYser.show()
330 self.panHist.hide()
331 else:
332 self.panVarX.hide()
333 self.lblYser.hide()
334 self.panHist.show()
343 Tables = qubx.pyenv.env.globals['QubX'].Tables
344 table = Tables.find_table(self.mnuTable.active_text)
345 if not table:
346 qubx.GTK.ShowMessage("There is no longer a %s table. Please pick another." % self.mnuTable.active_text)
347 return
348 if self.chkTypePlot.get_active():
349 for field_name in (self.mnuVarX.active_text, self.mnuVarY.active_text):
350 if not (field_name in table.fields):
351 qubx.GTK.ShowMessage("The %s table doesn't have a field %s. Please pick another." % (self.mnuTable.active_text, field_name))
352 return
353 if self.mnuVarX.active_text in table.fields_independent:
354 qubx.pyenv.env.OnScriptable('%s.add_one_plot(%s, %s, %s, %s, %s); QubX.show_charts()' %
355 (self.global_name,
356 repr(table.label), repr(self.mnuVarY.active_text), repr(self.chkLogY.get_active()),
357 repr(self.mnuVarX.active_text), repr(self.chkLogX.get_active())))
358 self.add_one_plot(table.label, self.mnuVarY.active_text, self.chkLogY.get_active(),
359 self.mnuVarX.active_text, self.chkLogX.get_active())
360 else:
361 qubx.pyenv.env.OnScriptable('%s.add_two_plot(%s, %s, %s, %s, %s); QubX.show_charts()' %
362 (self.global_name,
363 repr(table.label), repr(self.mnuVarX.active_text), repr(self.mnuVarY.active_text),
364 repr(self.chkLogX.get_active()), repr(self.chkLogY.get_active())))
365 self.add_two_plot(table.label, self.mnuVarX.active_text, self.mnuVarY.active_text,
366 self.chkLogX.get_active(), self.chkLogY.get_active())
367 else:
368 if not (self.mnuVarY.active_text in table.fields):
369 qubx.GTK.ShowMessage("The %s table doesn't have a field %s. Please pick another." % (self.mnuTable.active_text, self.mnuVarY.active_text))
370 return
371 qubx.pyenv.env.OnScriptable('%s.add_hist_plot(%s, %s, %s, %s); QubX.show_charts()' %
372 (self.global_name,
373 repr(table.label), repr(self.mnuVarY.active_text), repr(self.chkLogY.get_active()),
374 repr(self.txtHistBins.value)))
375 self.add_hist_plot(table.label, self.mnuVarY.active_text, self.chkLogY.get_active(), self.txtHistBins.value)
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)
450 - def trim(self, num_std=None):
451 stds = num_std
452 if stds is None:
453 QubX = qubx.pyenv.env.globals['QubX']
454 dlg = qubx.GTK.NumEntryDialog('%s - Trim'%QubX.appname, qubx.GTK.get_active_window(),
455 "Unselect points outside this many std devs:",
456 self.__trim_stds,
457 acceptFloatGreaterThan(0.0), '%.5g')
458 response = dlg.run()
459 dlg.destroy()
460 if response == gtk.RESPONSE_ACCEPT:
461 stds = self.__trim_stds = dlg.value
462 else:
463 return
464 qubx.pyenv.env.OnScriptable('%s.trim(num_std=%s)' % (self.global_name, repr(stds)))
465 def trim_fields(table, fields):
466 colors = self.__colors[table.label][:]
467 for field in fields:
468 for color in table.groups_occupied():
469 ixs = table.rows_in_group(color)
470 vals = self.vals[table.label][field](color)
471 mean = self.mean[table.label][field](color)
472 std = self.std[table.label][field](color)
473 for i,v in izip(ixs, vals):
474 if abs(v - mean) > std:
475 colors[i] = 0
476 self.set_colors(table.label, colors)
477 if self.__fit_ix is None:
478 for table in self.tb_by_name.values():
479 trim_fields(table, self.__fields[table.label])
480 else:
481 plot = self.plots[self.__fit_ix]
482 trim_fields(plot.table, plot.fields)
484 qubx.pyenv.env.OnScriptable('%s.cluster_k_means(table_name=%s)' % (self.global_name, repr(table_name)))
485 if (table_name is None) and not (self.__fit_ix is None):
486 table_names = [self.plots[self.__fit_ix].table_name]
487 fields = {table_names[0] : self.plots[self.__fit_ix].fields}
488 elif table_name:
489 table_names = [table_name]
490 fields = self.__fields
491 else:
492 table_names = self.tb_by_name.keys()
493 fields = self.__fields
494 for table_name in table_names:
495 table = self.tb_by_name[table_name]
496 if table_name in self.x_means:
497 wgt = self.x_means[table_name].weight_expr
498 else:
499 wgt = ""
500 colors = self.__colors[table_name][:]
501 color_set = set(colors)
502 k = len(color_set)
503 if 0 in color_set:
504 k -= 1
505 if k <= 0:
506 k = 1
507
508
509 try:
510 ww = self.__evalXMeansWeight(wgt, table=table)
511 except:
512 ww = array([1.0]*table.size, dtype='float32')
513 clusterer = qubx.fast.kmeans.Clusterer([vv for vv in [self.vals[table_name][field]() for field in fields[table_name]] if len(vv)],
514 ww)
515 ssd = clusterer.cluster(colors)
516 self.set_colors(table_name, colors)
517 LL, aicc = clusterer.ll_aicc(colors, k)
518 self.get_x_means_plot(table_name).set_ssd(k, ssd, LL, aicc, clusterer.Ndata, clusterer.Nseries)
520 if not self.plots:
521 return 0.0
522
523
524
525
526 clust = clusterer
527 if clusterer is None:
528 if (not (self.__fit_ix is None)) and (table_name == self.plots[self.__fit_ix].table_name):
529 fields = {table_name : self.plots[self.__fit_ix].fields}
530 else:
531 fields = self.__fields
532 table = self.tb_by_name[table_name]
533 wgt = self.x_means[table_name].weight_expr
534 try:
535 ww = self.__evalXMeansWeight(wgt, table=table)
536 except:
537 ww = array([1.0]*table.size, dtype='float32')
538 clust = qubx.fast.kmeans.Clusterer([vv for vv in [self.vals[table_name][field]() for field in fields[table_name]] if len(vv)],
539 ww)
540 tpk = trials_per_k
541 if tpk is None:
542 tpk = self.x_means[table_name].trials_per_k
543
544 colors = self.__colors[table_name][:]
545 ssd = clust.cluster_trials(colors, k, tpk)
546
547 self.set_colors(table_name, colors)
548 if not clusterer:
549 LL, aicc = clust.ll_aicc(colors, k)
550 self.get_x_means_plot(table_name).set_ssd(k, ssd, LL, aicc, clust.Ndata, clust.Nseries)
551 return ssd
552 - def cluster_x_means(self, table_name=None, k_min=None, k_max=None, trials_per_k=None, weight=None):
553 if not self.plots:
554 return
555 tbn = table_name
556 klo = k_min
557 khi = k_max
558 tpk = trials_per_k
559 wgt = weight
560 if (table_name is None) or (k_min is None) or (k_max is None) or (trials_per_k is None) or (weight is None):
561 if tbn is None:
562 if self.__add_table_name in self.tb_by_name:
563 tbn = self.__add_table_name
564 else:
565 tbn = self.tb_by_name.keys()[0]
566 if klo is None: klo = self.__xmeans_klo
567 if khi is None: khi = self.__xmeans_khi or int(round(sqrt(self.tb_by_name[tbn].size)))
568 if tpk is None: tpk = self.__profile['TrialsPerK'].data[0]
569 if wgt is None: wgt = self.__xmeans_weight_expr
570
571 QubX = qubx.pyenv.env.globals['QubX']
572 dlg = gtk.Dialog("%s - Charts - X-Means Clustering"%QubX.appname, qubx.GTK.get_active_window(), gtk.DIALOG_MODAL)
573 line = pack_item(gtk.HBox(True), dlg.vbox)
574 pack_label('Table:', line)
575 mnuTable = self.mnuXMeansTable = pack_item(qubx.GTK.StaticComboList(sorted([x for x in self.tb_by_name.keys()])), line)
576 line = pack_item(gtk.HBox(True), dlg.vbox)
577 pack_label('Min K:', line)
578 txtKlo = pack_item(qubx.GTK.NumEntry(klo, acceptIntGreaterThan(0)), line)
579 line = pack_item(gtk.HBox(True), dlg.vbox)
580 pack_label('Max K:', line)
581 txtKhi = pack_item(qubx.GTK.NumEntry(khi, acceptIntGreaterThan(0)), line)
582 line = pack_item(gtk.HBox(True), dlg.vbox)
583 pack_label('Trials/K:', line)
584 txtTrials = pack_item(qubx.GTK.NumEntry(tpk, acceptIntGreaterThan(0)), line)
585 line = pack_item(gtk.HBox(), dlg.vbox)
586 pack_label('Weight:', line)
587 txtWeight = self.txtXMeansWeight = pack_item(qubx.GTK.NumEntry(wgt, self.__acceptXMeansWeight), line, expand=True)
588 txtWeight.onParse(True)
589 btnHelp = pack_item(qubx.pyenvGTK.HelpTestButton(txtWeight), line)
590 btnHelp.caption = "Enter an expression in terms of field_name"
591 btnHelp.help_msg = XMEANS_WEIGHT_HELP
592 btnHelp.bind = lambda expr: qubx.pyenv.env.globals.__setitem__('xmeans_weight', lambda i: self.__evalXMeansWeight(expr=expr, indices=[i])[0])
593 btnHelp.write_test = lambda expr: 'xmeans_weight(0)'
594 self.mnuRecent = gtk.Menu()
595 for node in qubx.tree.children(self.__recent_weights):
596 entry = node.name
597 build_menuitem(entry, self.__ref(bind(self.txtXMeansWeight.setValue, entry, parse=True)), menu=self.mnuRecent)
598 self.btnRecent = pack_item(qubx.toolspace.Button_Popup(self.mnuRecent, tooltip='Recent...'), line)
599
600 dlg.add_button('Cancel', gtk.RESPONSE_REJECT)
601 dlg.add_button('OK', gtk.RESPONSE_ACCEPT)
602 response = dlg.run()
603 dlg.destroy()
604 if response != gtk.RESPONSE_ACCEPT:
605 return
606 tbn = mnuTable.active_text
607 klo = txtKlo.value
608 khi = txtKhi.value
609 tpk = txtTrials.value
610 wgt = txtWeight.value
611 self.__profile['TrialsPerK'].data[0] = tpk
612 self.__add_table_name = tbn
613 self.__xmeans_klo = klo
614 self.__xmeans_khi = khi
615 self.__xmeans_weight_expr = wgt
616
617 qubx.pyenv.env.OnScriptable('%s.cluster_x_means(table_name=%s, k_min=%s, k_max=%s, trials_per_k=%s, weight=%s)' %
618 (self.global_name, repr(tbn), repr(klo), repr(khi), repr(tpk), repr(wgt)))
619
620 if (not (self.__fit_ix is None)) and (tbn == self.plots[self.__fit_ix].table_name):
621 fields = {tbn : self.plots[self.__fit_ix].fields}
622 else:
623 fields = self.__fields
624 table = self.tb_by_name[tbn]
625 try:
626 ww = self.__evalXMeansWeight(wgt, table=table)
627 self.__add_recent(self.__recent_weights, wgt)
628 except:
629 ww = array([1.0]*table.size, dtype='float32')
630
631 colors = self.__colors[tbn][:]
632 color_set = set(colors)
633 orig_k = len(color_set)
634 if 0 in color_set:
635 orig_k -= 1
636
637 clusterer = qubx.fast.kmeans.Clusterer([vv for vv in [self.vals[tbn][field]() for field in fields[tbn]] if len(vv)], ww)
638
639 k_ssd_ll_aicc = []
640 for k in xrange(klo, khi+1):
641 ssd = self.cluster_x_means_k(tbn, k, trials_per_k=tpk, clusterer=clusterer)
642 LL, aicc = clusterer.ll_aicc(self.__colors[tbn], k)
643 k_ssd_ll_aicc.append((k, ssd, LL, aicc))
644
645 plot = self.get_x_means_plot(tbn)
646 plot.weight_expr = wgt
647 plot.trials_per_k = tpk
648 for k, ssd, LL, aicc in k_ssd_ll_aicc:
649 plot.set_ssd(k, ssd, LL, aicc, clusterer.Ndata, clusterer.Nseries)
650 if orig_k > 0:
651 self.cluster_x_means_k(tbn, orig_k, trials_per_k=tpk, clusterer=clusterer)
652 gobject.idle_add(self.__nb_auto_xmeans, plot)
683 if not self.plots:
684 return
685 if y1 is None:
686 x0 = self.plots[0].t0 if (x0 is None) else x0
687 y0 = self.plots[0].d0 if (y0 is None) else y0
688 x1 = self.plots[0].t1 if (x1 is None) else x1
689 y1 = self.plots[0].d1 if (y1 is None) else y1
690 x0, y0, x1, y1 = qubx.fit_space.PromptChartBounds(x0, y0, x1, y1)
691 if x0 is None:
692 return
693 qubx.pyenv.env.OnScriptable('QubX.Charts.edit_bounds_all(x0=%s, y0=%s, x1=%s, y1=%s)' % (x0, y0, x1, y1))
694 for plot in self.plots:
695 plot.set_bounds(x0, y0, x1, y1)
696 - def __reset_stats(self, table_name, field_name=None, is_log=False):
697 if field_name is None:
698 fields = self.vals[table_name].keys()
699 else:
700 fields = [(field_name, is_log)]
701 for field_name, is_log in fields:
702 if (field_name, is_log) in self.vals[table_name]:
703 self.vals[table_name][field_name, is_log].reset()
704 if (field_name, is_log) in self.mean[table_name]:
705 self.mean[table_name][field_name, is_log].reset()
706 self.std[table_name][field_name, is_log].reset()
707 self.median[table_name][field_name, is_log].reset()
708 self.mode[table_name][field_name, is_log].reset()
709 self.v_fields[table_name].reset()
710 self.v_names[table_name].reset()
711 self.vvv[table_name].reset()
713 return array([], dtype='float32')
714 - def __vals(self, table_name, field_name, is_log, group=None):
715 table = qubx.pyenv.env.globals['QubX'].Tables.find_table(table_name)
716 if (not table) or not (field_name in table.fields):
717 return self.__missing()
718 try:
719 vals = array([table.get(i, field_name) for i in table.rows_in_group(group)], dtype='float32')
720 if is_log:
721 for i,v in enumerate(vals):
722 if v > 0.0:
723 vals[i] = log10(v)
724 else:
725 vals[i] = 0.0
726 return vals
727 except ValueError, ve:
728 traceback.print_exc()
729 print 'select_charts.SelectFace.__vals(%s, %s, %s, %s) raised %s' % (table_name, field_name, is_log, group, ve)
730 return zeros(shape=(table.size,), dtype='float32')
731 - def __mean(self, table_name, field_name, is_log, group=None):
732 tot = 0.0
733 cnt = 0
734 for v in self.vals[table_name][field_name, is_log](group):
735 try:
736 tot += v
737 cnt += 1
738 except:
739 pass
740 return cnt and (tot / cnt) or 0.0
741 - def __std(self, table_name, field_name, is_log, group=None):
742 tot = 0.0
743 cnt = 0
744 mean = self.mean[table_name][field_name, is_log](group)
745 for v in self.vals[table_name][field_name, is_log](group):
746 try:
747 tot += (mean - v)**2
748 cnt += 1
749 except:
750 pass
751 return cnt and sqrt(tot / cnt) or 0.0
764 - def __mode(self, table_name, field_name, is_log, group=None):
765 counter = collections.defaultdict(lambda: 0)
766 for v in self.vals[table_name][field_name, is_log](group):
767 counter[v] += 1
768 counted = collections.defaultdict(lambda: [])
769 maxcnt = 0
770 for val, cnt in counter.iteritems():
771 counted[cnt].append(val)
772 if cnt > maxcnt:
773 maxcnt = cnt
774 modes = counted[maxcnt]
775 if len(modes) > 1:
776 return sum(modes) / len(modes)
777 elif modes:
778 return modes[0]
779 else:
780 return 0.0
797 - def __vvv(self, table_name):
798 if not (table_name in self.tb_by_name):
799 return []
800 table = self.tb_by_name[table_name]
801 if not table:
802 return []
803 return [self.vals[table_name][field_name, False]() for field_name in self.v_fields[table_name]()]
805 return 'Charts group stats'
807 sum = __builtin__.sum
808 return list(set(sum((self.colors_in(tbn) for tbn in self.tb_by_name.keys()), [])))
810 sum = __builtin__.sum
811 return (sum(len(self.__fields[tbn]) for tbn in self.tb_by_name.keys()), 1+4*len(self.nb_group_colors()))
813 sum = __builtin__.sum
814 return ["Name"] + sum((["Mean %d"%c, "Std %d"%c, "Median %d"%c, "Mode %d"%c]
815 for c in self.nb_group_colors()), [])
817 sum = __builtin__.sum
818 tb_order = sorted(self.tb_by_name.keys())
819 order = sorted(sum(([(tbn, field) for field in self.__fields[tbn]] for tbn in tb_order), []), key=lambda x: x[1][0].lower())
820 tbn, field = order[i]
821 return [field[0]] + sum(([stat[tbn][field](c) for stat in (self.mean, self.std, self.median, self.mode)]
822 for c in self.nb_group_colors()), [])
823 - def add_one_plot(self, table_name, field_name, is_log=False, ind_name='Index', ind_is_log=False):
824 if (table_name, field_name, is_log, ind_name, ind_is_log) in self.plots_showing:
825 return self.plots_showing[(table_name, field_name, is_log, ind_name, ind_is_log)]
826 table = self.__bind_plot(table_name, [(field_name, is_log)])
827 xlabel = FieldLabel(table, ind_name, ind_is_log)
828 ylabel = FieldLabel(table, field_name, is_log)
829 if self.vals[table_name][ind_name, ind_is_log] == self.missing:
830 self.vals[table_name][ind_name, ind_is_log] = memoize(bind_with_args(self.__vals, table_name, ind_name, ind_is_log))
831 plot = OnePlot(table_name, field_name, is_log, ylabel, ind_name, ind_is_log, xlabel,
832 self.v_names[table_name], self.vvv[table_name],
833 self.vals[table_name][ind_name, ind_is_log],
834 self.vals[table_name][field_name, is_log],
835 self.mean[table_name][field_name, is_log],
836 self.std[table_name][field_name, is_log],
837 table and table.count_in_group or (lambda g: None),
838 global_name='QubX.Figures.Charts.plots_showing[%s]'%str((table_name, field_name, is_log, ind_name, ind_is_log)))
839 plot.table = table
840 self.plots_showing[(table_name, field_name, is_log, ind_name, ind_is_log)] = plot
841 self.__plots_using_field[table_name][field_name].append(plot)
842 self.__plots_using_field[table_name][ind_name].append(plot)
843 return self.__show_plot(plot)
844 - def add_two_plot(self, table_name, field_name_x, field_name_y, is_log_x=False, is_log_y=False):
845 if (table_name, field_name_x, field_name_y, is_log_x, is_log_y) in self.plots_showing:
846 return self.plots_showing[(table_name, field_name_x, field_name_y, is_log_x, is_log_y)]
847 table = self.__bind_plot(table_name, [(field_name_x, is_log_x), (field_name_y, is_log_y)])
848 xlabel = FieldLabel(table, field_name_x, is_log_x)
849 ylabel = FieldLabel(table, 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 table and table.count_in_group or (lambda g: None),
859 global_name='QubX.Figures.Charts.plots_showing[%s]'%str((table_name, field_name_x, field_name_y, is_log_x, is_log_y)))
860 plot.table = table
861 self.plots_showing[(table_name, field_name_x, field_name_y, is_log_x, is_log_y)] = plot
862 self.__plots_using_field[table_name][field_name_x].append(plot)
863 self.__plots_using_field[table_name][field_name_y].append(plot)
864 return self.__show_plot(plot)
865 - def add_hist_plot(self, table_name, field_name, is_log=False, bin_count=12):
866 if (table_name, field_name, is_log, bin_count) in self.plots_showing:
867 return self.plots_showing[(table_name, field_name, is_log, bin_count)]
868 table = self.__bind_plot(table_name, [(field_name, is_log)])
869 ylabel = FieldLabel(table, field_name, is_log)
870 plot = HistPlot(table_name, field_name, is_log, bin_count, ylabel,
871 self.vals[table_name][field_name, is_log],
872 self.mean[table_name][field_name, is_log],
873 self.std[table_name][field_name, is_log],
874 table and table.count_in_group or (lambda g: None),
875 global_name='QubX.Figures.Charts.plots_showing[%s]'%str((table_name, field_name, is_log, bin_count)))
876 plot.table = table
877 self.plots_showing[(table_name, field_name, is_log, bin_count)] = plot
878 self.__plots_using_field[table_name][field_name].append(plot)
879 return self.__show_plot(plot)
881 if table_name in self.table_names:
882 try:
883 table = self.tb_by_name[table_name]
884 except KeyError:
885 table = None
886 else:
887 self.table_names.append(table_name)
888 self.table_events.append( (self.__ref(bind_with_args(self.__onInsert, table_name)),
889 self.__ref(bind_with_args(self.__onRemoved, table_name)),
890 self.__ref(bind_with_args(self.__onSet, table_name)),
891 self.__ref(bind_with_args(self.__onAddField, table_name))) )
892 self.v_fields[table_name] = memoize(bind(self.__v_fields, table_name))
893 self.v_names[table_name] = memoize(bind(self.__v_names, table_name))
894 self.vvv[table_name] = memoize(bind(self.__vvv, table_name))
895 table = qubx.pyenv.env.globals['QubX'].Tables.find_table(table_name)
896 if table:
897 self.__attach_table(table)
898 for field_name, is_log in fields:
899 self.__fields[table_name].add((field_name, is_log))
900 if self.vals[table_name][field_name, is_log] == self.missing:
901 self.vals[table_name][field_name, is_log] = memoize(bind_with_args(self.__vals, table_name, field_name, is_log))
902 if self.mean[table_name][field_name, is_log] == self.missing:
903 self.mean[table_name][field_name, is_log] = memoize(bind_with_args(self.__mean, table_name, field_name, is_log))
904 if self.std[table_name][field_name, is_log] == self.missing:
905 self.std[table_name][field_name, is_log] = memoize(bind_with_args(self.__std, table_name, field_name, is_log))
906 if self.median[table_name][field_name, is_log] == self.missing:
907 self.median[table_name][field_name, is_log] = memoize(bind_with_args(self.__median, table_name, field_name, is_log))
908 if self.mode[table_name][field_name, is_log] == self.missing:
909 self.mode[table_name][field_name, is_log] = memoize(bind_with_args(self.__mode, table_name, field_name, is_log))
910 return table
937 self.nbPictures.items.remove(plot.nbPicture)
938 self.nbCharts.items.remove(plot.nbChart)
939 if isinstance(plot, OnePlot):
940 del self.plots_showing[(plot.table_name, plot.field_name, plot.is_log, plot.ind_name, plot.ind_is_log)]
941 self.__plots_using_field[plot.table_name][plot.field_name].remove(plot)
942 self.__plots_using_field[plot.table_name][plot.ind_name].remove(plot)
943 elif isinstance(plot, TwoPlot):
944 del self.plots_showing[(plot.table_name, plot.field_name_x, plot.field_name_y, plot.is_log_x, plot.is_log_y)]
945 self.__plots_using_field[plot.table_name][plot.field_name_x].remove(plot)
946 self.__plots_using_field[plot.table_name][plot.field_name_y].remove(plot)
947 elif isinstance(plot, HistPlot):
948 del self.plots_showing[(plot.table_name, plot.field_name, plot.is_log, plot.bin_count)]
949 self.__plots_using_field[plot.table_name][plot.field_name].remove(plot)
950 self.plots.remove(plot)
951 self.__profile['Plots'].remove(plot.as_preset)
952 self.grid.remove(plot)
953 plot.OnClickClose -= self.__ref(self.__onClickClosePlot)
954 plot.OnShowOne -= self.__ref(self.__onShowOne)
955 plot.OnDelOne -= self.__ref(self.__onDelOne)
956 plot.OnSelectOne -= self.__ref(self.__onSelectOne)
957 plot.OnSelectMany -= self.__ref(self.__onSelectMany)
958 plot.OnChangeLayerset -= self.__ref(self.__onChangePlotLayerset)
959 plot.OnKeyPress -= self.__ref(self.__onKeyPress)
960 plot.dispose()
961 tables_remain = set(plot.table_name for plot in self.plots)
962 if not (plot.table_name in tables_remain):
963 if plot.table:
964 self.__detach_table(plot.table)
965 tbi = self.table_names.index(plot.table_name)
966 del self.table_names[tbi]
967 del self.table_events[tbi]
968 del self.__colors[plot.table_name]
969 del self.__fields[plot.table_name]
970 del self.vals[plot.table_name]
971 del self.mean[plot.table_name]
972 del self.std[plot.table_name]
973 del self.median[plot.table_name]
974 del self.mode[plot.table_name]
975 del self.v_fields[plot.table_name]
976 del self.v_names[plot.table_name]
977 del self.vvv[plot.table_name]
978 else:
979 self.__fields[plot.table_name] = set(reduce(operator.add, [p.fields for p in self.plots if p.table_name == plot.table_name], []))
980 if not self.plots:
981 self.grid.hide()
982 self.empty_msg.show()
1099 - def __onSet(self, table_name, i, field_name, val, prev, undoing):
1114 if self.vals[table_name][field_name, False] == self.missing:
1115 self.vals[table_name][field_name, False] = memoize(bind_with_args(self.__vals, table_name, field_name, False))
1116 else:
1117 self.vals[table_name][field_name, False].reset()
1118 for is_log in (False, True):
1119 if (field_name, is_log) in self.__fields[table_name]:
1120 self.__reset_stats(table_name, field_name, is_log)
1121 for plot in self.__plots_using_field[table_name][field_name]:
1122 plot.invalidate()
1127 if ord('0') <= event.keyval <= ord('9'):
1128 self.palette.color = event.keyval - ord('0')
1129 return
1130 if event.keyval in (ord('m'), ord('M')):
1131 self.mnuActions.do_popup()
1132 return
1140 if self.__colors[plot.table_name][ix] != self.palette.color:
1141 qubx.pyenv.env.OnScriptable('%s.set_color(table_name=%s, ix=%s, color=%s)' %
1142 (self.global_name, repr(plot.table_name), repr(ix), repr(self.palette.color)))
1143 self.set_color(plot.table_name, ix, self.palette.color)
1144 else:
1145 qubx.pyenv.env.OnScriptable('%s.set_color(table_name=%s, ix=%s, color=0)' %
1146 (self.global_name, repr(plot.table_name), repr(ix)))
1147 self.set_color(plot.table_name, ix, 0)
1159 if not (ix is None):
1160 self.grid.hide()
1161 self.__fit_grid_ix = self.grid.remove(self.plots[ix], temporary=True)
1162 self.panLeftRight.pack_start(self.plots[ix], True, True)
1163 else:
1164 self.panLeftRight.remove(self.plots[self.__fit_ix])
1165 self.grid.pack_aspect(self.plots[self.__fit_ix], self.__fit_grid_ix)
1166 self.grid.show_all()
1167 self.__fit_ix = ix
1168 fit_ix = property(lambda self: self.__fit_ix, lambda self, ix: self.set_fit_ix(ix),
1169 "warning: must alternate between None and a legit index")
1176 if not (ix is None):
1177 self.grid.hide()
1178 self.__xmeans_fit_grid_ix = self.grid.remove(self.x_means_plots[ix], temporary=True)
1179 self.panLeftRight.pack_start(self.x_means_plots[ix], True, True)
1180 else:
1181 self.panLeftRight.remove(self.x_means_plots[self.__xmeans_fit_ix])
1182 self.grid.pack_aspect(self.x_means_plots[self.__xmeans_fit_ix], self.__xmeans_fit_grid_ix)
1183 self.grid.show_all()
1184 self.__xmeans_fit_ix = ix
1185 xmeans_fit_ix = property(lambda self: self.__xmeans_fit_ix, lambda self, ix: self.set_xmeans_fit_ix(ix),
1186 "warning: must alternate between None and a legit index")
1188 if not showing:
1189 if not (self.__fit_ix is None):
1190 self.plots[self.__fit_ix].layerset = self.plots[self.__fit_ix].controlsHidden
1191 if not (self.__xmeans_fit_ix is None):
1192 self.x_means_plots[self.__xmeans_fit_ix].layerset = self.x_means_plots[self.__xmeans_fit_ix].controlsHidden
1208
1209
1211 if x0 > x1:
1212 x0, x1 = x1, x0
1213 if y0 > y1:
1214 y0, y1 = y1, y0
1215 return x0, y0, x1, y1
1216
1218 """Returns the Euclidean distance between (x1, y1) and (x2, y2)."""
1219 return sqrt((x2 - x1)**2 + (y2 - y1)**2)
1220
1236 qubx.fit_space.FitSpaceCursor.onPress(self, x, y, e)
1237 self.press_ix = self.space.dotmap.find(x, y, self.space.dot_rad_pix)
1238 self.press_pt = (x, y)
1239 if self.press_ix >= 0:
1240 self.__menuWaiting = True
1241 gobject.timeout_add(MENU_TIMEOUT, self.__onMenuTimeout,
1242 Anon(x=e.x, y=e.y, button=e.button, time=e.time))
1269 self.press_ix = self.space.dotmap.find(x, y, self.space.dot_rad_pix)
1270 if self.press_ix >= 0:
1271 self.mnuDot.popup(None, None, None, 0, e.time)
1280
1281
1283 - def __init__(self, label='Select', **kw):
1284 qubx.fit_space.FitSpace.__init__(self, label=label, **kw)
1285 self.__ref = Reffer()
1286 self.layerset = self.controlsHidden
1287 self.tool_select = SelectCursor(self)
1288 self.data_width = 0.0
1289 self.draw_fit_when_hidden = False
1290 self.extra_rad = self.extra_width = 0
1291 self.subCaption.w = -3
1292 self.OnClickClose = WeakEvent()
1293 self.OnShowOne = WeakEvent()
1294 self.OnDelOne = WeakEvent()
1295 self.OnSelectOne = WeakEvent()
1296 self.OnSelectMany = WeakEvent()
1297 self.OnDraw += self.__ref(self.on_overlay)
1298 self.OnOverlay += self.__ref(self.__onOverlay)
1299 self.as_preset = qubx.tree.Node('SelectPlot')
1300 self.__colors = []
1301 self.__serial = 0
1302 self.fields = []
1303 self.palette = None
1304 self.dot_rad_pix = 1
1305 self.dotmap = qubx.fast.clickmap.DotMap()
1306 self.__table = None
1307 self.__fitall = None
1308 self.__mnuGroup = None
1309 self.__mnuGroupIgnore = False
1310 self.subClose = qubx.toolspace.SubLayer_Label('X', 0, 1, x=-1.5, w=1.5, h=qubx.fit_space.LINE_EMS,
1311 color=qubx.fit_space.COLOR_FITSPACE_BUTTON,
1312 action=self.__ref(self.__onClickClose))
1313 self.layCaption.add_sublayer(self.subClose)
1314
1315 self.layTools = qubx.toolspace.Layer_Toolbar(dim=1, x=self.layZoom.rq_x, y=self.layZoom.rq_y+self.layZoom.rq_h, w=self.layZoom.rq_w)
1316 self.add_layer(self.layTools)
1317 self.layTools.add_tool('Pick Scroll cursor', qubx.toolspace.SubLayer_PanIcon(), qubx.fit_space.FitSpaceCursor(self))
1318 self.layTools.add_tool('Pick Select cursor', SubLayer_SelectIcon(), self.tool_select, active=True)
1319
1320 self.layNotebook = qubx.toolspace.Layer(x=1, y=-5.5-qubx.fit_space.LINE_EMS, w=2, h=2, cBG=qubx.toolspace.COLOR_CLEAR)
1321 self.subNotebook = qubx.notebookGTK.SubLayer_Notebook(x=0, y=0, w=2, h=2)
1322 self.layNotebook.add_sublayer(self.subNotebook)
1323 self.add_layer(self.layNotebook)
1324 self.nbChart = qubx.notebook.NbChart('Chart', self.global_name and ('%s.nbChart'%self.global_name) or '',
1325 lambda: self.caption,
1326 self.nb_get_shape, self.nb_get_headers,
1327 get_col=self.nb_get_col, get_type=lambda: float,
1328 get_series=self.nb_get_series,
1329 get_colors=self.nb_get_colors, get_color_indices=self.nb_get_color_indices)
1330 self.subNotebook.items.append(self.nbChart)
1331 self.nbPicture = qubx.notebookGTK.NbPicture('Picture', self.global_name and ('%s.nbPicture'%self.global_name) or '',
1332 self.nb_picture_get_shape,
1333 self.nb_picture_draw)
1334 self.subNotebook.items.append(self.nbPicture)
1335 self.nbStats = qubx.notebook.NbDynText('Group stats', self.global_name and ('%s.nbStats'%self.global_name) or '',
1336 self.nb_get_group_stats)
1337 self.subNotebook.items.append(self.nbStats)
1338 self.nbParams = qubx.notebook.NbDynText('Parameters', self.global_name and ('%s.nbParams'%self.global_name) or '',
1339 self.controls.nb_get_param_text)
1340 self.nbParams.std_err_est = None
1341 self.controls.robot.OnExpr += self.__ref(self.__onExpr)
1342 self.controls.robot.OnParam += self.__ref(self.__onParam)
1343 self.controls.robot.OnStats += self.__ref(self.__onStats)
1344 self.controls.robot.OnIteration += self.__ref(self.__onIteration)
1345 self.controls.robot.OnEndFit += self.__ref(self.__onEndFit)
1346 self.OnChangeLayerset += self.__ref(self.__onChangeLayerset)
1347 self.__nb_next_stats = False
1348 table = property(lambda self: self.__table, lambda self, x: self.set_table(x))
1350 if not (self.__fitall is None):
1351 self.__fitall.OnSet -= self.__ref(self.__onSetFitAll)
1352 self.OnChangeLayerset -= self.__ref(self.__onChangeLayerset)
1353 self.__table = x
1354 self.__fitall = x.custom.fitall if (not (x is None)) else None
1355 if not (self.__fitall is None):
1356 self.__fitall.OnSet += self.__ref(self.__onSetFitAll)
1357 self.OnChangeLayerset += self.__ref(self.__onChangeLayerset)
1358 self.__fitall_index = x.custom.fitall_index
1359 self.draw_fit_when_hidden = True
1360 if not self.__mnuGroup:
1361 self.__mnuGroup = gtk.Menu()
1362 self.__itemGroup = [
1363 build_menuitem('0: good fit', self.__ref(bind(self.__onItemGroup, 0)), menu=self.__mnuGroup, item_class=gtk.CheckMenuItem),
1364 build_menuitem('1: fit again', self.__ref(bind(self.__onItemGroup, 1)), menu=self.__mnuGroup, item_class=gtk.CheckMenuItem),
1365 build_menuitem('2: discard', self.__ref(bind(self.__onItemGroup, 2)), menu=self.__mnuGroup, item_class=gtk.CheckMenuItem)
1366 ]
1367 self.layTools.add_tool('FitAll: assign group', qubx.toolspace.SubLayer_Popup(self.__mnuGroup, qubx.toolspace.COLOR_WHITE, on_popup=self.__ref(self.__onPopupGroup), w=2.5, h=2.5))
1369 if (field == 'Group') and (index == self.__fitall_index):
1370 self.redraw_canvas(False)
1372 group = self.__fitall[self.__fitall_index, 'Group']
1373 self.__mnuGroupIgnore = True
1374 for i, item in enumerate(self.__itemGroup):
1375 item.set_active(i == group)
1376 self.__mnuGroupIgnore = False
1377 return True
1379 if not self.__mnuGroupIgnore:
1380 self.__fitall[self.__fitall_index, 'Group'] = g
1382 if layerset == self.controls:
1383 self.fitall.select(self.__fitall_index, sender=self)
1385 self.OnClickClose(self)
1389 colors = property(lambda self: self.__colors, lambda self, x: self.set_colors(x))
1391 self.__serial += 1
1392 gobject.idle_add(self.__update_plot, self.__serial)
1394 if serial != self.__serial:
1395 return
1396 self.update_plot()
1402 - def __onExpr(self, curve_name, expr, params, param_vals, lo, hi, can_fit):
1403 self.__param_names = params
1404 self.__param_vals = param_vals
1405 self.__param_active = can_fit
1406 - def __onParam(self, index, name, value, lo, hi, can_fit):
1413 self.__nb_next_stats = True
1414 - def __onStats(self, correlation, is_pseudo, std_err_est, ssr, r2, runs_prob):
1415 if self.__nb_next_stats:
1416 self.__nb_next_stats = False
1417 n = len(self.get_yy())
1418 caption = self.caption
1419 qubx.notebook.Notebook.send(qubx.notebook.NbText("""%(caption)s fitting finished.
1420 \tN: %(n)i
1421 \tSSR: %(ssr).6g
1422 \tR^2: %(r2).6g
1423 \tWald-Wolfowitz runs probability: %(runs_prob).6g
1424 \tCorrelation:
1425 %(correlation)s
1426 """ % locals()), auto_id='Select.Results')
1427 self.nbParams.std_err_est = std_err_est
1428 qubx.notebook.Notebook.send(self.nbParams, auto_id='Select.Parameters')
1429 qubx.notebook.Notebook.send(self.nbChart, auto_id='Select.Chart')
1430 qubx.notebook.Notebook.send(self.nbPicture, auto_id='Select.Picture')
1431 self.nbParams.std_err_est = None
1439 raise Exception('unimplemented abstract method')
1453 raise Exception('unimplemented abstract method')
1454
1455
1457 - 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, get_count, **kw):
1458 SelectPlot.__init__(self, 'Chart.%s'%ylabel, **kw)
1459 self.__ref = Reffer()
1460 self.as_preset.name = 'OnePlot'
1461 self.as_preset['Table'].data = self.table_name = table_name
1462 self.as_preset['Field'].data = self.field_name = field_name
1463 self.as_preset['IsLog'].data = self.is_log = is_log
1464 self.as_preset['Ind'].data = self.ind_name = ind_name
1465 self.as_preset['IndIsLog'].data = self.ind_is_log = ind_is_log
1466 self.get_v_names = get_v_names
1467 self.get_vvv = get_vvv
1468 self.get_xx = get_xx
1469 self.get_yy = get_yy
1470 self.get_mean = get_mean
1471 self.get_std = get_std
1472 self.get_count = get_count
1473 if xlabel == 'Index':
1474 self.caption = ylabel
1475 else:
1476 self.caption = '%s v. %s' % (ylabel, xlabel)
1477 self.fields = [(field_name, is_log)]
1478 self.invalidate()
1480 xx, yy = self.get_xx(), self.get_yy()
1481 if len(xx) != len(yy):
1482 xx = yy = []
1483 self.controls.robot.set_data(xx, yy, self.get_vvv(), self.get_v_names())
1485 context.set_source_rgb(.1,.1,.1)
1486 context.set_line_width(2.0)
1487 context.rectangle(0,0,w,h)
1488 context.stroke()
1489 lookup = self.appearance.color
1490 color = qubx.modelGTK.COLOR_CLASS
1491 t2x, d2y = self.t2x, self.d2y
1492 rad = self.dot_rad_pix = self.data_rad*self.appearance.emsize
1493 twopi = 2*pi
1494 xx, yy = self.get_xx(), self.get_yy()
1495 for x, y, c in izip(xx, yy, self.colors):
1496 context.set_source_rgba(*lookup(color(c)))
1497 context.arc(t2x(x), d2y(y), rad, 0, twopi)
1498 context.fill()
1499 if self.table:
1500 for c in self.table.groups_occupied():
1501 mean, std = self.get_mean(c), self.get_std(c)
1502 context.set_source_rgba(*qubx.toolspace.SETALPHA(lookup(color(c)), CENTROID_ALPHA))
1503 context.move_to(0, d2y(mean-std))
1504 context.line_to(w, d2y(mean-std))
1505 context.line_to(w, d2y(mean+std))
1506 context.line_to(0, d2y(mean+std))
1507 context.fill()
1508 self.dotmap.reset([t2x(x) for x in xx], [d2y(y) for y in yy])
1509
1510
1511
1513 - 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, get_count, **kw):
1514 SelectPlot.__init__(self, 'Chart.%s.v.%s' % (xlabel, ylabel), **kw)
1515 self.as_preset.name = 'TwoPlot'
1516 self.as_preset['Table'].data = self.table_name = table_name
1517 self.as_preset['FieldX'].data = self.field_name_x = field_name_x
1518 self.as_preset['FieldY'].data = self.field_name_y = field_name_y
1519 self.as_preset['IsLogX'].data = self.is_log_x = is_log_x
1520 self.as_preset['IsLogY'].data = self.is_log_y = is_log_y
1521 self.get_v_names = get_v_names
1522 self.get_vvv = get_vvv
1523 self.get_xx = get_xx
1524 self.get_yy = get_yy
1525 self.get_mean_x = get_mean_x
1526 self.get_mean_y = get_mean_y
1527 self.get_std_x = get_std_x
1528 self.get_std_y = get_std_y
1529 self.get_count = get_count
1530 self.caption = '%s v. %s' % (ylabel, xlabel)
1531 self.fields = [(field_name_x, is_log_x), (field_name_y, is_log_y)]
1532 self.invalidate()
1534 xx, yy = self.get_xx(), self.get_yy()
1535 if len(xx) != len(yy):
1536 xx = yy = []
1537 self.controls.robot.set_data(xx, yy, self.get_vvv(), self.get_v_names())
1539 context.set_source_rgb(.1,.1,.1)
1540 context.set_line_width(2.0)
1541 context.rectangle(0,0,w,h)
1542 context.stroke()
1543 lookup = self.appearance.color
1544 color = qubx.modelGTK.COLOR_CLASS
1545 t2x, d2y = self.t2x, self.d2y
1546 rad = self.dot_rad_pix = self.data_rad*self.appearance.emsize
1547 twopi = 2*pi
1548 xx, yy = self.get_xx(), self.get_yy()
1549 for x, y, c in izip(xx, yy, self.colors):
1550 context.set_source_rgba(*lookup(color(c)))
1551 context.arc(t2x(x), d2y(y), rad, 0, twopi)
1552 context.fill()
1553 if self.table:
1554 for c in self.table.groups_occupied():
1555 mean_x, std_x = self.get_mean_x(c), self.get_std_x(c)
1556 mean_y, std_y = self.get_mean_y(c), self.get_std_y(c)
1557 if std_x and std_y:
1558 context.save()
1559 context.translate(t2x(mean_x), d2y(mean_y))
1560 context.scale(t2x(mean_x+std_x)-t2x(mean_x),
1561 d2y(mean_y-std_y)-d2y(mean_y))
1562 context.set_source_rgba(*qubx.toolspace.SETALPHA(lookup(color(c)), CENTROID_ALPHA))
1563 context.arc(0, 0, 1.0, 0, 2*pi)
1564 context.fill()
1565 context.restore()
1566 self.dotmap.reset([t2x(x) for x in xx], [d2y(y) for y in yy])
1568 return self.caption+":\n"+"\n".join(["%4d: %.6g +/- %.6g\t,\t%.6g +/- %.6g\t(%d)" %
1569 (c, self.get_mean_x(c), self.get_std_x(c), self.get_mean_y(c), self.get_std_y(c), self.get_count(c))
1570 for c in sorted(list(set(self.colors)))])
1571
1573 - def __init__(self, table_name, field_name, is_log, bin_count, ylabel, get_yy, get_mean, get_std, get_count, **kw):
1574 SelectPlot.__init__(self, 'Chart.Hist.%s'%ylabel, **kw)
1575 self.draw_hist = True
1576 self.hist_width = 0.95
1577 self.as_preset.name = 'HistPlot'
1578 self.as_preset['Table'].data = self.table_name = table_name
1579 self.as_preset['Field'].data = self.field_name = field_name
1580 self.as_preset['IsLog'].data = self.is_log = is_log
1581 self.as_preset['BinCount'].data = self.bin_count = bin_count
1582 self.get_yy = get_yy
1583 self.get_mean = get_mean
1584 self.get_std = get_std
1585 self.get_count = get_count
1586 self.caption = ylabel
1587 self.xx = self.yy = self.stacking = []
1588 self.fields = [(field_name, is_log)]
1589 self.nbHist = qubx.notebook.NbChart('Histogram', self.global_name and ('%s.nbHist'%self.global_name) or '',
1590 lambda: self.caption,
1591 self.controls.nb_get_shape, self.nb_hist_get_headers,
1592 get_col=self.nb_get_col, get_type=lambda: float,
1593 get_series=self.nb_hist_get_series,
1594 get_colors=self.nb_get_colors, get_color_indices=self.nb_get_color_indices)
1595 self.subNotebook.items.append(self.nbHist)
1596 self.invalidate()
1601 context.set_source_rgb(.1,.1,.1)
1602 context.set_line_width(2.0)
1603 context.rectangle(0,0,w,h)
1604 context.stroke()
1605 if not len(self.xx):
1606 return
1607 lookup = self.appearance.color
1608 color = qubx.modelGTK.COLOR_CLASS
1609 t2x, d2y = self.t2x, self.d2y
1610 em = self.appearance.emsize
1611 rad = self.dot_rad_pix = min(self.data_rad*em, w/(2*len(self.xx)))
1612 twopi = 2*pi
1613 for x, y, c in izip(self.get_yy(), self.stacking, self.colors):
1614 context.set_source_rgba(*lookup(color(c)))
1615 context.arc(t2x(x), d2y(y), rad, 0, twopi)
1616 context.fill()
1617 if self.table:
1618 border = qubx.fit_space.LINE_EMS*em
1619 for c in self.table.groups_occupied():
1620 mean, std = self.get_mean(c), self.get_std(c)
1621 context.set_source_rgba(*qubx.toolspace.SETALPHA(lookup(color(c)), CENTROID_ALPHA))
1622 context.move_to(t2x(mean-std), border)
1623 context.line_to(t2x(mean-std), h-border)
1624 context.line_to(t2x(mean+std), h-border)
1625 context.line_to(t2x(mean+std), border)
1626 context.fill()
1627 self.dotmap.reset([t2x(x) for x in self.get_yy()], [d2y(y) for y in self.stacking])
1634 nr, nc = self.controls.nb_get_shape()
1635 return (max(nr, len(self.stacking)), nc+3)
1639 if c == 0:
1640 return self.get_yy()
1641 elif c == 1:
1642 return self.stacking
1643 elif c == 2:
1644 return self.colors
1645 else:
1646 return self.controls.nb_get_col(c-3)
1648 return [qubx.notebook.NbChartSeries(0, 1, ser_type=qubx.notebook.DOTS, nrow=len(self.stacking)),
1649 qubx.notebook.NbChartSeries(3, 4, ser_type=qubx.notebook.HISTOGRAM, nrow=len(self.controls.xx)),
1650 qubx.notebook.NbChartSeries(3, 5, ser_type=qubx.notebook.LINES, nrow=len(self.yy))]
1651
1652
1654 """Returns (bins, bin_width) as (numpy.array[n], float)."""
1655 d = (hi - lo)
1656 one = d/n
1657 bins = arange(n, dtype='float64')
1658 bins *= one
1659 bins += lo + one/2
1660 return bins, one
1661
1663 if len(yy) < 2:
1664 return [], [], []
1665 lo = min(yy)
1666 bins, bin_width = make_bins(lo, max(yy), bin_count)
1667 bars = zeros(shape=(bin_count,))
1668 stacking = zeros(shape=(len(yy),))
1669 if len(yy) and bin_count:
1670 one = 1.0 / len(yy)
1671 last = bin_count - 1
1672 data = array(yy)
1673 data -= lo
1674 data /= bin_width
1675 for i,x in enumerate(data.astype('int32')):
1676 ibar = max(0, min(last, x))
1677 stacking[i] = bars[ibar] + one/2
1678 bars[ibar] += one
1679 return bins, bars, stacking
1680
1682 field_label = field_name
1683 if is_log:
1684 field_label = 'log10(%s)' % field_label
1685 if table and (field_name in table.units) and table.units[field_name]:
1686 return '%s [%s]' % (field_label, table.units[field_name])
1687 return field_label
1688
1689
1690 -class CriteriaEntry(gtk.HBox):
1691 __explore_featured = ['recent', 'txtCriteria', 'btnHelp', 'mnuRecent', 'btnRecent', 'table', 'get_rows', 'acceptCriteria', 'update_recent']
1692 - def __init__(self, recent_tree):
1693 gtk.HBox.__init__(self)
1694 self.recent = recent_tree
1695 self.__table = None
1696 self.__ref = Reffer()
1697
1698 pack_label('Pick rows which have', self)
1699 self.txtCriteria = pack_item(qubx.GTK.NumEntry('', self.acceptCriteria), self, expand=True)
1700 self.btnHelp = pack_item(qubx.pyenvGTK.HelpTestButton(self.txtCriteria), self)
1701 self.btnHelp.caption = "Enter an expression in terms of field_name which evaluates True or False"
1702 self.btnHelp.help_msg = CRITERIA_HELP
1703 self.btnHelp.bind = lambda expr: qubx.pyenv.env.globals.__setitem__('rows_meeting_criteria', lambda: rows_meeting_criteria(self.table, expr))
1704 self.btnHelp.write_test = lambda expr: 'print rows_meeting_criteria()'
1705 self.mnuRecent = gtk.Menu()
1706 self.btnRecent = pack_item(qubx.toolspace.Button_Popup(self.mnuRecent, tooltip='Recent...', on_popup=self.__ref(self.__onPopupRecent), color=COLOR_CRITERIA_POPUP), self)
1707 - def set_table(self, x):
1708 self.__table = x
1709 self.txtCriteria.onParse(True)
1710 table = property(lambda self: self.__table, lambda self, x: self.set_table(x))
1711 - def get_rows(self):
1712 return rows_meeting_criteria(self.__table, self.txtCriteria.value)
1713 - def acceptCriteria(self, s):
1714 indices = rows_meeting_criteria(self.table, s, 1)
1715 return s
1717 self.mnuRecent.foreach(lambda item: self.mnuRecent.remove(item))
1718 for entry in qubx.tree.children(self.recent):
1719 build_menuitem(entry.name, self.__ref(bind(self.txtCriteria.setValue, entry.name, parse=True)), menu=self.mnuRecent)
1720 return True
1721 - def update_recent(self):
1722 if self.txtCriteria.value:
1723 self.__add_recent(self.recent, self.txtCriteria.value)
1724 - def __add_recent(self, tree, entry):
1725 if not entry:
1726 return
1727 rec = tree.find(entry)
1728 if not rec.isNull:
1729 tree.remove(rec)
1730 tree.insert(rec)
1731 else:
1732 tree.insert(qubx.tree.Node(entry))
1733 rec = tree.child
1734 for i in xrange(RECENT_COUNT):
1735 rec = rec.sibling
1736 if rec.isNull:
1737 break
1738 while not rec.isNull:
1739 next = rec.sibling
1740 tree.remove(rec)
1741 rec = next
1742
1745 QubX = qubx.pyenv.env.globals['QubX']
1746 gtk.Dialog.__init__(self, "%s - Select by criteria"%QubX.appname, qubx.GTK.get_active_window(), gtk.DIALOG_MODAL)
1747 self.set_size_request(500, -1)
1748 self.tables = tables
1749 self.table = tables[0]
1750 self.__ref = Reffer()
1751 line = pack_item(gtk.HBox(True), self.vbox)
1752 pack_label('Table:', line)
1753 self.mnuTable = pack_item(qubx.GTK.StaticComboList([table.label for table in tables]), line)
1754 self.mnuTable.OnChange += self.__ref(self.__onChangeTable)
1755 self.criteria = pack_item(CriteriaEntry(recent), self.vbox)
1756 self.criteria.table = self.table
1757 self.add_button('Cancel', gtk.RESPONSE_REJECT)
1758 self.add_button('Select', gtk.RESPONSE_ACCEPT)
1759 - def run(self, expr):
1768
1769
1772
1773 CRITERIA_HELP = """Enter a boolean expression such as
1774 (Group == 1) and (Amp_1 > 2.0)
1775
1776 These names are available:
1777 field_name -- val. of field in this row; replace spaces with underscores; match capitalization
1778 row["field name"] -- value of field in this row
1779 field_mean("field name") -- mean value of field
1780 field_std("field name") -- standard deviation of field
1781 field_median("field name") -- median value of field
1782 field_mode("field name") -- most common value of field
1783 group_mean("field name", c) -- mean value of field, group (color) c only
1784 group_std("field name", c) -- standard deviation of field, group (color) c only
1785 group_median("field name", c) -- median value of field, group (color) c only
1786 group_mode("field name", c) -- most common value of field, group (color) c only
1787
1788 Expressions use Python syntax. Full documentation is available at www.python.org.
1789 """ + qubx.pyenv.PYTHON_HELP
1790
1791
1801
1804 qubx.fit_space.FitSpace.__init__(self, label='X-Means SSD', **kw)
1805 self.caption = '%s: X-Means SSD' % table_name
1806 self.table_name = table_name
1807 self.__ref = Reffer()
1808 self.layerset = self.controlsHidden
1809 self.tool = XMeansCursor(self)
1810 self.data_width = 0.0
1811 self.draw_fit_when_hidden = False
1812 self.subCaption.w = -3
1813 self.OnClickClose = WeakEvent()
1814 self.OnClickPoint = WeakEvent()
1815 self.OnClickRefresh = WeakEvent()
1816 self.OnDraw += self.__ref(self.on_overlay)
1817 self.dot_rad_pix = 1
1818 self.dotmap = qubx.fast.clickmap.DotMap()
1819 self.subClose = qubx.toolspace.SubLayer_Label('X', 0, 1, x=-1.5, w=1.5, h=qubx.fit_space.LINE_EMS,
1820 color=qubx.fit_space.COLOR_FITSPACE_BUTTON,
1821 action=self.__ref(self.__onClickClose))
1822 self.layCaption.add_sublayer(self.subClose)
1823
1824 self.layRefresh = qubx.toolspace.Layer(x=-9, y=6, w=8, h=1+qubx.fit_space.LINE_EMS, cBG=self.controls.cLayer)
1825 self.subRefresh = qubx.toolspace.SubLayer_Label('Refresh', 0, 1, y=.5, w=8, h=qubx.fit_space.LINE_EMS, color=self.controls.cButton,
1826 action=self.__ref(lambda x,y,e: self.OnClickRefresh(self)))
1827 self.layRefresh.add_sublayer(self.subRefresh)
1828 self.add_layer(self.layRefresh)
1829
1830 self.layShow = qubx.toolspace.Layer(x=-15, y=4, w=14, h=qubx.fit_space.LINE_EMS, cBG=self.controls.cLayer)
1831 self.subShowSSD = qubx.toolspace.SubLayer_Radio(on_radio=self.__ref(self.__onRadioShow), label='SSD', justify=-1, vcenter=1,
1832 x=0, y=0, w=7, h=qubx.fit_space.LINE_EMS,
1833 color=self.controls.cText, hover_color=self.controls.cText)
1834 self.layShow.add_sublayer(self.subShowSSD)
1835 self.subShowAICc = qubx.toolspace.SubLayer_Radio(fellow=self.subShowSSD, label='AICc', justify=-1, vcenter=1,
1836 x=7, y=0, w=7, h=qubx.fit_space.LINE_EMS,
1837 color=self.controls.cText, hover_color=self.controls.cText)
1838 self.layShow.add_sublayer(self.subShowAICc)
1839 self.add_layer(self.layShow)
1840
1841 self.layHint = qubx.toolspace.Layer(x=-37, y=2.25, w=32, h=qubx.fit_space.LINE_EMS, cBG=qubx.toolspace.COLOR_CLEAR)
1842 self.subHint = qubx.toolspace.SubLayer_Label('Click a point to show the k-clustering', 1, 1, w=32, h=qubx.fit_space.LINE_EMS,
1843 color=self.controls.cText, hover_color=self.controls.cText)
1844 self.layHint.add_sublayer(self.subHint)
1845 self.add_layer(self.layHint)
1846
1847 self.layNotebook = qubx.toolspace.Layer(x=1, y=-5.5-qubx.fit_space.LINE_EMS, w=2, h=2, cBG=qubx.toolspace.COLOR_CLEAR)
1848 self.subNotebook = qubx.notebookGTK.SubLayer_Notebook(x=0, y=0, w=2, h=2)
1849 self.layNotebook.add_sublayer(self.subNotebook)
1850 self.add_layer(self.layNotebook)
1851 self.nbChart = qubx.notebook.NbChart('Chart', self.global_name and ('%s.nbChart'%self.global_name) or '',
1852 lambda: self.caption,
1853 self.controls.nb_get_shape, self.controls.nb_get_headers,
1854 get_col=self.controls.nb_get_col, get_type=lambda: float,
1855 get_series=self.nb_get_series)
1856 self.subNotebook.items.append(self.nbChart)
1857 self.nbPicture = qubx.notebookGTK.NbPicture('Picture', self.global_name and ('%s.nbPicture'%self.global_name) or '',
1858 self.nb_picture_get_shape,
1859 self.nb_picture_draw)
1860 self.subNotebook.items.append(self.nbPicture)
1861 self.ssd = collections.defaultdict(lambda: 0.0)
1862 self.aicc = collections.defaultdict(lambda: 0.0)
1863 self.__xx = self.__yy = []
1864 self.weight_expr = ""
1865 self.trials_per_k = 300
1866 self.__show_aicc = False
1867 xx = property(lambda self: self.__xx)
1868 yy = property(lambda self: self.__yy)
1870 if x == self.__show_aicc: return
1871 self.__show_aicc = x
1872 self.caption = '%s: X-Means %s' % (self.table_name,
1873 x and 'AICc' or 'SSD')
1874 if x:
1875 self.subShowAICc.active = True
1876 else:
1877 self.subShowSSD.active = True
1878 self.update_plot()
1879 show_aicc = property(lambda self: self.__show_aicc, lambda self, x: self.set_show_aicc(x))
1881 self.show_aicc = (sub == self.subShowAICc)
1883 self.OnClickClose(self)
1884 - def set_ssd(self, k, ssd, LL, aicc, Ndata, Nvar):
1885 self.ssd[k] = ssd
1886 self.aicc[k] = aicc
1887 self.update_plot()
1888 - def clear(self, detach=False):
1889 if detach:
1890 self.ssd = collections.defaultdict(lambda: 0.0)
1891 else:
1892 self.ssd.clear()
1893 self.update_plot()
1895 keys = self.ssd.keys()
1896 if keys:
1897 self.__xx = list(range(min(keys), max(keys)+1))
1898 if self.__show_aicc:
1899 self.__yy = [self.aicc[x] for x in self.__xx]
1900 else:
1901 self.__yy = [self.ssd[x] for x in self.__xx]
1902 else:
1903 self.__xx = self.__yy = []
1904 self.controls.robot.set_data(self.__xx, self.__yy)
1906 context.set_source_rgb(.1,.1,.1)
1907 context.set_line_width(2.0)
1908 context.rectangle(0,0,w,h)
1909 context.stroke()
1910
1911 self.dot_rad_pix = self.data_rad*self.appearance.emsize
1912 t2x, d2y = self.t2x, self.d2y
1913 xx, yy = self.__xx, self.__yy
1914 self.dotmap.reset([t2x(x) for x in xx], [d2y(y) for y in yy])
1915
1916 XMEANS_WEIGHT_HELP = """Enter an expression such as
1917 Weight
1918 or 1.0 / Std_1
1919 or Std_1 and (1.0 / Std_1) or 0.0 (avoids division by zero)
1920
1921 These names are available:
1922 field_name -- val. of field in this row; replace spaces with underscores; match capitalization
1923 row["field name"] -- value of field in this row
1924
1925 Expressions use Python syntax. Full documentation is available at www.python.org.
1926 """ + qubx.pyenv.PYTHON_HELP
1927
1928
1930 w = int(w)
1931 h = int(h)
1932 margin = min(w, h)/6
1933 cr.save()
1934 cr.set_line_width(1.0)
1935 cr.set_source_rgba(1, .3, .3, .5)
1936 cr.rectangle(margin, margin, w-3*margin, h/2)
1937 cr.fill_preserve()
1938 cr.set_source_rgba(1, .3, .3, 1)
1939 cr.stroke()
1940 cr.restore()
1941
1943 - def draw(self, context, w, h, appearance):
1946