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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26