IA: Histogramm speedups using the ndimage.measurements module
[pyplotsuite.git] / pyplotsuite / imageanalyzer / histogramdialog.py
bloba2512bc661393807917ed257ef257360c3459778
2 # Copyright (C) 2006-2007 Antonino Ingargiola <tritemio@gmail.com>
4 # This file is part of PyPlotSuite <http://pyplotsuite.sourceforge.net>.
6 # PyPlotSuite 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 2 of the License, or
9 # (at your option) any later version.
11 from numpy import array, arange, min
12 from matplotlib.widgets import SpanSelector
13 from pyplotsuite.common.gtk_generic_windows import GenericSecondaryPlotWindow
14 try:
15 import scipy.ndimage.measurements as M
16 except ImportError:
17 try:
18 import numarray.nd_image.measurements as M
19 except ImportError:
20 has_measurements = False
22 class HistogramApp(GenericSecondaryPlotWindow):
23 """
24 This class implements the histogram window.
25 """
26 def __init__(self, gladefile, callerApp, bits=14, debug=True):
27 GenericSecondaryPlotWindow.__init__(self, 'HistogramWindow', gladefile,
28 autoconnect=False)
29 self.callerApp = callerApp
30 self.min, self.max = self.callerApp.min, self.callerApp.max
31 self.debug = debug
33 # Calculate the histogram
34 n = 250
35 m = min((0, self.callerApp.image_array.min()))
36 Max = self.callerApp.image_array.max()
37 self.x = arange(n)*Max/float(n-1)
38 self.y = M.histogram(self.callerApp.image_array, m, Max, n)
39 self.dprint ('x', len(self.x), 'y', len(self.y))
41 # Plot the histogram
42 self.yscale = 'linear'
43 self.showPoints = False
44 self.showLines = True
45 self.showBars = False
46 self.replot = True
48 if self.showBars: self.showPoints, self.showLines = False, False
50 self.selection = None # Range selected (axvspan instance)
51 self.plot_histogram()
52 #self.plot_histogram()
54 # Spin Buttons handlers
55 self.widthSpinButt = self.widgetTree.get_widget('widthSpinButt')
56 self.positionSpinButt = self.widgetTree.get_widget('positionSpinButt')
58 # Check Buttons handlers
59 self.pointsCheckButt = self.widgetTree.get_widget('pointsCheckButton')
60 self.linesCheckButt = self.widgetTree.get_widget('linesCheckButton')
61 self.barsCheckButt = self.widgetTree.get_widget('barsCheckButton')
63 # Create the span selector, link to the CB, but make it not visible
64 self.span = self.create_span()
65 self.span.visible = False
67 # Set the SpinButtons to the right values
68 self.called_by_onspanselect = False
69 self.set_selection(self.callerApp.min, self.callerApp.max)
71 # Connect the CB now to avoid CB calls during the setup of SpinButtons
72 self.widgetTree.signal_autoconnect(self)
73 self.window.show_all()
75 def dprint(self, *args):
76 if self.debug: print args
78 def create_span(self):
79 self.dprint ("create span")
80 span = SpanSelector(self.axis, self.onspanselect,
81 'horizontal', useblit=True, minspan=50)
82 return span
84 def plot_histogram(self, showPoints=None, showLines=None):
85 if not self.replot: return
87 if showPoints != None: self.showPoints = showPoints
88 if showLines != None: self.showLines = showLines
90 options = {'ls': '', 'marker': ''}
91 if self.showPoints and self.showLines:
92 options = {'ls': '-', 'marker': '.', 'ms': 10}
93 elif not self.showPoints and self.showLines:
94 options = {'ls': '-', 'marker': ''}
95 elif self.showPoints and not self.showLines:
96 options = {'ls': '', 'marker': '.', 'ms': 10}
98 # We clear the axis so a change in Y scale could take effect
99 # but in this way span.selection becomes an object without axis
100 # so we have to reset it too
101 self.axis.clear()
102 self.selection = None
103 # We plot in 'linear' Y scale to avoid problems plotting log scale
104 self.axis.set_yscale('linear')
106 if self.showBars:
107 self.axis.bar(self.x, self.y, width=1.0,
108 bottom=0.01, edgecolor='black')
109 else:
110 self.axis.plot(self.x, self.y, linewidth=1, **options)
112 self.axis.set_xlabel('Values')
113 self.axis.set_ylabel('Number of points')
114 self.axis.grid(True)
115 # Now the actual Y scale can be safely set
116 self.axis.set_yscale(self.yscale) # 'log' or 'linear'
117 if self.yscale == 'log':
118 self.axis.set_ylim(ymin=0.2)
119 self.plot_selection(self.min, self.max, drawcanvas=False)
120 self.canvas.draw()
122 def plot_selection(self, min, max, drawcanvas=True):
123 """ Plot the rectangle representing the selection. """
124 self.dprint ('plot_selection')
125 if self.selection == None:
126 self.selection = self.axis.axvspan(min, max,
127 facecolor='green', alpha=0.5)
128 else:
129 self.selection.xy = [(min, 0), (min, 1), (max, 1), (max, 0)]
130 if drawcanvas:
131 self.canvas.draw()
133 def set_selection(self, min, max):
134 self.dprint ('set_selection')
135 self.positionSpinButt.set_value(min)
136 self.widthSpinButt.set_value(max-min)
138 def statusminmax(self, min, max):
139 self.dprint ('statusminmax')
140 self.statusBar.push(self.context,
141 'Range: min = '+ str(min) +', max = '+ str(max))
143 def onspanselect(self, xmin, xmax):
144 self.dprint ('onspanselect')
145 min, max = int(xmin), int(xmax)
147 self.called_by_onspanselect = True
148 self.set_selection(min, max)
149 self.called_by_onspanselect = False
151 self.plot_selection(min, max)
153 self.callerApp.plot_image(min, max)
154 self.statusminmax(min, max)
155 self.min, self.max = min, max
158 # The following are GUI callback methods
160 def on_yscale_toggled(self, widget, *args):
161 if self.yscale == 'linear': self.yscale = 'log'
162 else: self.yscale = 'linear'
163 self.dprint ("YScale:", self.yscale)
164 self.axis.set_yscale(self.yscale)
165 if self.yscale == 'log':
166 self.axis.set_ylim(ymin=0.2)
168 #self.axis.autoscale_view(scaley=True)
169 self.canvas.draw()
171 def on_pointsCheckButton_toggled(self, widget, *args):
172 self.showPoints = not self.showPoints
173 if self.showPoints:
174 self.replot = False
175 self.barsCheckButt.set_active(False)
176 self.replot = True
177 self.plot_histogram(showPoints=self.showPoints)
179 def on_linesCheckButton_toggled(self, widget, *args):
180 self.showLines = not self.showLines
181 if self.showLines:
182 self.replot = False
183 self.barsCheckButt.set_active(False)
184 self.replot = True
185 self.plot_histogram(showLines=self.showLines)
187 def on_barsCheckButton_toggled(self, widget, *args):
188 self.showBars = not self.showBars
189 if self.showBars:
190 self.replot = False
191 self.linesCheckButt.set_active(False)
192 self.pointsCheckButt.set_active(False)
193 self.replot = True
194 self.plot_histogram(showLines=self.showLines)
196 def on_SpinButtons_value_changed(self, widget, *args):
197 if self.called_by_onspanselect: return
198 min = self.positionSpinButt.get_value()
199 self.plot_selection(min, min+self.widthSpinButt.get_value())
200 self.statusBar.push(self.context,
201 'Press "Apply" to set the changes on the image.')
203 def on_applyRangeButton_clicked(self, widget, *args):
204 self.dprint ('on_applyRangeButton_clicked')
205 min = int(self.positionSpinButt.get_value())
206 max = min + int(self.widthSpinButt.get_value())
207 self.statusminmax(min, max)
208 if (min, max) == (self.min, self.max): return
209 self.min, self.max = min, max
210 self.callerApp.plot_image(min, max)
212 def on_closeButton_clicked(self, widget, *args):
213 self.window.hide()
215 def on_rangeselectTButton_toggled(self, widget, *args):
216 self.span.visible = not self.span.visible
217 if self.span.visible:
218 self.dprint ('Span selector activated')
219 self.statusBar.push(self.context,
220 'Now drag the mouse over the plot to select a range.')
221 else:
222 self.dprint ('Span selector deactivated')
223 self.statusBar.push(self.context,
224 'Range selection tool deactivated.')
226 def on_destroy(self, widget, data=None):
227 self.dprint ('idestroy:', widget)
228 self.callerApp.histogramApp = None
229 self.window.destroy()