/[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 635 - (show annotations)
Wed Apr 9 15:42:25 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: 30912 byte(s)
Modifications to allow simple addition and selection of new color schemes.
(MonochromaticRamp): New. Generates a ramp between two colors.
(RedRamp): New. Generates a ramp of all red.
(GreenRamp): New. Generates a ramp of all green.
(BlueRamp): New. Generates a ramp of all blue.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26