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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 629 - (show annotations)
Wed Apr 9 10:09:44 2003 UTC (21 years, 11 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/classgen.py
File MIME type: text/x-python
File size: 28591 byte(s)
Renamed GenRangePanel to GenUniformPanel.
(GenUniquePanel): New. Controls to allow the user to select
        which unique field values they would like in the classification.
(CustomRampPanel): Code that was in ClassGenDialog that allows
        the user to select the properties for a custom ramp.
(ClassGenerator.GenUniformDistribution): Was called GenerateRanges.

1 # Copyright (c) 2003 by Intevation GmbH
2 # Authors:
3 # Jonathan Coles <[email protected]>
4 #
5 # This program is free software under the GPL (>=v2)
6 # Read the file COPYING coming with Thuban for details.
7
8 from Thuban import _
9
10 from wxPython.wx import *
11
12 from Thuban.Model.classification import Classification, ClassGroupRange, \
13 ClassGroupSingleton, ClassGroupProperties
14
15 from Thuban.Model.table import Table, FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
16 FIELDTYPE_STRING
17
18 from Thuban.Model.color import Color
19
20 import classifier
21
22 from Thuban.common import Str2Num
23
24 ID_CLASSGEN_GEN = 4001
25 ID_CLASSGEN_CLOSE = 4002
26 ID_CLASSGEN_COMBO = 4007
27
28 COMBOSTR_UNIFORM = _("Uniform Distribution")
29 COMBOSTR_UNIQUE = _("Unique Values")
30
31 class ClassGenDialog(wxDialog):
32
33 def __init__(self, parent, layer, fieldName):
34 """Inialize the class generating dialog.
35
36 parent -- this must be an instance of the Classifier class
37 """
38
39 wxDialog.__init__(self, parent, -1, _("Generate Classification"),
40 style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
41
42 self.parent = parent
43 self.clazz = None
44
45 self.type, name, width, prec = layer.table.field_info_by_name(fieldName)
46
47 #############
48 # we need to create genButton first because when we create the
49 # panels they will call AllowGenerate() which uses genButton.
50 #
51 buttonSizer = wxBoxSizer(wxHORIZONTAL)
52 self.genButton = wxButton(self, ID_CLASSGEN_GEN, _("Generate"))
53
54 buttonSizer.Add(self.genButton, 0, wxALL, 4)
55 buttonSizer.Add(60, 20, 0, wxALL, 4)
56 buttonSizer.Add(wxButton(self, ID_CLASSGEN_CLOSE, _("Close")),
57 0, wxALL, 4)
58
59 #############
60
61 sizer = wxBoxSizer(wxVERTICAL)
62
63 sizer.Add(wxStaticText(self, -1, _("Field: %s") % fieldName),
64 0, wxALL, 4)
65 sizer.Add(wxStaticText(
66 self, -1,
67 _("Field Type: %s") % classifier.Classifier.type2string[self.type]),
68 0, wxALL, 4)
69
70 psizer = wxBoxSizer(wxHORIZONTAL)
71 psizer.Add(wxStaticText(
72 self, -1,
73 _("Generate:")),
74 0, wxALIGN_CENTER_VERTICAL, 0)
75
76 self.genCombo = wxComboBox(self,
77 ID_CLASSGEN_COMBO,
78 "", style = wxCB_READONLY)
79 psizer.Add(self.genCombo, 1, wxALL | wxGROW, 4)
80 EVT_COMBOBOX(self, ID_CLASSGEN_COMBO, self._OnGenTypeSelect)
81
82 sizer.Add(psizer, 0, wxALL | wxGROW, 4)
83
84 #############
85
86 self.genPanel = None
87
88 panel = GenUniquePanel(self, layer, fieldName, self.type)
89 self.genCombo.Append(COMBOSTR_UNIQUE)
90 self.genCombo.SetClientData(self.genCombo.GetCount() - 1, panel)
91 sizer.Add(panel, 1, wxGROW | wxALL, 4)
92
93 self.genPanel = panel
94
95 if self.type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):
96 panel = GenUniformPanel(self, layer, fieldName, self.type)
97 self.genCombo.Append(COMBOSTR_UNIFORM)
98 self.genCombo.SetClientData(self.genCombo.GetCount() - 1, panel)
99 sizer.Add(panel, 0, wxGROW | wxALL, 4)
100 sizer.Show(panel, False)
101
102 #############
103
104 self.propPanel = None
105
106 panel = CustomRampPanel(self, layer.ShapeType())
107
108 self.propPanel = panel
109
110 sizer.Add(panel, 1, wxALL | wxGROW, 4)
111
112 #############
113
114 sizer.Add(buttonSizer, 0,
115 wxALL | wxALIGN_BOTTOM | wxALIGN_CENTER_HORIZONTAL, 4)
116
117
118 self.SetSizer(sizer)
119 self.SetAutoLayout(True)
120 sizer.SetSizeHints(self)
121
122 self.sizer = sizer
123
124 EVT_BUTTON(self, ID_CLASSGEN_GEN, self._OnGenerate)
125 EVT_BUTTON(self, ID_CLASSGEN_CLOSE, self._OnCloseBtn)
126
127 def GetClassification(self):
128 return self.clazz
129
130 def AllowGenerate(self, on):
131 pass #self.genButton.Enable(on)
132
133 def _OnGenerate(self, event):
134
135 selIndex = self.genCombo.GetSelection()
136
137 sel = self.genCombo.GetString(selIndex)
138 genPanel = self.genCombo.GetClientData(selIndex)
139 propPanel = self.propPanel
140
141 if sel == COMBOSTR_UNIFORM:
142
143 min = genPanel.GetMin()
144 max = genPanel.GetMax()
145 numGroups = genPanel.GetNumGroups()
146 sp = propPanel.GetStartProperties()
147 ep = propPanel.GetEndProperties()
148
149 if min is not None \
150 and max is not None \
151 and numGroups is not None:
152
153 self.clazz = ClassGenerator().GenUnifromDistribution(
154 min, max, numGroups, sp, ep,
155 self.type == FIELDTYPE_INT)
156
157 self.parent._SetClassification(self.clazz)
158
159 elif sel == COMBOSTR_UNIQUE:
160
161 list = genPanel.GetValueList()
162 numGroups = genPanel.GetNumGroups()
163 sp = propPanel.GetStartProperties()
164 ep = propPanel.GetEndProperties()
165
166 if len(list) > 0 \
167 and numGroups is not None:
168
169 self.clazz = ClassGenerator().GenSingletonsFromList(
170 list, numGroups, sp, ep)
171
172 self.parent._SetClassification(self.clazz)
173
174 else:
175 pass
176
177 def _OnCloseBtn(self, event):
178 self.Close()
179
180 def _OnGenTypeSelect(self, event):
181
182 combo = event.GetEventObject()
183
184 selIndex = combo.GetSelection()
185
186 if self.genPanel is not None:
187 self.sizer.Show(self.genPanel, False)
188
189 self.genPanel = combo.GetClientData(selIndex)
190 if self.genPanel is not None:
191 self.sizer.Show(self.genPanel, True)
192
193 self.sizer.SetSizeHints(self)
194 self.sizer.Layout()
195
196
197 ID_UNIFORM_MIN = 4001
198 ID_UNIFORM_MAX = 4002
199 ID_UNIFORM_NGROUPS = 4003
200 ID_UNIFORM_STEP = 4004
201 ID_UNIFORM_RETRIEVE = 4005
202
203 class GenUniformPanel(wxPanel):
204
205 def __init__(self, parent, layer, fieldName, fieldType):
206 wxPanel.__init__(self, parent, -1)
207
208 self.parent = parent
209 self.layer = layer
210 self.fieldName = fieldName
211 self.fieldType = fieldType
212
213 topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""),
214 wxVERTICAL)
215
216 #############
217
218 sizer = wxBoxSizer(wxHORIZONTAL)
219
220 sizer.Add(wxStaticText(self, -1, _("Min:")), 0, wxALL, 4)
221 self.minCtrl = wxTextCtrl(self, ID_UNIFORM_MIN, style=wxTE_RIGHT)
222 sizer.Add(self.minCtrl, 1, wxALL, 4)
223 EVT_TEXT(self, ID_UNIFORM_MIN, self._OnRangeChanged)
224
225 sizer.Add(wxStaticText(self, -1, _("Max:")), 0, wxALL, 4)
226 self.maxCtrl = wxTextCtrl(self, ID_UNIFORM_MAX, style=wxTE_RIGHT)
227 sizer.Add(self.maxCtrl, 1, wxALL, 4)
228 EVT_TEXT(self, ID_UNIFORM_MAX, self._OnRangeChanged)
229
230 sizer.Add(wxButton(self, ID_UNIFORM_RETRIEVE, _("Retrieve From Table")),
231 0, wxALL, 4)
232 EVT_BUTTON(self, ID_UNIFORM_RETRIEVE, self._OnRetrieve)
233
234 topSizer.Add(sizer, 1, wxGROW, 0)
235
236 #############
237
238 sizer = wxBoxSizer(wxHORIZONTAL)
239
240 sizer.Add(wxStaticText(self, -1, _("Number of Groups:")), 0, wxALL, 4)
241 self.numGroupsCtrl = wxSpinCtrl(self, ID_UNIFORM_NGROUPS, style=wxTE_RIGHT)
242 EVT_TEXT(self, ID_UNIFORM_NGROUPS, self._OnNumGroupsChanged)
243 EVT_SPINCTRL(self, ID_UNIFORM_NGROUPS, self._OnNumGroupsChanged)
244 sizer.Add(self.numGroupsCtrl, 1, wxALL, 4)
245
246 sizer.Add(wxStaticText(self, -1, _("Stepping:")), 0, wxALL, 4)
247 self.stepCtrl = wxTextCtrl(self, ID_UNIFORM_STEP, style=wxTE_RIGHT)
248 EVT_TEXT(self, ID_UNIFORM_STEP, self._OnSteppingChanged)
249 sizer.Add(self.stepCtrl , 1, wxALL, 4)
250
251 topSizer.Add(sizer, 1, wxGROW, 0)
252
253 #############
254
255 self.SetSizer(topSizer)
256 self.SetAutoLayout(True)
257 topSizer.SetSizeHints(self)
258
259 self.numGroupsChanging = False
260 self.steppingChanging = False
261
262 self.numGroupsCtrl.SetRange(1, 100)
263
264 self.numGroupsCtrl.SetValue(1)
265 self.stepCtrl.SetValue("1")
266 self.maxCtrl.SetValue("0")
267 self.minCtrl.SetValue("0")
268 self.minCtrl.SetFocus()
269
270 def GetNumGroups(self):
271 value = self.numGroupsCtrl.GetValue()
272 return self.__GetValidatedTypeEntry(self.numGroupsCtrl,
273 value,
274 FIELDTYPE_INT,
275 None)
276
277 def GetStepping(self):
278 step = self.stepCtrl.GetValue()
279 return self.__GetValidatedTypeEntry(self.stepCtrl,
280 step,
281 self.fieldType,
282 0)
283
284 def GetMin(self):
285 min = self.minCtrl.GetValue()
286 max = self.maxCtrl.GetValue()
287 return self.__GetValidatedTypeEntry(self.minCtrl,
288 min,
289 self.fieldType,
290 max)
291
292 def GetMax(self):
293 min = self.minCtrl.GetValue()
294 max = self.maxCtrl.GetValue()
295 return self.__GetValidatedTypeEntry(self.maxCtrl,
296 max,
297 self.fieldType,
298 min)
299
300 def _OnRangeChanged(self, event):
301
302 hasFocus = wxWindow_FindFocus() == event.GetEventObject()
303 min = self.GetMin()
304 max = self.GetMax()
305
306 on = min is not None \
307 and max is not None
308
309 self.numGroupsCtrl.Enable(on)
310 self.stepCtrl.Enable(on)
311
312 if on:
313 self.numGroupsCtrl.SetRange(1, abs(max - min) / 0.001)
314
315 ngroups = self.GetNumGroups()
316
317 if ngroups is not None \
318 and min is not None \
319 and max is not None \
320 and ngroups != 0:
321
322 #self.stepCtrl.SetValue(str((max - min) / ngroups))
323 self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
324 #self.numGroupsCtrl.SetValue(ngroups)
325
326 self.parent.AllowGenerate(self.GetStepping() is not None)
327 else:
328 self.parent.AllowGenerate(False)
329
330
331 if hasFocus:
332 event.GetEventObject().SetFocus()
333
334 def _OnNumGroupsChanged(self, event):
335 if self.steppingChanging:
336 self.steppingChanging = False
337 return
338
339
340 obj = event.GetEventObject()
341 ngroups = self.GetNumGroups()
342 min = self.GetMin()
343 max = self.GetMax()
344
345 if ngroups >= self.numGroupsCtrl.GetMax():
346 self.numGroupsCtrl.SetRange(1, ngroups + 1)
347
348 if ngroups is not None \
349 and min is not None \
350 and max is not None \
351 and ngroups != 0:
352
353 #
354 # changing the value in the stepCtrl sends an event
355 # that the control is changing, at which point
356 # we try to update the numGroupsCtrl. This causes
357 # an infinite recursion. This flag and the one
358 # called steppingChanging tries to prevent the recursion.
359 #
360 self.numGroupsChanging = True
361
362 self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
363
364 self.parent.AllowGenerate(self.GetStepping() is not None)
365 else:
366 self.parent.AllowGenerate(False)
367
368
369 def _OnSteppingChanged(self, event):
370 if self.numGroupsChanging:
371 self.numGroupsChanging = False
372 return
373
374 step = self.GetStepping()
375 min = self.GetMin()
376 max = self.GetMax()
377
378 if step is not None \
379 and min is not None \
380 and max is not None \
381 and step != 0:
382
383 #
384 # see note in _OnNumGroupsChanged
385 #
386 self.steppingChanging = True
387 self.numGroupsCtrl.SetValue(self.__CalcNumGroups(min, max, step))
388
389 self.parent.AllowGenerate(self.GetNumGroups() is not None)
390 else:
391 self.parent.AllowGenerate(False)
392
393 def _OnRetrieve(self, event):
394
395 if self.layer.table is not None:
396 range = self.layer.table.field_range(self.fieldName)
397 self.minCtrl.SetValue(str(range[0][0]))
398 self.maxCtrl.SetValue(str(range[1][0]))
399
400 def __GetValidatedTypeEntry(self, win, value, type, badValue = None):
401
402 if type == FIELDTYPE_INT:
403 func = int
404 elif type == FIELDTYPE_DOUBLE:
405 func = float
406 elif type == FIELDTYPE_STRING:
407 func = str
408 else:
409 assert False, "Unsupported FIELDTYPE"
410 pass
411
412 if self.__ValidateEntry(win, value, func, badValue):
413 return func(value)
414
415 return None
416
417 def __ValidateEntry(self, win, value, test, badValue = None):
418
419 valid = value != ""
420
421 try:
422 if valid:
423 value = test(value)
424
425 if badValue is not None:
426 valid = value != test(badValue)
427 except ValueError:
428 valid = False
429
430 if valid:
431 win.SetForegroundColour(wxBLACK)
432 else:
433 win.SetForegroundColour(wxRED)
434
435 win.Refresh()
436
437 return valid
438
439 def __CalcStepping(self, min, max, ngroups):
440 step = Str2Num(str((max - min) / float(ngroups)))
441 if self.fieldType == FIELDTYPE_INT:
442 step = int(step)
443
444 return step
445
446 def __CalcNumGroups(self, min, max, step):
447 n = int((max - min) / step)
448 if n == 0:
449 n = 1
450
451 if self.fieldType == FIELDTYPE_INT and step == 1:
452 n += 1
453
454 return n
455
456
457 ID_UNIQUE_RETRIEVE = 4001
458 ID_UNIQUE_USEALL = 4002
459 ID_UNIQUE_USE = 4003
460 ID_UNIQUE_DONTUSE = 4004
461 ID_UNIQUE_USENONE = 4005
462 ID_UNIQUE_SORTAVAIL = 4006
463 ID_UNIQUE_SORTUSE = 4007
464
465 class GenUniquePanel(wxPanel):
466
467 def __init__(self, parent, layer, fieldName, fieldType):
468 wxPanel.__init__(self, parent, -1)
469
470 self.parent = parent
471 self.layer = layer
472 self.fieldName = fieldName
473 self.fieldType = fieldType
474
475 topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""),
476 wxVERTICAL)
477
478
479 sizer = wxBoxSizer(wxHORIZONTAL)
480
481 self.dataList = []
482
483 psizer = wxBoxSizer(wxVERTICAL)
484 self.list_avail = wxListCtrl(self, -1,
485 style=wxLC_REPORT | wxLC_SINGLE_SEL)
486 self.list_avail.InsertColumn(0, "Available")
487 self.list_avail_data = []
488 psizer.Add(self.list_avail, 1, wxGROW, 0)
489
490 psizer.Add(wxButton(self, ID_UNIQUE_SORTAVAIL, _("Sort")))
491
492 EVT_BUTTON(self, ID_UNIQUE_SORTAVAIL, self._OnSortAvailList)
493
494 sizer.Add(psizer, 1, wxGROW, 0)
495
496
497 bsizer = wxBoxSizer(wxVERTICAL)
498 bsizer.Add(wxButton(self, ID_UNIQUE_USEALL, _("Use All")),
499 0, wxGROW | wxALL, 4)
500 bsizer.Add(wxButton(self, ID_UNIQUE_USE, _("Use >>")),
501 0, wxGROW | wxALL, 4)
502 bsizer.Add(wxButton(self, ID_UNIQUE_DONTUSE, _("<< Don't Use")),
503 0, wxGROW | wxALL, 4)
504 bsizer.Add(wxButton(self, ID_UNIQUE_USENONE, _("Use None")),
505 0, wxGROW | wxALL, 4)
506
507 EVT_BUTTON(self, ID_UNIQUE_USEALL, self._OnUseAll)
508 EVT_BUTTON(self, ID_UNIQUE_USE, self._OnUse)
509 EVT_BUTTON(self, ID_UNIQUE_DONTUSE, self._OnDontUse)
510 EVT_BUTTON(self, ID_UNIQUE_USENONE, self._OnUseNone)
511
512 sizer.Add(bsizer, 0, wxALL | wxALIGN_CENTER_VERTICAL, 4)
513
514 psizer = wxBoxSizer(wxVERTICAL)
515 self.list_use = wxListCtrl(self, -1,
516 style=wxLC_REPORT | wxLC_SINGLE_SEL)
517 self.list_use.InsertColumn(0, "Use")
518 self.list_use_data = []
519 psizer.Add(self.list_use, 1, wxGROW, 0)
520
521 psizer.Add(wxButton(self, ID_UNIQUE_SORTUSE, _("Sort")))
522
523 EVT_BUTTON(self, ID_UNIQUE_SORTUSE, self._OnSortUseList)
524
525 sizer.Add(psizer, 1, wxGROW, 0)
526
527 bsizer = wxBoxSizer(wxVERTICAL)
528 bsizer.Add(wxButton(self, ID_UNIQUE_RETRIEVE,
529 _("Retrieve From Table")),
530 0, wxGROW | wxALL, 4)
531
532 EVT_BUTTON(self, ID_UNIQUE_RETRIEVE, self._OnRetrieve)
533
534 sizer.Add(bsizer, 0, wxALL, 4)
535
536 topSizer.Add(sizer, 1, wxGROW, 0)
537
538 self.SetSizer(topSizer)
539 self.SetAutoLayout(True)
540 topSizer.SetSizeHints(self)
541
542 self.parent.AllowGenerate(False)
543
544 self.mylist = ["Hallo", "Welt!", "Wie", "geht", "es", "dir", "?"]
545
546 def GetNumGroups(self):
547 return self.list_use.GetItemCount()
548
549 def GetValueList(self):
550 list = []
551 for i in range(self.list_use.GetItemCount()):
552 list.append(self.dataList[self.list_use.GetItemData(i)])
553 return list
554
555 def _OnSortAvailList(self, event):
556 self.list_avail.SortItems(lambda i1, i2:
557 cmp(self.dataList[i1],
558 self.dataList[i2]))
559
560 def _OnSortUseList(self, event):
561 self.list_use.SortItems(lambda i1, i2:
562 cmp(self.dataList[i1],
563 self.dataList[i2]))
564
565 def _OnRetrieve(self, event):
566 self.list_use.DeleteAllItems()
567 self.list_use_data = []
568 self.list_avail.DeleteAllItems()
569 self.list_avail_data = []
570
571 list = self.layer.table.GetUniqueValues(self.fieldName)
572 index = 0
573 for v in list:
574 self.dataList.append(v)
575 i = self.list_avail.InsertStringItem(index, str(v))
576 self.list_avail.SetItemData(index, i)
577
578 self.list_avail_data.append(v)
579 index += 1
580
581 def _OnUseAll(self, event):
582 for i in range(self.list_avail.GetItemCount()):
583 self.__MoveListItem(0, self.list_avail, self.list_use)
584
585 def _OnUse(self, event):
586 print "_OnUse"
587 self.__MoveSelectedItems(self.list_avail, self.list_use)
588
589 def _OnDontUse(self, event):
590 print "_OnDontUse"
591 self.__MoveSelectedItems(self.list_use, self.list_avail)
592
593 def _OnUseNone(self, event):
594 print "_OnUseNone"
595
596 for i in range(self.list_use.GetItemCount()):
597 self.__MoveListItem(0, self.list_use, self.list_avail)
598
599 def __MoveSelectedItems(self, list_src, list_dest):
600 while True:
601 index = list_src.GetNextItem(-1,
602 wxLIST_NEXT_ALL,
603 wxLIST_STATE_SELECTED)
604
605 if index == -1:
606 break
607
608 self.__MoveListItem(index, list_src, list_dest)
609
610
611 def __MoveListItem(self, index, list_src, list_dest):
612
613 item = list_src.GetItem(index)
614
615 x = list_dest.InsertStringItem(
616 list_dest.GetItemCount(),
617 str(self.dataList[item.GetData()]))
618
619 list_dest.SetItemData(x, item.GetData())
620
621 list_src.DeleteItem(index)
622
623 # def _OnListSize(self, event):
624 # list = event.GetEventObject()
625
626 # list.SetColumnWidth(0, event.GetSize().GetWidth())
627 #
628
629 ID_CUSTOMRAMP_COPYSTART = 4001
630 ID_CUSTOMRAMP_COPYEND = 4002
631 ID_CUSTOMRAMP_EDITSTART = 4003
632 ID_CUSTOMRAMP_EDITEND = 4004
633 ID_CUSTOMRAMP_SPROP = 4005
634 ID_CUSTOMRAMP_EPROP = 4006
635
636 class CustomRampPanel(wxPanel):
637
638 def __init__(self, parent, shapeType):
639 wxPanel.__init__(self, parent, -1)
640
641 topSizer = wxStaticBoxSizer(wxStaticBox(self, -1, ""), wxHORIZONTAL)
642
643 bsizer = wxBoxSizer(wxVERTICAL)
644 bsizer.Add(wxStaticText(self, -1, _("Start:")), 0, wxALL | wxCENTER, 4)
645 self.startPropCtrl = classifier.ClassGroupPropertiesCtrl(
646 self, ID_CUSTOMRAMP_SPROP,
647 ClassGroupProperties(), shapeType,
648 style=wxSIMPLE_BORDER, size=(40, 20))
649 bsizer.Add(self.startPropCtrl, 1, wxGROW | wxALL | wxCENTER, 4)
650 bsizer.Add(wxButton(self, ID_CUSTOMRAMP_EDITSTART, _("Change")),
651 0, wxGROW | wxALL | wxCENTER, 4)
652
653 topSizer.Add(bsizer,
654 1, wxALL \
655 | wxSHAPED \
656 | wxALIGN_CENTER_HORIZONTAL \
657 | wxALIGN_CENTER_VERTICAL, \
658 4)
659
660 bsizer = wxBoxSizer(wxVERTICAL)
661 bsizer.Add(wxButton(self, ID_CUSTOMRAMP_COPYSTART, _("Copy >>")),
662 0, wxGROW | wxALL, 4)
663 bsizer.Add(wxButton(self, ID_CUSTOMRAMP_COPYEND, _("<< Copy")),
664 0, wxGROW | wxALL, 4)
665
666 topSizer.Add(bsizer,
667 0, wxALL \
668 | wxALIGN_CENTER_HORIZONTAL \
669 | wxALIGN_CENTER_VERTICAL,
670 4)
671
672 bsizer = wxBoxSizer(wxVERTICAL)
673 bsizer.Add(wxStaticText(self, -1, _("End:")), 0, wxALL | wxCENTER, 4)
674 self.endPropCtrl = classifier.ClassGroupPropertiesCtrl(
675 self, ID_CUSTOMRAMP_EPROP,
676 ClassGroupProperties(), shapeType,
677 style=wxSIMPLE_BORDER, size=(40, 20))
678 bsizer.Add(self.endPropCtrl, 1, wxGROW | wxALL | wxCENTER, 4)
679 bsizer.Add(wxButton(self, ID_CUSTOMRAMP_EDITEND, _("Change")),
680 0, wxGROW | wxALL | wxCENTER, 4)
681
682 topSizer.Add(bsizer,
683 1, wxALL \
684 | wxSHAPED \
685 | wxALIGN_RIGHT \
686 | wxALIGN_CENTER_HORIZONTAL \
687 | wxALIGN_CENTER_VERTICAL,
688 4)
689
690 EVT_BUTTON(self, ID_CUSTOMRAMP_COPYSTART, self._OnCopyStart)
691 EVT_BUTTON(self, ID_CUSTOMRAMP_COPYEND, self._OnCopyEnd)
692 EVT_BUTTON(self, ID_CUSTOMRAMP_EDITSTART, self._OnEditStart)
693 EVT_BUTTON(self, ID_CUSTOMRAMP_EDITEND, self._OnEditEnd)
694
695 self.SetSizer(topSizer)
696 self.SetAutoLayout(True)
697 topSizer.SetSizeHints(self)
698
699 def GetStartProperties(self):
700 return self.startPropCtrl.GetProperties()
701
702 def GetEndProperties(self):
703 return self.endPropCtrl.GetProperties()
704
705 def _OnCopyStart(self, event):
706 self.endPropCtrl.SetProperties(self.startPropCtrl.GetProperties())
707
708 def _OnCopyEnd(self, event):
709 self.startPropCtrl.SetProperties(self.endPropCtrl.GetProperties())
710
711 def _OnEditStart(self, event):
712 self.startPropCtrl.DoEdit()
713
714 def _OnEditEnd(self, event):
715 self.endPropCtrl.DoEdit()
716
717 class ClassGenerator:
718
719 def GenSingletonsFromList(self, list, numGroups, prop1, prop2):
720 """Generate a new classification consisting solely of singletons.
721
722 The resulting classification will consist of at most 'numGroups'
723 groups whose group properties ramp between 'prop1' and 'prop2'. There
724 could be fewer groups if 'list' contains fewer that 'numGroups' items.
725
726 list -- any object that implements the iterator interface
727
728 numGroups -- how many groups to generate. This can not be
729 determined while the classification is being
730 generated because the stepping values must
731 be precalculated to ramp between prop1 and prop2.
732
733 prop1 -- initial group property values
734
735 prop2 -- final group property values
736 """
737
738 clazz = Classification()
739 if numGroups == 0: return clazz
740
741 for value, prop in zip(list, CustomRamp(numGroups, prop1, prop2)):
742 clazz.AppendGroup(ClassGroupSingleton(value, prop))
743
744 return clazz
745
746 def GenSingletons(self, min, max, numGroups, prop1, prop2):
747
748 clazz = Classification()
749
750 #step = int((max - min) / float(numGroups))
751 step = int(Str2Num(str((max - min + 1) / float(numGroups))))
752
753 if numGroups > 0:
754 cur_value = min
755
756 for prop in CustomRamp(numGroups, prop1, prop2):
757 clazz.AppendGroup(
758 ClassGroupSingleton(
759 Str2Num(str(cur_value)),
760 prop))
761 cur_value += step
762
763 return clazz
764
765 def GenUnifromDistribution(self, min, max, numGroups,
766 prop1, prop2, intStep = False):
767 """Generate a classification with numGroups range groups
768 each with the same interval.
769
770 intStep -- force the calculated stepping to an integer.
771 Useful if the values are integers but the
772 number of groups specified doesn't evenly
773 divide (max - min).
774 """
775
776 clazz = Classification()
777 if numGroups == 0: return clazz
778
779 step = Str2Num(str((max - min) / float(numGroups)))
780
781 if intStep:
782 step = int(step)
783
784 cur_min = min
785 cur_max = cur_min + step
786
787 i = 0
788 for prop in CustomRamp(numGroups, prop1, prop2):
789
790 if i == (numGroups - 1):
791 cur_max = max
792
793 # this check guards against rounding issues
794 if cur_min != cur_max:
795 clazz.AppendGroup(
796 ClassGroupRange(
797 Str2Num(str(cur_min)),
798 Str2Num(str(cur_max)),
799 prop))
800
801 cur_min = cur_max
802 cur_max += step
803 i += 1
804
805 return clazz
806
807 CLR = 0
808 STEP = 1
809 class CustomRamp:
810
811 def __init__(self, num, prop1, prop2):
812
813 self.count = int(num)
814 num = float(num)
815
816 clr = prop1.GetLineColor()
817 lineColor2 = prop2.GetLineColor()
818
819 self.noLine = clr is not Color.Transparent \
820 and lineColor2 is not Color.Transparent
821
822
823 self.lineInfo = self.__GetColorInfo(prop1.GetLineColor(),
824 prop2.GetLineColor(),
825 num)
826
827 self.fillInfo = self.__GetColorInfo(prop1.GetFill(),
828 prop2.GetFill(),
829 num)
830
831 self.lineWidth = prop1.GetLineWidth()
832 self.lineWidthStep = (prop2.GetLineWidth() - self.lineWidth) / num
833
834 def __iter__(self):
835 return self
836
837 def next(self):
838 if self.count == 0:
839 raise StopIteration
840
841 prop = ClassGroupProperties()
842
843 if self.lineInfo is None:
844 prop.SetLineColor(Color.Transparent)
845 else:
846 prop.SetLineColor(Color(self.lineInfo[CLR][0] / 255,
847 self.lineInfo[CLR][1] / 255,
848 self.lineInfo[CLR][2] / 255))
849
850 self.lineInfo[CLR][0] += self.lineInfo[STEP][0]
851 self.lineInfo[CLR][1] += self.lineInfo[STEP][1]
852 self.lineInfo[CLR][2] += self.lineInfo[STEP][2]
853
854 if self.fillInfo is None:
855 prop.SetFill(Color.Transparent)
856 else:
857 prop.SetFill(Color(self.fillInfo[CLR][0] / 255,
858 self.fillInfo[CLR][1] / 255,
859 self.fillInfo[CLR][2] / 255))
860
861 self.fillInfo[CLR][0] += self.fillInfo[STEP][0]
862 self.fillInfo[CLR][1] += self.fillInfo[STEP][1]
863 self.fillInfo[CLR][2] += self.fillInfo[STEP][2]
864
865
866 prop.SetLineWidth(int(self.lineWidth))
867 self.lineWidth += self.lineWidthStep
868
869 self.count -= 1
870
871 return prop
872
873 def __GetColorInfo(self, color1, color2, numGroups):
874
875 if color1 is Color.Transparent and color2 is Color.Transparent:
876 #
877 # returning early
878 #
879 return None
880 elif color1 is not Color.Transparent and color2 is Color.Transparent:
881 color = [color1.red * 255,
882 color1.green * 255,
883 color1.blue * 255]
884 step = (0, 0, 0)
885 elif color1 is Color.Transparent and color2 is not Color.Transparent:
886 color = [color2.red * 255,
887 color2.green * 255,
888 color2.blue * 255]
889 step = (0, 0, 0)
890 else:
891 color = [color1.red * 255,
892 color1.green * 255,
893 color1.blue * 255]
894 step = ((color2.red * 255 - color1.red * 255) / numGroups,
895 (color2.green * 255 - color1.green * 255) / numGroups,
896 (color2.blue * 255 - color1.blue * 255) / numGroups)
897
898
899 return (color, step)

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26