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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26