/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/classgen.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/UI/classgen.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 620 by jonathan, Mon Apr 7 10:14:25 2003 UTC revision 978 by frank, Thu May 22 11:40:32 2003 UTC
# Line 5  Line 5 
5  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
6  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
7    
8    import sys
9    
10  from Thuban import _  from Thuban import _
11    
12  from wxPython.wx import *  from wxPython.wx import *
13    
14  from Thuban.Model.classification import Classification, ClassGroupRange, \  from Thuban.Model.classification import ClassGroupProperties
     ClassGroupSingleton, ClassGroupProperties  
15    
16  from Thuban.Model.table import Table, FIELDTYPE_INT, FIELDTYPE_DOUBLE, \  from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
17       FIELDTYPE_STRING       FIELDTYPE_STRING
18    
19  from Thuban.Model.color import Color  from Thuban.Model.range import Range
20    
21    import classifier, resource
22    
23    from Thuban.Model.classgen import ClassGenerator, \
24        CustomRamp, GreyRamp, RedRamp, GreenRamp, BlueRamp, GreenToRedRamp, \
25        HotToColdRamp
26    
27    USEALL_BMP  = "group_use_all"
28    USE_BMP     = "group_use"
29    USENOT_BMP  = "group_use_not"
30    USENONE_BMP = "group_use_none"
31    
32    GENCOMBOSTR_UNIFORM = _("Uniform Distribution")
33    GENCOMBOSTR_UNIQUE = _("Unique Values")
34    GENCOMBOSTR_QUANTILES = _("Quantiles from Table")
35    
36    PROPCOMBOSTR_CUSTOM     = _("Custom Ramp")
37    PROPCOMBOSTR_GREY       = _("Grey Ramp")
38    PROPCOMBOSTR_RED        = _("Red Ramp")
39    PROPCOMBOSTR_GREEN      = _("Green Ramp")
40    PROPCOMBOSTR_BLUE       = _("Blue Ramp")
41    PROPCOMBOSTR_GREEN2RED  = _("Green-to-Red Ramp")
42    PROPCOMBOSTR_HOT2COLD   = _("Hot-to-Cold Ramp")
43    
44  ID_CLASSGEN_GEN = 4001  ID_CLASSGEN_GENCOMBO = 4007
45  ID_CLASSGEN_CANCEL = 4002  ID_CLASSGEN_PROPCOMBO = 4008
46    
47  class ClassGenDialog(wxDialog):  class ClassGenDialog(wxDialog):
48                                                                                    
49      def __init__(self, parent, table, fieldName):      def __init__(self, parent, layer, fieldName):
50            """Inialize the class generating dialog.
51    
52            parent -- this must be an instance of the Classifier class
53            """
54    
55          wxDialog.__init__(self, parent, -1, _("Generate Classification"),          wxDialog.__init__(self, parent, -1, _("Generate Classification"),
56                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)                            style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
57                                                                                    
58            self.parent = parent
59            self.layer = layer
60          self.clazz = None          self.clazz = None
61    
62          type, name, width, prec = table.field_info_by_name(fieldName)          col = layer.table.Column(fieldName)
63            self.type = col.type
64    
65            self.fieldName = fieldName
66            self.fieldType = self.type
67    
68            self.curGenPanel = None
69    
70            self.genpanels = []
71    
72            #############
73            # we need to create genButton first because when we create the
74            # panels they will call AllowGenerate() which uses genButton.
75            #
76            self.genButton = wxButton(self, wxID_OK, _("Generate"))
77            self.genButton.SetDefault()
78            self.cancelButton = wxButton(self, wxID_CANCEL, _("Close"))
79    
80            self.genChoice = wxChoice(self, ID_CLASSGEN_GENCOMBO)
81    
82            self.genpanels.append((GENCOMBOSTR_UNIQUE, GenUniquePanel))
83            if self.type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):
84                self.genpanels.append((GENCOMBOSTR_UNIFORM, GenUniformPanel))
85                self.genpanels.append((GENCOMBOSTR_QUANTILES, GenQuantilesPanel))
86    
87            for name, clazz in self.genpanels:
88                self.genChoice.Append(name, [clazz, None])
89    
90            self.genChoice.SetSelection(0)
91    
92            for i in range(self.genChoice.GetCount()):
93                clazz, obj = self.genChoice.GetClientData(i)
94    
95                if obj is None:
96                    obj = clazz(self, self.layer, self.fieldName, self.fieldType)
97                    obj.Hide()
98                    self.genChoice.SetClientData(i, [clazz, obj])
99    
100    
101            #############
102    
103          sizer = wxBoxSizer(wxVERTICAL)          sizer = wxBoxSizer(wxVERTICAL)
104    
105          buttonSizer = wxBoxSizer(wxHORIZONTAL)          sizer.Add(wxStaticText(self, -1, _("Field: %s") % fieldName),
106          self.genButton = wxButton(self, ID_CLASSGEN_GEN, _("Generate"))                    0, wxALL, 4)
107          buttonSizer.Add(self.genButton, 0, wxALL, 4)          sizer.Add(wxStaticText(
108          buttonSizer.Add(60, 20, 0, wxALL, 4)              self, -1,
109          buttonSizer.Add(wxButton(self, ID_CLASSGEN_CANCEL, _("Cancel")),              _("Data Type: %s") % classifier.Classifier.type2string[self.type]),
110                          0, wxALL, 4)              0, wxALL, 4)
111    
112          if type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):          psizer = wxBoxSizer(wxHORIZONTAL)
113              self.panel = GenRangePanel(self, table, fieldName, type)          psizer.Add(wxStaticText(self, -1, _("Generate:")),
114          elif type == FIELDTYPE_STRING:              0, wxALIGN_CENTER_VERTICAL, 0)
115              print "Select a field that is an int/decimal"          psizer.Add(self.genChoice, 1, wxALL | wxGROW, 4)
116              #panel = GenSingletonPanel(self, table, fieldName)  
117          else:          sizer.Add(psizer, 0, wxALL | wxGROW, 4)
118              assert False, "Shouldn't be here."  
119              pass          self.sizer_genPanel = wxBoxSizer(wxVERTICAL)
120            sizer.Add(self.sizer_genPanel, 1, wxGROW | wxALL, 4)
121    
122            psizer = wxBoxSizer(wxHORIZONTAL)
123            psizer.Add(wxStaticText(self, -1, _("Color Scheme:")),
124                0, wxALIGN_CENTER_VERTICAL, 0)
125    
126            # Properties (Ramp) ComboBox
127            self.propCombo = wxChoice(self, ID_CLASSGEN_PROPCOMBO)
128    
129            self.propPanel = None
130            custom_ramp_panel = CustomRampPanel(self, layer.ShapeType())
131    
132            self.propCombo.Append(PROPCOMBOSTR_GREY,  GreyRamp())
133            self.propCombo.Append(PROPCOMBOSTR_RED,   RedRamp())
134            self.propCombo.Append(PROPCOMBOSTR_GREEN, GreenRamp())
135            self.propCombo.Append(PROPCOMBOSTR_BLUE,  BlueRamp())
136            self.propCombo.Append(PROPCOMBOSTR_GREEN2RED, GreenToRedRamp())
137            self.propCombo.Append(PROPCOMBOSTR_HOT2COLD,  HotToColdRamp())
138            self.propCombo.Append(PROPCOMBOSTR_CUSTOM, custom_ramp_panel)
139    
140            self.propCombo.SetSelection(0)
141    
142            psizer.Add(self.propCombo, 1, wxALL | wxGROW, 4)
143            sizer.Add(psizer, 0, wxALL | wxGROW, 4)
144    
145            sizer.Add(custom_ramp_panel, 1, wxGROW | wxALL, 4)
146            sizer.Show(custom_ramp_panel, False)
147    
148          sizer.Add(self.panel, 1, wxGROW | wxALL, 4)          # Finally place the main buttons
149          sizer.Add(buttonSizer, 0,          buttonSizer = wxBoxSizer(wxHORIZONTAL)
150                    wxALL | wxALIGN_BOTTOM | wxALIGN_CENTER_HORIZONTAL, 4)          buttonSizer.Add(self.genButton, 0, wxRIGHT|wxEXPAND, 10)
151            buttonSizer.Add(self.cancelButton, 0, wxRIGHT|wxEXPAND, 10)
152            sizer.Add(buttonSizer, 0, wxALIGN_RIGHT|wxBOTTOM|wxTOP, 10)
153    
154          self.SetSizer(sizer)          self.SetSizer(sizer)
155          self.SetAutoLayout(True)          self.SetAutoLayout(True)
156          sizer.SetSizeHints(self)          sizer.SetSizeHints(self)
157    
158          EVT_BUTTON(self, ID_CLASSGEN_GEN, self._OnGenerate)          self.topBox = sizer
159          EVT_BUTTON(self, ID_CLASSGEN_CANCEL, self._OnCancel)  
160            self.__DoOnGenTypeSelect()
161    
162            EVT_CHOICE(self, ID_CLASSGEN_GENCOMBO, self._OnGenTypeSelect)
163            EVT_CHOICE(self, ID_CLASSGEN_PROPCOMBO, self._OnPropTypeSelect)
164            EVT_BUTTON(self, wxID_OK, self.OnOK)
165            EVT_BUTTON(self, wxID_CANCEL, self.OnCancel)
166    
167            self.__DoOnGenTypeSelect()
168    
169            self.genChoice.SetFocus()
170    
171      def GetClassification(self):      def GetClassification(self):
172          return self.clazz          return self.clazz
173    
174      def AllowGenerate(self, on):      def AllowGenerate(self, on):
175          self.genButton.Enable(on)          pass #self.genButton.Enable(on)
176    
177      def _OnGenerate(self, event):      def OnOK(self, event):
178          min = self.panel.GetMin()          """This is really the generate button, but we want to override
179          max = self.panel.GetMax()          the wxDialog class.
180          numGroups = self.panel.GetNumGroups()          """
         cgp = ClassGroupProperties()  
         cgp2 = ClassGroupProperties()  
                                                                                   
         cgp.SetLineColor(Color(.5, 0, 0))  
         cgp2.SetLineColor(Color(1, 0, 1))  
         cgp2.SetLineWidth(10)  
181    
182          if min is not None \          index = self.genChoice.GetSelection()
183              and max is not None \  
184              and numGroups is not None:          assert index != -1, "button should be disabled!"
185              self.clazz = ClassGenerator().GenerateRanges(min, max,  
186                                                           numGroups, cgp, cgp2)          genSel = self.genChoice.GetString(index)
187          else:            clazz, genPanel = self.genChoice.GetClientData(index)
188              self.clazz = None # for now  
189            propPanel = self.propPanel
190          self.EndModal(wxID_OK)  
191                                                                                            if genSel in (GENCOMBOSTR_UNIFORM,          \
192      def _OnCancel(self, event):                        GENCOMBOSTR_UNIQUE,           \
193          self.EndModal(wxID_CANCEL)                        GENCOMBOSTR_QUANTILES):
194    
195  ID_RANGE_MIN = 4001              numGroups = genPanel.GetNumGroups()
196  ID_RANGE_MAX = 4002  
197  ID_RANGE_NGROUPS = 4003              index = self.propCombo.GetSelection()
198  ID_RANGE_STEP = 4004  
199                propSel = self.propCombo.GetString(index)
200                propPanel = self.propCombo.GetClientData(index)
201    
202                ramp = propPanel.GetRamp()
203    
204                if genSel == GENCOMBOSTR_UNIFORM:
205    
206                    min = genPanel.GetMin()
207                    max = genPanel.GetMax()
208    
209                    if min is not None \
210                        and max is not None \
211                        and numGroups is not None:
212    
213                        self.clazz = ClassGenerator().GenUniformDistribution(
214                                    min, max, numGroups, ramp,
215                                    self.type == FIELDTYPE_INT)
216    
217  class GenRangePanel(wxPanel):                      self.parent._SetClassification(self.clazz)
218    
219      def __init__(self, parent, table, fieldName, fieldType):              elif genSel == GENCOMBOSTR_UNIQUE:
220    
221                    list = genPanel.GetValueList()
222    
223                    if len(list) > 0 \
224                        and numGroups is not None:
225    
226                        self.clazz = ClassGenerator().GenSingletonsFromList(
227                                        list, numGroups, ramp)
228    
229                        self.parent._SetClassification(self.clazz)
230    
231                elif genSel == GENCOMBOSTR_QUANTILES:
232    
233                    _range = genPanel.GetRange()
234                    _list = genPanel.GetList()
235                    _list.sort()
236    
237                    delta = 1 / float(numGroups)
238                    percents = [delta * i for i in range(1, numGroups + 1)]
239                    adjusted, self.clazz = \
240                        ClassGenerator().GenQuantiles(_list, percents, ramp, _range)
241    
242                    if adjusted:
243                        dlg = wxMessageDialog(self,
244                            _("Based on the data from the table and the input\n" +
245                              "values, the exact quantiles could not be generated.\n\n" +
246                              "Accept a close estimate?"),
247                            _("Problem with Quantiles"),
248    
249                            wxYES_NO|wxYES_DEFAULT|wxICON_QUESTION)
250                        if dlg.ShowModal() == wxID_YES:
251                            self.parent._SetClassification(self.clazz)
252                    else:
253                        self.parent._SetClassification(self.clazz)
254    
255        def OnCancel(self, event):
256            self.Close()
257    
258        def _OnGenTypeSelect(self, event):
259            self.__DoOnGenTypeSelect()
260            return
261    
262            combo = event.GetEventObject()
263    
264            selIndex = combo.GetSelection()
265    
266            if self.genPanel is not None:
267                self.topBox.Show(self.genPanel, False)
268    
269            self.genPanel = combo.GetClientData(selIndex)
270            if self.genPanel is not None:
271                self.topBox.Show(self.genPanel, True)
272    
273            self.topBox.SetSizeHints(self)
274            self.topBox.Layout()
275    
276        def _OnPropTypeSelect(self, event):
277            combo = event.GetEventObject()
278    
279            selIndex = combo.GetSelection()
280            sel = combo.GetString(selIndex)
281    
282            if isinstance(self.propPanel, wxPanel):
283                self.topBox.Show(self.propPanel, False)
284    
285            self.propPanel = combo.GetClientData(selIndex)
286    
287            if isinstance(self.propPanel, wxPanel):
288                self.topBox.Show(self.propPanel, True)
289    
290            self.topBox.SetSizeHints(self)
291            self.topBox.Layout()
292    
293        def __DoOnGenTypeSelect(self):
294            choice = self.genChoice
295    
296            sel = choice.GetSelection()
297            if sel == -1: return
298    
299            clazz, obj = choice.GetClientData(sel)
300    
301            if self.curGenPanel is not None:
302                self.curGenPanel.Hide()
303                self.sizer_genPanel.Remove(self.curGenPanel)
304    
305            self.curGenPanel = obj
306            self.curGenPanel.Show()
307    
308            self.sizer_genPanel.Add(self.curGenPanel, 1,
309                wxALL|wxEXPAND|wxADJUST_MINSIZE, 3)
310            self.sizer_genPanel.Layout()
311            self.Layout()
312            self.topBox.SetSizeHints(self)
313    
314    ID_UNIFORM_MIN = 4001
315    ID_UNIFORM_MAX = 4002
316    ID_UNIFORM_NGROUPS = 4003
317    ID_UNIFORM_STEP = 4004
318    ID_UNIFORM_RETRIEVE = 4005
319    
320    class GenUniformPanel(wxPanel):
321    
322        def __init__(self, parent, layer, fieldName, fieldType):
323          wxPanel.__init__(self, parent, -1)          wxPanel.__init__(self, parent, -1)
324    
325          self.parent = parent          self.parent = parent
326            self.layer = layer
327            self.fieldName = fieldName
328          self.fieldType = fieldType          self.fieldType = fieldType
329    
330          topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, "Ranges"),          topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""),
331                                      wxVERTICAL)                                      wxVERTICAL)
332    
333            #############
334    
335          sizer = wxBoxSizer(wxHORIZONTAL)          sizer = wxBoxSizer(wxHORIZONTAL)
336    
337          sizer.Add(wxStaticText(self, -1, _("Min:")), 0, wxALL, 4)          sizer.Add(wxStaticText(self, -1, _("Min:")), 0, wxALL, 4)
338          self.minCtrl = wxTextCtrl(self, ID_RANGE_MIN, style=wxTE_RIGHT)          self.minCtrl = wxTextCtrl(self, ID_UNIFORM_MIN, style=wxTE_RIGHT)
339          sizer.Add(self.minCtrl, 0, wxALL, 4)          sizer.Add(self.minCtrl, 1, wxALL, 4)
340          EVT_TEXT(self, ID_RANGE_MIN, self._OnRangeChanged)          EVT_TEXT(self, ID_UNIFORM_MIN, self._OnRangeChanged)
         self.goodTextColour = self.minCtrl.GetForegroundColour()  
         self.badTextColour = wxRED  
341    
342          sizer.Add(wxStaticText(self, -1, _("Max:")), 0, wxALL, 4)          sizer.Add(wxStaticText(self, -1, _("Max:")), 0, wxALL, 4)
343          self.maxCtrl = wxTextCtrl(self, ID_RANGE_MAX, style=wxTE_RIGHT)          self.maxCtrl = wxTextCtrl(self, ID_UNIFORM_MAX, style=wxTE_RIGHT)
344          sizer.Add(self.maxCtrl, 0, wxALL, 4)          sizer.Add(self.maxCtrl, 1, wxALL, 4)
345          EVT_TEXT(self, ID_RANGE_MAX, self._OnRangeChanged)          EVT_TEXT(self, ID_UNIFORM_MAX, self._OnRangeChanged)
346          topSizer.Add(sizer, 0, wxALL, 4)  
347            sizer.Add(wxButton(self, ID_UNIFORM_RETRIEVE, _("Retrieve From Table")),
348                0, wxALL, 4)
349            EVT_BUTTON(self, ID_UNIFORM_RETRIEVE, self._OnRetrieve)
350    
351            topSizer.Add(sizer, 1, wxGROW, 0)
352    
353            #############
354    
355          sizer = wxBoxSizer(wxHORIZONTAL)          sizer = wxBoxSizer(wxHORIZONTAL)
356    
357          sizer.Add(wxStaticText(self, -1, _("Number of Groups:")), 0, wxALL, 4)          sizer.Add(wxStaticText(self, -1, _("Number of Groups:")), 0, wxALL, 4)
358          self.numGroupsCtrl = wxSpinCtrl(self, ID_RANGE_NGROUPS, style=wxTE_RIGHT)          self.numGroupsCtrl = wxSpinCtrl(self, ID_UNIFORM_NGROUPS,
359          EVT_TEXT(self, ID_RANGE_NGROUPS, self._OnNumGroupsChanged)                                          style=wxTE_RIGHT)
360          EVT_SPINCTRL(self, ID_RANGE_NGROUPS, self._OnNumGroupsChanged)          EVT_TEXT(self, ID_UNIFORM_NGROUPS, self._OnNumGroupsChanged)
361          sizer.Add(self.numGroupsCtrl, 0, wxALL, 4)          EVT_SPINCTRL(self, ID_UNIFORM_NGROUPS, self._OnNumGroupsChanged)
362            sizer.Add(self.numGroupsCtrl, 1, wxALL, 4)
363    
364          sizer.Add(wxStaticText(self, -1, _("Stepping:")), 0, wxALL, 4)          sizer.Add(wxStaticText(self, -1, _("Stepping:")), 0, wxALL, 4)
365          self.stepCtrl = wxTextCtrl(self, ID_RANGE_STEP, style=wxTE_RIGHT)          self.stepCtrl = wxTextCtrl(self, ID_UNIFORM_STEP, style=wxTE_RIGHT)
366          EVT_TEXT(self, ID_RANGE_STEP, self._OnSteppingChanged)          EVT_TEXT(self, ID_UNIFORM_STEP, self._OnSteppingChanged)
367          sizer.Add(self.stepCtrl , 0, wxALL, 4)          sizer.Add(self.stepCtrl , 1, wxALL, 4)
368          topSizer.Add(sizer, 0, wxALL, 4)  
369            topSizer.Add(sizer, 1, wxGROW, 0)
370    
371            #############
372    
373          self.SetSizer(topSizer)          self.SetSizer(topSizer)
374          self.SetAutoLayout(True)          self.SetAutoLayout(True)
# Line 141  class GenRangePanel(wxPanel): Line 377  class GenRangePanel(wxPanel):
377          self.numGroupsChanging = False          self.numGroupsChanging = False
378          self.steppingChanging = False          self.steppingChanging = False
379    
380          self.numGroupsCtrl.SetRange(1, 100)          self.numGroupsCtrl.SetRange(1, sys.maxint)
381    
382          self.numGroupsCtrl.SetValue(1)          self.numGroupsCtrl.SetValue(1)
383          self.stepCtrl.SetValue("1")          self.stepCtrl.SetValue("1")
# Line 156  class GenRangePanel(wxPanel): Line 392  class GenRangePanel(wxPanel):
392                                              FIELDTYPE_INT,                                              FIELDTYPE_INT,
393                                              None)                                              None)
394    
         ##if self.__ValidateEntry(self.numGroupsCtrl, value, int):  
             #return value  
   
         #return None  
   
395      def GetStepping(self):      def GetStepping(self):
396          step = self.stepCtrl.GetValue()          step = self.stepCtrl.GetValue()
397          return self.__GetValidatedTypeEntry(self.stepCtrl,          return self.__GetValidatedTypeEntry(self.stepCtrl,
# Line 196  class GenRangePanel(wxPanel): Line 427  class GenRangePanel(wxPanel):
427          self.numGroupsCtrl.Enable(on)          self.numGroupsCtrl.Enable(on)
428          self.stepCtrl.Enable(on)          self.stepCtrl.Enable(on)
429    
         if on:  
             self.numGroupsCtrl.SetRange(1, abs(max - min) / 0.001)  
   
430          ngroups = self.GetNumGroups()          ngroups = self.GetNumGroups()
431    
432          if ngroups is not None  \          if ngroups is not None  \
# Line 206  class GenRangePanel(wxPanel): Line 434  class GenRangePanel(wxPanel):
434              and max is not None \              and max is not None \
435              and ngroups != 0:              and ngroups != 0:
436    
437              self.stepCtrl.SetValue(str((max - min) / ngroups))              #self.stepCtrl.SetValue(str((max - min) / ngroups))
438                self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
439                #self.numGroupsCtrl.SetValue(ngroups)
440    
441              self.parent.AllowGenerate(self.GetStepping() is not None)              self.parent.AllowGenerate(self.GetStepping() is not None)
442          else:          else:
# Line 227  class GenRangePanel(wxPanel): Line 457  class GenRangePanel(wxPanel):
457          min = self.GetMin()          min = self.GetMin()
458          max = self.GetMax()          max = self.GetMax()
459    
         if ngroups >= self.numGroupsCtrl.GetMax():  
             self.numGroupsCtrl.SetRange(1, ngroups + 1)  
   
460          if ngroups is not None  \          if ngroups is not None  \
461              and min is not None \              and min is not None \
462              and max is not None \              and max is not None \
# Line 243  class GenRangePanel(wxPanel): Line 470  class GenRangePanel(wxPanel):
470              # called steppingChanging tries to prevent the recursion.              # called steppingChanging tries to prevent the recursion.
471              #              #
472              self.numGroupsChanging = True              self.numGroupsChanging = True
473              self.stepCtrl.SetValue(str((max - min) / ngroups))  
474                self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
475    
476              self.parent.AllowGenerate(self.GetStepping() is not None)              self.parent.AllowGenerate(self.GetStepping() is not None)
477          else:          else:
# Line 268  class GenRangePanel(wxPanel): Line 496  class GenRangePanel(wxPanel):
496              # see note in _OnNumGroupsChanged              # see note in _OnNumGroupsChanged
497              #              #
498              self.steppingChanging = True              self.steppingChanging = True
499              n = int((max - min) / step)              self.numGroupsCtrl.SetValue(self.__CalcNumGroups(min, max, step))
             if n == 0:  
                 n = 1  
   
             self.numGroupsCtrl.SetValue(n)  
500    
501              self.parent.AllowGenerate(self.GetNumGroups() is not None)              self.parent.AllowGenerate(self.GetNumGroups() is not None)
502          else:          else:
503              self.parent.AllowGenerate(False)              self.parent.AllowGenerate(False)
504    
505        def _OnRetrieve(self, event):
506    
507            if self.layer.table is not None:
508                wxBeginBusyCursor()
509                min, max = self.layer.table.ValueRange(self.fieldName)
510                self.minCtrl.SetValue(str(min))
511                self.maxCtrl.SetValue(str(max))
512                wxEndBusyCursor()
513    
514      def __GetValidatedTypeEntry(self, win, value, type, badValue = None):      def __GetValidatedTypeEntry(self, win, value, type, badValue = None):
515    
516          if type == FIELDTYPE_INT:          if type == FIELDTYPE_INT:
# Line 316  class GenRangePanel(wxPanel): Line 549  class GenRangePanel(wxPanel):
549          win.Refresh()          win.Refresh()
550    
551          return valid          return valid
           
552    
553  class GenSingletonPanel(wxPanel):      def __CalcStepping(self, min, max, ngroups):
554            step = (max - min) / float(ngroups)
555            if self.fieldType == FIELDTYPE_INT:
556                step = int(step)
557    
558            return step
559    
560        def __CalcNumGroups(self, min, max, step):
561            n = int((max - min) / step)
562            if n == 0:
563                n = 1
564    
565            if self.fieldType == FIELDTYPE_INT and step == 1:
566                n += 1
567    
568      def __init__(self, parent, table, fieldName, fieldType):          return n
569    
570    
571    ID_UNIQUE_RETRIEVE = 4001
572    ID_UNIQUE_USEALL = 4002
573    ID_UNIQUE_USE = 4003
574    ID_UNIQUE_DONTUSE = 4004
575    ID_UNIQUE_USENONE = 4005
576    ID_UNIQUE_SORTAVAIL = 4006
577    ID_UNIQUE_SORTUSE = 4007
578    ID_UNIQUE_REVAVAIL = 4008
579    ID_UNIQUE_REVUSE = 4009
580    
581    class GenUniquePanel(wxPanel):
582    
583        def __init__(self, parent, layer, fieldName, fieldType):
584          wxPanel.__init__(self, parent, -1)          wxPanel.__init__(self, parent, -1)
585    
586            self.parent = parent
587            self.layer = layer
588            self.fieldName = fieldName
589            self.fieldType = fieldType
590    
591  class ClassGenerator:          topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""),
592                                        wxVERTICAL)
593    
     def GenerateSingletons(self, list, numGroups, prop1, prop2):  
         """Generate a new classification consisting solely of singletons.  
594    
595          The resulting classification will consist of at most 'numGroups'          #bsizer = wxBoxSizer(wxVERTICAL)
596          groups whose group properties ramp between 'prop1' and 'prop2'. There          topSizer.Add(wxButton(self, ID_UNIQUE_RETRIEVE,
597          could be fewer groups if 'list' contains fewer that 'numGroups' items.                              _("Retrieve From Table")),
598                       0, wxALL | wxALIGN_RIGHT, 4)
599    
600          list -- any object that implements the iterator interface          EVT_BUTTON(self, ID_UNIQUE_RETRIEVE, self._OnRetrieve)
601    
602          numGroups -- how many groups to generate. This can not be          #topSizer.Add(bsizer, 0, wxALL, 4)
                      determined while the classification is being  
                      generated because the stepping values must  
                      be precalculated to ramp between prop1 and prop2.  
603    
604          prop1 -- initial group property values          sizer = wxBoxSizer(wxHORIZONTAL)
605    
606          prop2 -- final group property values          self.dataList = []
         """  
607    
608          clazz = Classification()          psizer = wxBoxSizer(wxVERTICAL)
609          if numGroups == 0: return clazz          self.list_avail = wxListCtrl(self, -1,
610                            style=wxLC_REPORT | wxLC_SINGLE_SEL)
611            self.list_avail.InsertColumn(0, "Available")
612            self.list_avail_data = []
613            psizer.Add(self.list_avail, 1, wxGROW, 0)
614    
615            bsizer = wxBoxSizer(wxHORIZONTAL)
616            bsizer.Add(wxButton(self, ID_UNIQUE_SORTAVAIL, _("Sort")))
617            EVT_BUTTON(self, ID_UNIQUE_SORTAVAIL, self._OnSortList)
618    
619          for value, prop in zip(list, PropertyRamp(numGroups, prop1, prop2)):          bsizer.Add(wxButton(self, ID_UNIQUE_REVAVAIL, _("Reverse")))
620              clazz.AppendGroup(ClassGroupSingleton(value, prop))          EVT_BUTTON(self, ID_UNIQUE_REVAVAIL, self._OnReverseList)
621    
622          return clazz          psizer.Add(bsizer, 0, wxGROW, 0)
623            sizer.Add(psizer, 1, wxGROW, 0)
624    
625      def GenerateRanges(self, min, max, numGroups, prop1, prop2):          
626            bsizer = wxBoxSizer(wxVERTICAL)
627    
628          clazz = Classification()          bmp = resource.GetBitmapResource(USEALL_BMP, wxBITMAP_TYPE_XPM)
629          if numGroups == 0: return clazz          bsizer.Add(wxBitmapButton(self, ID_UNIQUE_USEALL, bmp),
630                       0, wxGROW | wxALL, 4)
631            bmp = resource.GetBitmapResource(USE_BMP, wxBITMAP_TYPE_XPM)
632            bsizer.Add(wxBitmapButton(self, ID_UNIQUE_USE, bmp),
633                       0, wxGROW | wxALL, 4)
634            bmp = resource.GetBitmapResource(USENOT_BMP, wxBITMAP_TYPE_XPM)
635            bsizer.Add(wxBitmapButton(self, ID_UNIQUE_DONTUSE, bmp),
636                       0, wxGROW | wxALL, 4)
637            bmp = resource.GetBitmapResource(USENONE_BMP, wxBITMAP_TYPE_XPM)
638            bsizer.Add(wxBitmapButton(self, ID_UNIQUE_USENONE, bmp),
639                       0, wxGROW | wxALL, 4)
640    
641            EVT_BUTTON(self, ID_UNIQUE_USEALL, self._OnUseAll)
642            EVT_BUTTON(self, ID_UNIQUE_USE, self._OnUse)
643            EVT_BUTTON(self, ID_UNIQUE_DONTUSE, self._OnDontUse)
644            EVT_BUTTON(self, ID_UNIQUE_USENONE, self._OnUseNone)
645    
646            sizer.Add(bsizer, 0, wxALL | wxALIGN_CENTER_VERTICAL, 4)
647    
648            psizer = wxBoxSizer(wxVERTICAL)
649            self.list_use = wxListCtrl(self, -1,
650                            style=wxLC_REPORT | wxLC_SINGLE_SEL)
651            self.list_use.InsertColumn(0, "Use")
652            self.list_use_data = []
653            psizer.Add(self.list_use, 1, wxGROW, 0)
654    
655            bsizer = wxBoxSizer(wxHORIZONTAL)
656            bsizer.Add(wxButton(self, ID_UNIQUE_SORTUSE, _("Sort")))
657            EVT_BUTTON(self, ID_UNIQUE_SORTUSE, self._OnSortList)
658    
659            bsizer.Add(wxButton(self, ID_UNIQUE_REVUSE, _("Reverse")))
660            EVT_BUTTON(self, ID_UNIQUE_REVUSE, self._OnReverseList)
661    
662          step = (max - min) / float(numGroups)          psizer.Add(bsizer, 0, wxGROW, 0)
663    
664          cur_min = min          sizer.Add(psizer, 1, wxGROW, 0)
         cur_max = cur_min + step  
665    
         i = 0  
         for prop in PropertyRamp(numGroups, prop1, prop2):  
666    
667              if i == (numGroups - 1):          topSizer.Add(sizer, 1, wxGROW, 0)
                 cur_max = max  
668    
669              # this check guards against rounding issues          self.SetSizer(topSizer)
670              if cur_min != cur_max:          self.SetAutoLayout(True)
671                  clazz.AppendGroup(ClassGroupRange(cur_min, cur_max, prop))          topSizer.SetSizeHints(self)
672    
673              cur_min = cur_max          width, height = self.list_avail.GetSizeTuple()
674              cur_max += step          self.list_avail.SetColumnWidth(0,width)
675              i += 1          width, height = self.list_use.GetSizeTuple()
676            self.list_use.SetColumnWidth(0,width)
677    
678          return clazz          self.parent.AllowGenerate(False)
679    
680  class PropertyRamp:      def GetNumGroups(self):
681            return self.list_use.GetItemCount()
682    
683      def __init__(self, num, prop1, prop2):      def GetValueList(self):
684            list = []
685            for i in range(self.list_use.GetItemCount()):
686                list.append(self.dataList[self.list_use.GetItemData(i)])
687            return list
688    
689          self.count = int(num)      def _OnSortList(self, event):
690          num = float(num)          id = event.GetId()
691    
692            if id == ID_UNIQUE_SORTUSE:
693                list = self.list_use
694            else:
695                list = self.list_avail
696    
697          self.lineColor = prop1.GetLineColor()          list.SortItems(lambda i1, i2: cmp(self.dataList[i1],
698          self.fillColor = prop1.GetFill()                                            self.dataList[i2]))
         self.lineWidth = prop1.GetLineWidth()  
699    
700          lineColor2 = prop2.GetLineColor()      def _OnReverseList(self, event):
701          fillColor2 = prop2.GetFill()          id = event.GetId()
         lineWidth2 = prop2.GetLineWidth()  
702    
703          self.line_redStep   = (lineColor2.red   - self.lineColor.red)   / num          if id == ID_UNIQUE_REVUSE:
704          self.line_greenStep = (lineColor2.green - self.lineColor.green) / num              list = self.list_use
705          self.line_blueStep  = (lineColor2.blue  - self.lineColor.blue)  / num          else:
706                list = self.list_avail
707    
708          self.line_widthStep = (lineWidth2 - self.lineWidth) / num          #
709            # always returning 1 reverses the list
710            #
711            list.SortItems(lambda i1, i2: 1)
712    
713          self.fill_redStep   = (fillColor2.red   - self.fillColor.red)   / num      def _OnRetrieve(self, event):
714          self.fill_greenStep = (fillColor2.green - self.fillColor.green) / num          self.list_use.DeleteAllItems()
715          self.fill_blueStep  = (fillColor2.blue  - self.fillColor.blue)  / num          self.list_use_data = []
716            self.list_avail.DeleteAllItems()
717            self.list_avail_data = []
718    
719      def __iter__(self):          list = self.layer.table.UniqueValues(self.fieldName)
720          return self          index = 0
721            for v in list:
722                self.dataList.append(v)
723                i = self.list_avail.InsertStringItem(index, str(v))
724                self.list_avail.SetItemData(index, i)
725    
726      def next(self):              self.list_avail_data.append(v)
727          if self.count == 0:              index += 1
             raise StopIteration  
728    
729          prop = ClassGroupProperties()      def _OnUseAll(self, event):
730          prop.SetFill(self.fillColor)          for i in range(self.list_avail.GetItemCount()):
731          prop.SetLineColor(self.lineColor)              self.__MoveListItem(0, self.list_avail, self.list_use)
732          prop.SetLineWidth(int(self.lineWidth))  
733                def _OnUse(self, event):
734          self.lineColor.red   += self.line_redStep          self.__MoveSelectedItems(self.list_avail, self.list_use)
735          self.lineColor.green += self.line_greenStep  
736          self.lineColor.blue  += self.line_blueStep      def _OnDontUse(self, event):
737            self.__MoveSelectedItems(self.list_use, self.list_avail)
738    
739        def _OnUseNone(self, event):
740    
741            for i in range(self.list_use.GetItemCount()):
742                self.__MoveListItem(0, self.list_use, self.list_avail)
743    
744        def __MoveSelectedItems(self, list_src, list_dest):
745            while True:
746                index = list_src.GetNextItem(-1,
747                                             wxLIST_NEXT_ALL,
748                                             wxLIST_STATE_SELECTED)
749    
750                if index == -1:
751                    break
752    
753                self.__MoveListItem(index, list_src, list_dest)
754    
755    
756        def __MoveListItem(self, index, list_src, list_dest):
757    
758            item = list_src.GetItem(index)
759    
760            x = list_dest.InsertStringItem(
761                    list_dest.GetItemCount(),
762                    str(self.dataList[item.GetData()]))
763    
764            list_dest.SetItemData(x, item.GetData())
765    
766            list_src.DeleteItem(index)
767    
768    #   def _OnListSize(self, event):
769    #       list = event.GetEventObject()
770    
771    #       list.SetColumnWidth(0, event.GetSize().GetWidth())
772    #      
773    
774    ID_QUANTILES_RANGE = 4001
775    ID_QUANTILES_RETRIEVE = 4002
776    
777    class GenQuantilesPanel(wxPanel):
778    
779        def __init__(self, parent, layer, fieldName, fieldType):
780            wxPanel.__init__(self, parent, -1)
781    
782            self.parent = parent
783            self.layer = layer
784            self.fieldName = fieldName
785            self.fieldType = fieldType
786    
787            topBox = wxStaticBoxSizer(wxStaticBox(self, -1, ""),
788                                        wxVERTICAL)
789    
790            self.text_range = wxTextCtrl(self, ID_QUANTILES_RANGE, "")
791            self.button_retrieve = wxButton(self, ID_QUANTILES_RETRIEVE,
792                                            _("Retrieve from Table"))
793    
794            self.spin_numClasses = wxSpinCtrl(self, -1, style=wxTE_RIGHT)
795            self.spin_numClasses.SetRange(1, sys.maxint)
796            self.spin_numClasses.SetValue(1)
797    
798    
799            sizer = wxBoxSizer(wxHORIZONTAL)
800            sizer.Add(wxStaticText(self, -1, _("Apply to Range")), 0, wxALL, 4)
801            sizer.Add(self.text_range, 1, wxALL, 4)
802            sizer.Add(self.button_retrieve, 0, wxALL, 4)
803    
804            topBox.Add(sizer, 0, wxEXPAND, 0)
805    
806            sizer = wxBoxSizer(wxHORIZONTAL)
807            sizer.Add(wxStaticText(self, -1, _("Number of Classes:")), 0, wxALL, 4)
808            sizer.Add(self.spin_numClasses, 1, wxALL, 4)
809    
810            topBox.Add(sizer, 0, wxEXPAND, 0)
811    
812            self.SetSizer(topBox)
813            self.SetAutoLayout(True)
814            topBox.Fit(self)
815            topBox.SetSizeHints(self)
816    
817            EVT_TEXT(self, ID_QUANTILES_RANGE, self.OnRangeText)
818            EVT_BUTTON(self, ID_QUANTILES_RETRIEVE, self.OnRetrieve)
819    
820            self.__range = None
821    
822        def GetNumGroups(self):
823            return self.spin_numClasses.GetValue()
824    
825        def GetRange(self):
826            assert self.__range is not None
827    
828            return self.__range
829    
830        def GetList(self):
831    
832            _list = []
833    
834            if self.layer.table is not None:
835                wxBeginBusyCursor()
836    
837                #
838                # FIXME: Replace with a call to table when the method
839                # has been written to get all the values
840                #
841                table = self.layer.table
842                for i in range(table.NumRows()):
843                    _list.append(table.ReadValue(i, self.fieldName))
844    
845                wxEndBusyCursor()
846    
847            return _list
848    
849        def OnRangeText(self, event):
850    
851            try:
852                self.__range = Range(self.text_range.GetValue())
853            except ValueError:
854                self.__range = None
855    
856            if self.__range is not None:
857                self.text_range.SetForegroundColour(wxBLACK)
858            else:
859                self.text_range.SetForegroundColour(wxRED)
860    
861        def OnRetrieve(self, event):
862    
863            if self.layer.table is not None:
864                wxBeginBusyCursor()
865                min, max = self.layer.table.ValueRange(self.fieldName)
866                self.text_range.SetValue("[" + str(min) + ";" + str(max) + "]")
867                wxEndBusyCursor()
868    
869    ID_CUSTOMRAMP_COPYSTART = 4001
870    ID_CUSTOMRAMP_COPYEND = 4002
871    ID_CUSTOMRAMP_EDITSTART = 4003
872    ID_CUSTOMRAMP_EDITEND = 4004
873    ID_CUSTOMRAMP_SPROP = 4005
874    ID_CUSTOMRAMP_EPROP = 4006
875    
876    class CustomRampPanel(wxPanel):
877    
878        def __init__(self, parent, shapeType):
879            wxPanel.__init__(self, parent, -1)
880    
881            topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""), wxHORIZONTAL)
882    
883            bsizer = wxBoxSizer(wxVERTICAL)
884            bsizer.Add(wxStaticText(self, -1, _("Start:")), 0, wxALL | wxCENTER, 4)
885            self.startPropCtrl = classifier.ClassGroupPropertiesCtrl(
886                self, ID_CUSTOMRAMP_SPROP,
887                ClassGroupProperties(), shapeType,
888                style=wxSIMPLE_BORDER, size=(40, 20))
889            bsizer.Add(self.startPropCtrl, 1, wxGROW | wxALL | wxCENTER, 4)
890            bsizer.Add(wxButton(self, ID_CUSTOMRAMP_EDITSTART, _("Change")),
891                       0, wxGROW | wxALL | wxCENTER, 4)
892    
893            topSizer.Add(bsizer,
894                       1, wxALL \
895                          | wxSHAPED \
896                          | wxALIGN_CENTER_HORIZONTAL \
897                          | wxALIGN_CENTER_VERTICAL, \
898                       4)
899    
900            bmp = resource.GetBitmapResource(USE_BMP, wxBITMAP_TYPE_XPM)
901            bsizer = wxBoxSizer(wxVERTICAL)
902            bsizer.Add(wxBitmapButton(self, ID_CUSTOMRAMP_COPYSTART, bmp),
903                       0, wxGROW | wxALL, 4)
904            bmp = resource.GetBitmapResource(USENOT_BMP, wxBITMAP_TYPE_XPM)
905            bsizer.Add(wxBitmapButton(self, ID_CUSTOMRAMP_COPYEND, bmp),
906                       0, wxGROW | wxALL, 4)
907    
908            topSizer.Add(bsizer,
909                       0, wxALL \
910                          | wxALIGN_CENTER_HORIZONTAL \
911                          | wxALIGN_CENTER_VERTICAL,
912                       4)
913    
914            bsizer = wxBoxSizer(wxVERTICAL)
915            bsizer.Add(wxStaticText(self, -1, _("End:")), 0, wxALL | wxCENTER, 4)
916            self.endPropCtrl = classifier.ClassGroupPropertiesCtrl(
917                self, ID_CUSTOMRAMP_EPROP,
918                ClassGroupProperties(), shapeType,
919                style=wxSIMPLE_BORDER, size=(40, 20))
920            bsizer.Add(self.endPropCtrl, 1, wxGROW | wxALL | wxCENTER, 4)
921            bsizer.Add(wxButton(self, ID_CUSTOMRAMP_EDITEND, _("Change")),
922                       0, wxGROW | wxALL | wxCENTER, 4)
923    
924            topSizer.Add(bsizer,
925                       1, wxALL \
926                          | wxSHAPED \
927                          | wxALIGN_RIGHT \
928                          | wxALIGN_CENTER_HORIZONTAL \
929                          | wxALIGN_CENTER_VERTICAL,
930                       4)
931    
932            EVT_BUTTON(self, ID_CUSTOMRAMP_COPYSTART, self._OnCopyStart)
933            EVT_BUTTON(self, ID_CUSTOMRAMP_COPYEND, self._OnCopyEnd)
934            EVT_BUTTON(self, ID_CUSTOMRAMP_EDITSTART, self._OnEditStart)
935            EVT_BUTTON(self, ID_CUSTOMRAMP_EDITEND, self._OnEditEnd)
936    
937            self.SetSizer(topSizer)
938            self.SetAutoLayout(True)
939            topSizer.SetSizeHints(self)
940    
941        def GetRamp(self):
942            return CustomRamp(self.startPropCtrl.GetProperties(),
943                              self.endPropCtrl.GetProperties())
944    
945          self.fillColor.red   += self.fill_redStep      def _OnCopyStart(self, event):
946          self.fillColor.green += self.fill_greenStep          self.endPropCtrl.SetProperties(self.startPropCtrl.GetProperties())
         self.fillColor.blue  += self.fill_blueStep  
947    
948          self.lineWidth       += self.line_widthStep      def _OnCopyEnd(self, event):
949            self.startPropCtrl.SetProperties(self.endPropCtrl.GetProperties())
950    
951          self.count -= 1      def _OnEditStart(self, event):
952            self.startPropCtrl.DoEdit()
953    
954          return prop      def _OnEditEnd(self, event):
955            self.endPropCtrl.DoEdit()
956    
957      

Legend:
Removed from v.620  
changed lines
  Added in v.978

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26