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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26