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

Legend:
Removed from v.614  
changed lines
  Added in v.907

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26