source: sans/utils/bt5/bt5plot/bt5plot.py @ 922

Last change on this file since 922 was 780, checked in by ajj, 12 years ago

Fix log scaling for old matplotlib (0.91) that is on BT5

  • Property svn:executable set to *
File size: 13.1 KB
Line 
1#!/usr/bin/env python
2
3import sys
4import os
5import re
6import matplotlib
7import numpy
8matplotlib.use('GTK')
9
10from matplotlib.figure import Figure
11from matplotlib.axes import Subplot
12from matplotlib.backends.backend_gtk import FigureCanvasGTK, NavigationToolbar
13
14import usans
15from BT5DataSet import BT5DataSet
16from BT5DataGroup import BT5DataGroup
17
18try:
19    import pygtk
20    pygtk.require("2.0")
21   
22except:
23    pass
24
25try:
26    import gtk
27    import gtk.glade
28except:
29    sys.exit(1)
30
31class appGui:
32   
33    TARGETS = [('STRING', gtk.TARGET_SAME_APP, 0)]
34   
35    def __init__(self):
36
37        runpath = os.path.dirname(os.path.realpath(__file__))
38       
39        gladefile = runpath+"/bt5plot.glade"
40        self.windowname = "win_Main"
41        self.wTree = gtk.glade.XML(gladefile, self.windowname)
42
43        event_dic = {"on_win_Main_destroy" : gtk.main_quit,
44                     "on_quit1_activate" : gtk.main_quit,
45                     "on_set_data_dir1_activate" : self.setdatadir,
46                     "on_xaxis_loglin_activate" : self.handle_xaxis_loglin,
47                     "on_yaxis_loglin_activate" : self.handle_yaxis_loglin,
48                     "on_yaxis_errorbars_activate" : self.handle_yaxis_errorbars,
49                     "on_plot_type_activate" : self.handle_plot_type_change,
50                     "on_btn_ClearPlot_clicked" : self.handle_clearplot,
51                     "on_btn_Refresh_clicked" : self.handle_refreshlist,
52                     "on_btn_Filter_clicked" : self.handle_filter}
53    #                 "on_tv_plotlist_key_press_event" : self.handle_plotlist_keypress}
54
55        #This is a bit clunky, but never mind.
56        #Set default plottype to rate. Glade definition sets that as default active button in menu
57        self.plottype = 'rate'
58        self.yerrorbars = True
59       
60        self.wTree.signal_autoconnect(event_dic)
61
62        # Set up file list
63        self.filelistview = self.wTree.get_widget("tv_filelist")
64       
65        self.filelist = gtk.TreeStore(str, 'gboolean', object)
66        self.filelist.set_sort_column_id(0, gtk.SORT_ASCENDING)
67
68        # Set up filtering of file list
69        self.filter_entry = self.wTree.get_widget("ent_filter")
70        self.filter_string = []
71        self.filter_string.append(self.filter_entry.get_text())
72        self.filelistfilter = self.filelist.filter_new()
73        self.filelistfilter.set_visible_func(self.filter_filelist, self.filter_string)
74
75        self.filelistview.set_model(self.filelistfilter)
76
77        self.cellrenderertoggle = gtk.CellRendererToggle()
78        self.cellrenderertoggle.set_property('activatable', True)
79        self.cellrenderertoggle.connect("toggled", self.handle_plot_toggle, self.filelistfilter)
80   
81        self.AddFileListColumns()
82
83        #fill the file list
84        if (len(sys.argv) > 1):
85                os.chdir(sys.argv[1])
86        self.FillFileList(usans.GetBT5DirList())
87
88        # Set up graphing widget to display data
89        self.figure = Figure(figsize=(4, 4), dpi=72)
90        self.axis = self.figure.add_subplot(111)
91        self.axis.set_yscale('log')
92        self.axis.set_aspect('auto')
93        self.axis.set_autoscale_on('True')
94        self.axis.set_xlabel('Motor position')
95        self.axis.set_ylabel('Counts')
96        self.axis.grid(True)
97       
98        self.canvas = FigureCanvasGTK(self.figure)
99        self.figure.canvas.mpl_connect('pick_event', self.handle_plot_click)
100        self.canvas.show()
101       
102        self.plotView = self.wTree.get_widget("vbox4")
103        self.plotView.pack_start(self.canvas, True, True)   
104       
105        self.metadataView = self.wTree.get_widget("tv_metadata")
106        self.mdlist = gtk.ListStore(str, str)
107       
108       
109    def AddFileListColumns(self):
110        """This function adds a column to the list view.
111        First it create the gtk.TreeViewColumn and then set
112        some needed properties"""
113                       
114        column = gtk.TreeViewColumn('Filename', gtk.CellRendererText(), text=0)
115        column.set_resizable(True)       
116        column.set_sort_column_id(0)
117        self.filelistview.append_column(column)
118
119        column = gtk.TreeViewColumn('', self.cellrenderertoggle, active=1)
120        self.filelistview.append_column(column)
121        return
122       
123   
124    def FillFileList(self, filenames):
125        self.filelist.clear()
126       
127        groupList = self.generateDataGroups(filenames)
128       
129        for group in groupList:
130                self.filelist.append(None, [group.groupName, 0, None])
131               
132        return
133           
134           
135    def generateDataGroups(self,filenames):
136       
137        datasetList = []
138        dataindexList = []
139        datagroupList = []
140       
141       
142        #assuming list hsa come in sorted by date...
143        for filename in filenames:
144            #generate list of BT5DataSet objects
145            datasetList.append(BT5DataSet(filename))
146       
147        #print datasetList
148        #build list of list indices where either scanned motor is A2 or scanned motor is not A2
149        for dataset in datasetList:         
150            if dataset.scanmot == 'A2':
151                #check for 0
152                if 0 in dataset.detdata.keys():
153                    dataindexList.append(datasetList.index(dataset))
154            else:
155                dataindexList.append(datasetList.index(dataset))
156       
157        previndex = 0
158        for dataindex in dataindexList:
159            if dataindexList.index(dataindex) == len(dataindexList)-1:
160                nextindex = len(datasetList)
161            else:
162                nextindex = dataindex
163            datagroupList.append(BT5DataGroup(datasetList[previndex:nextindex]))
164            previndex = dataindex
165       
166        print len(datagroupList)
167       
168        return datagroupList
169   
170   
171    def RefreshFileList(self, filenames):       
172        #print len(filenames)
173       
174        deletelist = []
175        tempstr = self.filter_entry.get_text()
176        del self.filter_string[:]
177        self.filter_string.append("")
178        self.filelistfilter.refilter()
179       
180        treestore = self.filelistview.get_model()
181        treestore.foreach(self.filelist_match_filename, (filenames, deletelist))
182         
183        for filename in filenames:
184            self.filelist.append([filename, 0, None])
185       
186        deletelist.reverse()
187        for path in deletelist:
188            treestore.remove(treestore.get_iter(path))
189
190        del self.filter_string[:]
191        self.filter_string.append(tempstr)
192        self.filelistfilter.refilter()
193        return
194
195    def filelist_match_filename(self, model, path, iter, data):
196       
197        mval = model.get_value(iter, 0)
198       
199        if mval in data[0]:
200            del data[0][data[0].index(mval)]
201        else:
202            data[1].append(path)
203           
204        return False
205   
206    def handle_refreshlist(self, widget):
207
208        self.RefreshFileList(usans.GetBT5DirList())
209       
210        return
211
212    def filter_filelist(self, model, iter, data):
213       
214        if model.get_value(iter, 0):       
215            match = re.match(data[0], model.get_value(iter, 0))
216        else:
217            match = None
218       
219        if match is None:
220            return False
221        else:
222            return True
223       
224    def handle_filter(self, widget):
225       
226        del self.filter_string[:]
227        self.filter_string.append(self.filter_entry.get_text())
228        #print self.filter_string[0]
229        self.filelistfilter.refilter()
230       
231        return
232
233    def setdatadir(self, widget):
234       
235        #Clear plot before selecting new folder
236        #This is a bit clunky, but it avoids a lot of pain for the moment
237       
238        self.clearplot()
239       
240        chooser = gtk.FileChooserDialog(title="Select Data Directory", action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
241                                  buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
242        chooser.set_default_response(gtk.RESPONSE_OK)
243        chooser.set_current_folder(os.getcwd())
244        response = chooser.run()
245        if response == gtk.RESPONSE_OK:
246            os.chdir(chooser.get_filename())
247            self.FillFileList(usans.GetBT5DirList())
248        chooser.destroy()
249
250    def handle_plot_toggle(self, filter_cell, filter_path, filter_model):
251        model = filter_model.get_model()
252        path = filter_model.convert_path_to_child_path(filter_path)
253        model[path][1] = not model[path][1]
254
255        if model[path][1]:
256            #load data
257            model[path][2] = BT5DataSet(model[path][0])
258            #add plot
259            model[path][2].plot_dataset(self.axis, self.plottype, self.yerrorbars)
260            self.rescale_and_redraw()
261        else:
262            #remove plot
263            model[path][2].remove_plot()
264            self.rescale_and_redraw()
265        return
266
267 
268    def handle_xaxis_loglin(self, widget):
269
270
271        if (self.axis.get_xscale() == "log"):
272            self.axis.set_xscale('linear')
273        else:
274            self.axis.set_xscale('log')
275
276        self.rescale_and_redraw()
277       
278        return   
279
280    def handle_yaxis_loglin(self, widget):
281
282
283        if (self.axis.get_yscale() == "log"):
284            self.axis.set_yscale('linear')
285        else:
286            self.axis.set_yscale('log')
287
288        self.rescale_and_redraw()
289        return
290 
291    def handle_yaxis_errorbars(self, widget):
292       
293        if (self.yerrorbars == True):
294            self.yerrorbars = False
295        else:
296            self.yerrorbars = True
297
298        model = self.filelistview.get_model().get_model()
299        iter = model.iter_children(None)
300        while iter:
301            path = model.get_path(iter)
302            if model[path][1] != 0:
303                model[path][2].remove_plot()
304                model[path][2].plot_dataset(self.axis, self.plottype, self.yerrorbars)
305            iter = model.iter_next(iter)
306
307        self.rescale_and_redraw()
308        return
309       
310    def handle_plot_type_change(self, widget):
311               
312        if widget.get_active():
313                self.plottype = widget.get_name().split('_')[1]
314
315        model = self.filelistview.get_model().get_model()
316        iter = model.iter_children(None)
317        while iter:
318            path = model.get_path(iter)
319            if model[path][1] != 0:
320                model[path][2].remove_plot()
321                model[path][2].plot_dataset(self.axis, self.plottype, self.yerrorbars)
322            iter = model.iter_next(iter)
323
324        self.rescale_and_redraw()
325               
326        return
327       
328    def handle_clearplot(self, widget):
329       
330        self.clearplot()
331       
332        return
333       
334   
335    def clearplot(self):
336        model = self.filelistview.get_model().get_model()
337        iter = model.iter_children(None)
338        while iter:
339            path = model.get_path(iter)
340            if model[path][1] != 0:
341                model[path][2].remove_plot()
342                model[path][1] = not model[path][1]
343            iter = model.iter_next(iter)
344       
345        self.canvas.draw()
346        return 
347       
348    def rescale_and_redraw(self):
349
350        xdata = []
351        ydata = []
352
353        if len(self.axis.lines) > 0:
354
355            for line in self.axis.lines:
356                if self.axis.get_xscale() == 'log':
357                        xdata.extend([xval for xval in line.get_xdata() if xval > 0])
358                else:
359                        xdata.extend(line.get_xdata())
360                if self.axis.get_yscale() == 'log':
361                        ydata.extend([xval for xval in line.get_ydata() if xval > 0])
362                else:
363                        ydata.extend(line.get_ydata())
364         
365            #set limits
366            xmin = float(min(xdata))
367            xmax = float(max(xdata))
368            ymin = float(min(ydata))
369            ymax = float(max(ydata))   
370   
371            #adjust for size of markers (sort of)
372            xmin = xmin - 0.1 * abs(xmin)
373            xmax = xmax + 0.1 * abs(xmax)
374            ymin = ymin - 0.1 * abs(ymin)
375            ymax = ymax + 0.1 * abs(ymax)
376                   
377            self.axis.set_xlim(xmin, xmax)
378            self.axis.set_ylim(ymin, ymax)
379       
380        #self.axis.autoscale_view()
381        self.canvas.draw()
382
383        return
384
385    def handle_plot_click(self, event):
386
387        if event.mouseevent.button == 1:
388            """ Report data about point """
389            model = self.filelistview.get_model().get_model()
390            iter = model.iter_children(None)
391   
392   
393            if isinstance(event.artist, matplotlib.lines.Line2D):
394                #print "Clicked..."
395                pickedline = event.artist
396                ind = event.ind
397                xdata = pickedline.get_xdata()
398   
399                while iter:
400                    path = model.get_path(iter)
401                    if model[path][1] != 0:
402                        for line in model[path][2].plot:
403                            if line == pickedline:
404                                model[path][2].calcAlignVals(xdata[ind])
405                                label = self.wTree.get_widget("lbl_alignvals")
406                                label.set_text(model[path][2].alignvalstring)
407                                break
408                    iter = model.iter_next(iter)
409        elif event.mouseevent.button == 3:
410            """ Do fit stuff """
411            #print "Right button pressed"
412           
413
414app = appGui()
415gtk.main()
Note: See TracBrowser for help on using the repository browser.