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
15 import scipy
.ndimage
.measurements
as M
18 import numarray
.nd_image
.measurements
as M
20 has_measurements
= False
22 class HistogramApp(GenericSecondaryPlotWindow
):
24 This class implements the histogram window.
26 def __init__(self
, gladefile
, callerApp
, bits
=14, debug
=True):
27 GenericSecondaryPlotWindow
.__init
__(self
, 'HistogramWindow', gladefile
,
29 self
.callerApp
= callerApp
30 self
.min, self
.max = self
.callerApp
.min, self
.callerApp
.max
33 # Calculate the histogram
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
))
42 self
.yscale
= 'linear'
43 self
.showPoints
= False
48 if self
.showBars
: self
.showPoints
, self
.showLines
= False, False
50 self
.selection
= None # Range selected (axvspan instance)
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)
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
102 self
.selection
= None
103 # We plot in 'linear' Y scale to avoid problems plotting log scale
104 self
.axis
.set_yscale('linear')
107 self
.axis
.bar(self
.x
, self
.y
, width
=1.0,
108 bottom
=0.01, edgecolor
='black')
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')
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)
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)
129 self
.selection
.xy
= [(min, 0), (min, 1), (max, 1), (max, 0)]
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)
171 def on_pointsCheckButton_toggled(self
, widget
, *args
):
172 self
.showPoints
= not self
.showPoints
175 self
.barsCheckButt
.set_active(False)
177 self
.plot_histogram(showPoints
=self
.showPoints
)
179 def on_linesCheckButton_toggled(self
, widget
, *args
):
180 self
.showLines
= not self
.showLines
183 self
.barsCheckButt
.set_active(False)
185 self
.plot_histogram(showLines
=self
.showLines
)
187 def on_barsCheckButton_toggled(self
, widget
, *args
):
188 self
.showBars
= not self
.showBars
191 self
.linesCheckButt
.set_active(False)
192 self
.pointsCheckButt
.set_active(False)
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
):
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.')
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()