pygmi 2.2.7__zip

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. pygmi-2.2.7/LICENSE.txt +623 -0
  2. pygmi-2.2.7/MANIFEST.in +7 -0
  3. pygmi-2.2.7/PKG-INFO +47 -0
  4. pygmi-2.2.7/README.md +55 -0
  5. pygmi-2.2.7/README.rst +20 -0
  6. pygmi-2.2.7/log.txt +242 -0
  7. pygmi-2.2.7/pygmi/__init__.py +22 -0
  8. pygmi-2.2.7/pygmi/clust/__init__.py +4 -0
  9. pygmi-2.2.7/pygmi/clust/crisp_clust.py +708 -0
  10. pygmi-2.2.7/pygmi/clust/datatypes.py +65 -0
  11. pygmi-2.2.7/pygmi/clust/fuzzy_clust.py +906 -0
  12. pygmi-2.2.7/pygmi/clust/graphs.py +421 -0
  13. pygmi-2.2.7/pygmi/clust/graphtool.py +667 -0
  14. pygmi-2.2.7/pygmi/clust/menu.py +139 -0
  15. pygmi-2.2.7/pygmi/clust/var_ratio.py +92 -0
  16. pygmi-2.2.7/pygmi/clust/xie_beni.py +93 -0
  17. pygmi-2.2.7/pygmi/helpdocs/linepointer.png +0 -0
  18. pygmi-2.2.7/pygmi/helpdocs/pygmi.main.html +31 -0
  19. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.ddisp.html +15 -0
  20. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.iodefs.exportkmz.html +13 -0
  21. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.iodefs.importpicture.html +16 -0
  22. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.layer.html +17 -0
  23. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.mext.html +44 -0
  24. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.misc.rangedcopy.html +16 -0
  25. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.param.html +37 -0
  26. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.prof.html +32 -0
  27. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.pview.html +26 -0
  28. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.gradients.html +14 -0
  29. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.tilt.html +14 -0
  30. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.visibility.html +14 -0
  31. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datagrid.html +13 -0
  32. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datamerge.html +11 -0
  33. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datareproj.html +11 -0
  34. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.rtp.html +14 -0
  35. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.ginterp.html +31 -0
  36. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.igrf.html +20 -0
  37. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.normalisation.html +14 -0
  38. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.smooth.html +22 -0
  39. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.tiltdepth.html +20 -0
  40. pygmi-2.2.7/pygmi/images/Help.png +0 -0
  41. pygmi-2.2.7/pygmi/images/bringtofront.png +0 -0
  42. pygmi-2.2.7/pygmi/images/cgs2.emf +0 -0
  43. pygmi-2.2.7/pygmi/images/delete.png +0 -0
  44. pygmi-2.2.7/pygmi/images/linepointer.png +0 -0
  45. pygmi-2.2.7/pygmi/images/logo256.ico +0 -0
  46. pygmi-2.2.7/pygmi/images/logo256.png +0 -0
  47. pygmi-2.2.7/pygmi/images/pointer.png +0 -0
  48. pygmi-2.2.7/pygmi/images/pygmi.png +0 -0
  49. pygmi-2.2.7/pygmi/images/sendtoback.png +0 -0
  50. pygmi-2.2.7/pygmi/main.py +1037 -0
  51. pygmi-2.2.7/pygmi/menu_default.py +327 -0
  52. pygmi-2.2.7/pygmi/misc.py +147 -0
  53. pygmi-2.2.7/pygmi/pfmod/__init__.py +6 -0
  54. pygmi-2.2.7/pygmi/pfmod/cubes.py +1488 -0
  55. pygmi-2.2.7/pygmi/pfmod/datatypes.py +292 -0
  56. pygmi-2.2.7/pygmi/pfmod/grvmag3d.py +1265 -0
  57. pygmi-2.2.7/pygmi/pfmod/iodefs.py +1001 -0
  58. pygmi-2.2.7/pygmi/pfmod/menu.py +107 -0
  59. pygmi-2.2.7/pygmi/pfmod/misc.py +301 -0
  60. pygmi-2.2.7/pygmi/pfmod/pfmod.py +248 -0
  61. pygmi-2.2.7/pygmi/pfmod/tab_ddisp.py +425 -0
  62. pygmi-2.2.7/pygmi/pfmod/tab_layer.py +490 -0
  63. pygmi-2.2.7/pygmi/pfmod/tab_mext.py +544 -0
  64. pygmi-2.2.7/pygmi/pfmod/tab_param.py +548 -0
  65. pygmi-2.2.7/pygmi/pfmod/tab_prof.py +946 -0
  66. pygmi-2.2.7/pygmi/pfmod/tab_pview.py +740 -0
  67. pygmi-2.2.7/pygmi/raster/IGRF11.COF +1635 -0
  68. pygmi-2.2.7/pygmi/raster/__init__.py +14 -0
  69. pygmi-2.2.7/pygmi/raster/cooper.py +718 -0
  70. pygmi-2.2.7/pygmi/raster/dataprep.py +1640 -0
  71. pygmi-2.2.7/pygmi/raster/datatypes.py +123 -0
  72. pygmi-2.2.7/pygmi/raster/equation_editor.py +256 -0
  73. pygmi-2.2.7/pygmi/raster/ginterp.py +1901 -0
  74. pygmi-2.2.7/pygmi/raster/graphs.py +531 -0
  75. pygmi-2.2.7/pygmi/raster/igrf.py +860 -0
  76. pygmi-2.2.7/pygmi/raster/iodefs.py +813 -0
  77. pygmi-2.2.7/pygmi/raster/menu.py +307 -0
  78. pygmi-2.2.7/pygmi/raster/normalisation.py +187 -0
  79. pygmi-2.2.7/pygmi/raster/show_table.py +245 -0
  80. pygmi-2.2.7/pygmi/raster/smooth.py +406 -0
  81. pygmi-2.2.7/pygmi/raster/tiltdepth.py +590 -0
  82. pygmi-2.2.7/pygmi/seis/__init__.py +0 -0
  83. pygmi-2.2.7/pygmi/seis/beachball.py +751 -0
  84. pygmi-2.2.7/pygmi/seis/datatypes.py +605 -0
  85. pygmi-2.2.7/pygmi/seis/del_rec.py +410 -0
  86. pygmi-2.2.7/pygmi/seis/iodefs.py +1261 -0
  87. pygmi-2.2.7/pygmi/seis/menu.py +136 -0
  88. pygmi-2.2.7/pygmi/seis/scan_imp.py +795 -0
  89. pygmi-2.2.7/pygmi/test/__init__.py +6 -0
  90. pygmi-2.2.7/pygmi/test/pfmod.py +212 -0
  91. pygmi-2.2.7/pygmi/test/tests.py +39 -0
  92. pygmi-2.2.7/pygmi/vector/__init__.py +7 -0
  93. pygmi-2.2.7/pygmi/vector/datatypes.py +74 -0
  94. pygmi-2.2.7/pygmi/vector/graphs.py +443 -0
  95. pygmi-2.2.7/pygmi/vector/iodefs.py +345 -0
  96. pygmi-2.2.7/pygmi/vector/menu.py +127 -0
  97. pygmi-2.2.7/pygmi.egg-info/PKG-INFO +47 -0
  98. pygmi-2.2.7/pygmi.egg-info/SOURCES.txt +105 -0
  99. pygmi-2.2.7/pygmi.egg-info/dependency_links.txt +1 -0
  100. pygmi-2.2.7/pygmi.egg-info/entry_points.txt +3 -0
  101. pygmi-2.2.7/pygmi.egg-info/not-zip-safe +1 -0
  102. pygmi-2.2.7/pygmi.egg-info/requires.txt +7 -0
  103. pygmi-2.2.7/pygmi.egg-info/top_level.txt +1 -0
  104. pygmi-2.2.7/quickstart.py +35 -0
  105. pygmi-2.2.7/setup.cfg +8 -0
  106. pygmi-2.2.7/setup.py +80 -0
@@ -0,0 +1,1901 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Name: ginterp.py (part of PyGMI)
3
+ #
4
+ # Author: Patrick Cole
5
+ # E-Mail: pcole@geoscience.org.za
6
+ #
7
+ # Copyright: (c) 2013 Council for Geoscience
8
+ # Licence: GPL-3.0
9
+ #
10
+ # This file is part of PyGMI
11
+ #
12
+ # PyGMI is free software: you can redistribute it and/or modify
13
+ # it under the terms of the GNU General Public License as published by
14
+ # the Free Software Foundation, either version 3 of the License, or
15
+ # (at your option) any later version.
16
+ #
17
+ # PyGMI is distributed in the hope that it will be useful,
18
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ # GNU General Public License for more details.
21
+ #
22
+ # You should have received a copy of the GNU General Public License
23
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
24
+ # -----------------------------------------------------------------------------
25
+ # Licence for original ModestImage code (modified version below)
26
+ # ModestImage
27
+ # Copyright (c) 2013 Chris Beaumont
28
+ #
29
+ # Permission is hereby granted, free of charge, to any person obtaining a
30
+ # copy of this software and associated documentation files (the "Software"),
31
+ # to deal in the Software without restriction, including without limitation
32
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
33
+ # and/or sell copies of the Software, and to permit persons to whom the
34
+ # Software is furnished to do so, subject to the following conditions:
35
+ #
36
+ # The above copyright notice and this permission notice shall be included in
37
+ # all copies or substantial portions of the Software.
38
+ #
39
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
44
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
45
+ # DEALINGS IN THE SOFTWARE.
46
+ # -----------------------------------------------------------------------------
47
+ """
48
+ Plot Raster Data
49
+
50
+ This is the raster data interpretation module. This module allows for the
51
+ display of raster data in a variety of modes, as well as the export of that
52
+ display to GeoTiff format.
53
+
54
+ Currently the following is supported
55
+ * Pseudo Color - data mapped to a color map
56
+ * Contours with solid contours
57
+ * RGB ternary images
58
+ * CMYK ternary images
59
+ * Sun shaded or hill shaded images
60
+
61
+ It can be very effectively used in conjunction with a GIS package which
62
+ supports GeoTiff files.
63
+ """
64
+
65
+ import os
66
+ import copy
67
+ import numpy as np
68
+ import numexpr as ne
69
+ from math import cos, sin, tan
70
+ from PyQt4 import QtGui, QtCore
71
+ from scipy import ndimage
72
+ from matplotlib.figure import Figure
73
+ import matplotlib.gridspec as gridspec
74
+ import matplotlib.cm as cm
75
+ import matplotlib.pyplot as plt
76
+ import matplotlib.image as mi
77
+ import matplotlib.colors as mcolors
78
+ import matplotlib.colorbar as mcolorbar
79
+ from matplotlib import rcParams
80
+ from matplotlib.backends.backend_qt4agg import FigureCanvas
81
+ from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as \
82
+ NavigationToolbar
83
+ import pygmi.raster.iodefs as iodefs
84
+ import pygmi.raster.dataprep as dataprep
85
+ from matplotlib.path import Path
86
+ from matplotlib.patches import PathPatch
87
+ import pygmi.menu_default as menu_default
88
+ #import pygmi.raster.modest_image as modest_image
89
+ import pdb
90
+
91
+
92
+ class ModestImage2(mi.AxesImage):
93
+ """
94
+ Computationally modest image class - modified for use in PyGMI.
95
+
96
+ ModestImage is an extension of the Matplotlib AxesImage class
97
+ better suited for the interactive display of larger images. Before
98
+ drawing, ModestImage resamples the data array based on the screen
99
+ resolution and view window. This has very little affect on the
100
+ appearance of the image, but can substantially cut down on
101
+ computation since calculations of unresolved or clipped pixels
102
+ are skipped.
103
+
104
+ The interface of ModestImage is the same as AxesImage. However, it
105
+ does not currently support setting the 'extent' property. There
106
+ may also be weird coordinate warping operations for images that
107
+ I'm not aware of. Don't expect those to work either.
108
+
109
+ ModestImage
110
+ Copyright (c) 2013 Chris Beaumont
111
+
112
+ Permission is hereby granted, free of charge, to any person obtaining a
113
+ copy of this software and associated documentation files (the "Software"),
114
+ to deal in the Software without restriction, including without limitation
115
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
116
+ and/or sell copies of the Software, and to permit persons to whom the
117
+ Software is furnished to do so, subject to the following conditions:
118
+
119
+ The above copyright notice and this permission notice shall be included in
120
+ all copies or substantial portions of the Software.
121
+
122
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
123
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
124
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
125
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
126
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
127
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
128
+ DEALINGS IN THE SOFTWARE.
129
+ """
130
+ def __init__(self, *args, **kwargs):
131
+ if 'extent' in kwargs and kwargs['extent'] is not None:
132
+ raise NotImplementedError("ModestImage does not support extents")
133
+
134
+ self._full_res = None
135
+ self._sx, self._sy = None, None
136
+ self._bounds = (None, None, None, None)
137
+ super(ModestImage2, self).__init__(*args, **kwargs)
138
+
139
+ self.smallres = None
140
+ self.cbar = cm.jet
141
+ self.htype = 'Linear'
142
+ self.hstype = 'Linear'
143
+ self.dtype = 'Single Color Map'
144
+ self.cell = 100.
145
+ self.phi = -np.pi/4.
146
+ self.theta = np.pi/4.
147
+ self.alpha = .0
148
+ self.kval = 0.01
149
+ self._rgbacache = None
150
+ self._oldxslice = None
151
+ self._oldyslice = None
152
+
153
+ def set_data(self, A):
154
+ """
155
+ Set the image array
156
+
157
+ ACCEPTS: numpy/PIL Image A
158
+ """
159
+ self._full_res = A
160
+ self._A = A
161
+ self.smallres = A
162
+
163
+ # if self._A.dtype != np.uint8 and not np.can_cast(self._A.dtype,
164
+ # np.float):
165
+ # raise TypeError("Image data can not convert to float")
166
+ #
167
+ # if (self._A.ndim not in (2, 3) or
168
+ # (self._A.ndim == 3 and self._A.shape[-1] not in (3, 4))):
169
+ # raise TypeError("Invalid dimensions for image data")
170
+
171
+ self._imcache = None
172
+ self._rgbacache = None
173
+ self._oldxslice = None
174
+ self._oldyslice = None
175
+ self._sx, self._sy = None, None
176
+ if self.axes.dataLim.x0 != np.inf:
177
+ self._scale_to_res()
178
+
179
+ # def get_array(self):
180
+ # """Override to return the full-resolution array"""
181
+ # return self._full_res
182
+
183
+ def _scale_to_res(self):
184
+ """ Change self._A and _extent to render an image whose
185
+ resolution is matched to the eventual rendering."""
186
+
187
+ ax = self.axes
188
+
189
+ fx0, fy0, fx1, fy1 = ax.dataLim.extents
190
+ try:
191
+ tmp = self._full_res.shape
192
+ rows = tmp[0]
193
+ cols = tmp[1]
194
+ except AttributeError:
195
+ tmp = self._full_res[0].shape
196
+ rows = tmp[0]
197
+ cols = tmp[1]
198
+
199
+ ddx = (fx1-fx0)/cols
200
+ ddy = (fy1-fy0)/rows
201
+
202
+ ext = ax.transAxes.transform([1, 1]) - ax.transAxes.transform([0, 0])
203
+ xlim, ylim = ax.get_xlim(), ax.get_ylim()
204
+ dx, dy = xlim[1] - xlim[0], ylim[1] - ylim[0]
205
+
206
+ y0 = max(0, (ylim[0]-fy0)/ddy)
207
+ y1 = min(rows, (ylim[1]-fy0)/ddy)
208
+ x0 = max(0, (xlim[0]-fx0)/ddx)
209
+ x1 = min(cols, (xlim[1] - fx0)/ddx)
210
+
211
+ if y1 == y0:
212
+ y1 = y0+1
213
+
214
+ if x1 == x0:
215
+ x1 = x0+1
216
+
217
+ y0, y1, x0, x1 = [int(i) for i in [y0, y1, x0, x1]]
218
+
219
+ # This divisor is to slightly increase the resolution of sunshaded
220
+ # images to get optimal detail.
221
+ divtmp = 1.0
222
+ if self.dtype == 'Sunshade':
223
+ divtmp = 1.5
224
+
225
+ sy = max(int(np.ceil(dy/(ddy*ext[1]))/divtmp), 1)
226
+ sx = max(int(np.ceil(dx/(ddx*ext[0]))/divtmp), 1)
227
+
228
+ if self._sx is None:
229
+ pass
230
+ elif (sx >= self._sx and sy >= self._sy and
231
+ x0 >= self._bounds[0] and x1 <= self._bounds[1] and
232
+ y0 >= self._bounds[2] and y1 <= self._bounds[3]):
233
+ return
234
+
235
+ if self.dtype == 'Single Color Map':
236
+ pseudo = self._full_res[(rows-y1):(rows-y0):sy, x0:x1:sx]
237
+ mask = pseudo.mask
238
+
239
+ if self.htype == '95% Linear, 5% Compact':
240
+ pseudo = histcomp(pseudo)
241
+
242
+ if self.htype == 'Histogram Equalization':
243
+ pseudo = histeq(pseudo)
244
+
245
+ self.smallres = pseudo.copy()
246
+
247
+ pnorm = norm2(pseudo)
248
+
249
+ colormap = self.cbar(pnorm)
250
+ colormap[:, :, 3] = np.logical_not(mask)
251
+
252
+ self._A = colormap
253
+
254
+ elif self.dtype == 'Sunshade':
255
+ # pseudo = self._full_res[0]
256
+ # sun = self._full_res[1]
257
+ pseudo = self._full_res[0][(rows-y1):(rows-y0):sy, x0:x1:sx]
258
+ sun = self._full_res[1][(rows-y1):(rows-y0):sy, x0:x1:sx]
259
+ mask = np.logical_or(pseudo.mask, sun.mask)
260
+
261
+ if self.htype == '95% Linear, 5% Compact':
262
+ pseudo = histcomp(pseudo)
263
+
264
+ if self.htype == 'Histogram Equalization':
265
+ pseudo = histeq(pseudo)
266
+
267
+ if self.hstype == '95% Linear, 5% Compact':
268
+ sun = histcomp(sun)
269
+
270
+ if self.hstype == 'Histogram Equalization':
271
+ sun = histeq(sun)
272
+
273
+
274
+ self.smallres = np.ma.ones((sun.shape[0], sun.shape[1], 2))
275
+ self.smallres[:, :, 0] = pseudo
276
+ self.smallres[:, :, 1] = sun
277
+
278
+ sunshader = currentshader(sun.data, self.cell, self.theta,
279
+ self.phi, self.alpha)
280
+
281
+ snorm = norm2(sunshader)
282
+ pnorm = norm2(pseudo)
283
+
284
+ colormap = self.cbar(pnorm)
285
+
286
+ colormap[:, :, 0] *= snorm # red
287
+ colormap[:, :, 1] *= snorm # green
288
+ colormap[:, :, 2] *= snorm # blue
289
+ colormap[:, :, 3] = np.logical_not(mask)
290
+
291
+ self._A = colormap
292
+
293
+ elif 'Ternary' in self.dtype:
294
+ red = self._full_res[0][(rows-y1):(rows-y0):sy, x0:x1:sx]
295
+ green = self._full_res[1][(rows-y1):(rows-y0):sy, x0:x1:sx]
296
+ blue = self._full_res[2][(rows-y1):(rows-y0):sy, x0:x1:sx]
297
+ mask = np.logical_or(red.mask, green.mask)
298
+ mask = np.logical_or(mask, blue.mask)
299
+
300
+ if self.htype == '95% Linear, 5% Compact':
301
+ red = histcomp(red)
302
+ green = histcomp(green)
303
+ blue = histcomp(blue)
304
+
305
+ if self.htype == 'Histogram Equalization':
306
+ red = histeq(red)
307
+ green = histeq(green)
308
+ blue = histeq(blue)
309
+
310
+ self.smallres = np.ma.ones((red.shape[0], red.shape[1], 3))
311
+ self.smallres[:, :, 0] = red
312
+ self.smallres[:, :, 1] = green
313
+ self.smallres[:, :, 2] = blue
314
+
315
+ colormap = np.ma.ones((red.shape[0], red.shape[1], 4))
316
+ colormap[:, :, 0] = norm2(red)
317
+ colormap[:, :, 1] = norm2(green)
318
+ colormap[:, :, 2] = norm2(blue)
319
+ colormap[:, :, 3] = np.logical_not(mask)
320
+
321
+ if 'CMY' in self.dtype:
322
+ colormap[:, :, 0] = (1-colormap[:, :, 0])*(1-self.kval)
323
+ colormap[:, :, 1] = (1-colormap[:, :, 1])*(1-self.kval)
324
+ colormap[:, :, 2] = (1-colormap[:, :, 2])*(1-self.kval)
325
+
326
+ self._A = colormap
327
+
328
+ y0 = ylim[0]
329
+ y1 = ylim[1]
330
+ x0 = xlim[0]
331
+ x1 = xlim[1]
332
+
333
+ # self.set_extent([x0 - .5, x1 - .5, y0 - .5, y1 - .5])
334
+ self.set_extent([x0, x1, y0, y1])
335
+ self._sx = sx
336
+ self._sy = sy
337
+ self._bounds = (x0, x1, y0, y1)
338
+ self.changed()
339
+
340
+ def draw(self, renderer, *args, **kwargs):
341
+ """ Draw """
342
+
343
+ # This loop forces the histograms to remain static
344
+ for argb in self.figure.axes[1:]:
345
+ argb.set_xlim(argb.dataLim.x0, argb.dataLim.x1)
346
+ argb.set_ylim(argb.dataLim.y0, argb.dataLim.y1*1.2)
347
+
348
+ # self._scale_to_res()
349
+ # The next command runs the original draw for this class.
350
+ super().draw(renderer, *args, **kwargs)
351
+
352
+
353
+ class ModestImage(ModestImage2):
354
+ """ Modest Image """
355
+ def __init__(self, *args, **kwargs):
356
+ ModestImage2.__init__(self, *args, **kwargs)
357
+
358
+
359
+ def imshow(axes, X, cmap=None, norm=None, aspect=None,
360
+ interpolation=None, alpha=None, vmin=None, vmax=None,
361
+ origin=None, extent=None, shape=None, filternorm=1,
362
+ filterrad=4.0, imlim=None, resample=None, url=None, **kwargs):
363
+ """Similar to matplotlib's imshow command, but produces a ModestImage
364
+
365
+ Unlike matplotlib version, must explicitly specify axes
366
+ """
367
+
368
+ if not axes._hold:
369
+ axes.cla()
370
+ if norm is not None:
371
+ assert isinstance(norm, mcolors.Normalize)
372
+ if aspect is None:
373
+ aspect = rcParams['image.aspect']
374
+ axes.set_aspect(aspect)
375
+ im = ModestImage(axes, cmap, norm, interpolation, origin, extent,
376
+ filternorm=filternorm, filterrad=filterrad,
377
+ resample=resample, **kwargs)
378
+
379
+ im.set_data(X)
380
+ im.set_alpha(alpha)
381
+ axes._set_artist_props(im)
382
+
383
+ if im.get_clip_path() is None:
384
+ # image does not already have clipping set, clip to axes patch
385
+ im.set_clip_path(axes.patch)
386
+
387
+ # if norm is None and shape is None:
388
+ # im.set_clim(vmin, vmax)
389
+ if vmin is not None or vmax is not None:
390
+ im.set_clim(vmin, vmax)
391
+ else:
392
+ im.autoscale_None()
393
+ im.set_url(url)
394
+
395
+ # update ax.dataLim, and, if autoscaling, set viewLim
396
+ # to tightly fit the image, regardless of dataLim.
397
+ im.set_extent(im.get_extent())
398
+
399
+ axes.images.append(im)
400
+ im._remove_method = lambda h: axes.images.remove(h)
401
+
402
+ return im
403
+
404
+
405
+ class MyMplCanvas(FigureCanvas):
406
+ """
407
+ Canvas for the actual plot
408
+
409
+ Attributes
410
+ ----------
411
+ htype : str
412
+ string indicating the histogram stretch to apply to the data
413
+ hstype : str
414
+ string indicating the histogram stretch to apply to the sun data
415
+ cbar : matplotlib color map
416
+ color map to be used for pseudo color bars
417
+ data : list
418
+ list of PyGMI raster data objects - used for color images
419
+ sdata : list
420
+ list of PyGMI raster data objects - used for shaded images
421
+ gmode : str
422
+ string contaning the graphics mode - Contour, Ternary, Sunshade,
423
+ Single Color Map.
424
+ argb : list
425
+ list of matplotlib subplots. There are up to three.
426
+ hhist : list
427
+ matplotlib hist associated with argb
428
+ hband: list
429
+ list of strings containing the band names to be used.
430
+ htxt : list
431
+ list of strings associated with hhist, denoting a raster value (where
432
+ mouse is currently hovering over on image)
433
+ image : Modestimage imshow
434
+ imshow instance - this is the primary way of displaying an image.
435
+ cnt : matplotlib contour
436
+ contour instance - used for the contour image
437
+ cntf : matplotlib contourf
438
+ contourf instance - used for the contour image
439
+ background : matplotlib bounding box
440
+ image bounding box - used in blitting
441
+ bbox_hist_red : matplotlib bounding box
442
+ red histogram bounding box
443
+ bbox_hist_green : matplotlib bounding box
444
+ green histogram bounding box
445
+ bbox_hist_blue : matplotlib bounding box
446
+ blue histogram bounding box
447
+ axes : matpolotlib axes
448
+ axes for the plot
449
+ pinit : numpy array
450
+ calculated with aspect - used in sunshading
451
+ qinit : numpy array
452
+ calculated with aspect - used in sunshading
453
+ phi : float
454
+ azimuth (sunshading)
455
+ theta : float
456
+ sun elevation (sunshading)
457
+ cell : float
458
+ between 1 and 100 - controls sunshade detail.
459
+ alpha : float
460
+ how much incident light is reflected (0 to 1)
461
+ kval : float
462
+ k value for cmyk mode
463
+ """
464
+ def __init__(self, parent):
465
+ fig = Figure()
466
+ super(MyMplCanvas, self).__init__(fig)
467
+
468
+ # figure stuff
469
+ self.htype = 'Linear'
470
+ self.hstype = 'Linear'
471
+ self.cbar = cm.jet
472
+ self.data = []
473
+ self.sdata = []
474
+ self.gmode = None
475
+ self.argb = [None, None, None]
476
+ self.hhist = [None, None, None]
477
+ self.hband = [None, None, None]
478
+ self.htxt = [None, None, None]
479
+ self.image = None
480
+ self.cnt = None
481
+ self.cntf = None
482
+ self.background = None
483
+ self.bbox_hist_red = None
484
+ self.bbox_hist_green = None
485
+ self.bbox_hist_blue = None
486
+
487
+ gspc = gridspec.GridSpec(3, 4)
488
+ self.axes = fig.add_subplot(gspc[0:, 1:])
489
+ self.axes.xaxis.set_visible(False)
490
+ self.axes.yaxis.set_visible(False)
491
+
492
+ for i in range(3):
493
+ self.argb[i] = fig.add_subplot(gspc[i, 0])
494
+ self.argb[i].xaxis.set_visible(False)
495
+ self.argb[i].yaxis.set_visible(False)
496
+ self.argb[i].autoscale(False)
497
+
498
+ fig.subplots_adjust(bottom=0.05)
499
+ fig.subplots_adjust(top=.95)
500
+ fig.subplots_adjust(left=0.05)
501
+ fig.subplots_adjust(right=.95)
502
+ fig.subplots_adjust(wspace=0.05)
503
+ fig.subplots_adjust(hspace=0.05)
504
+
505
+ self.setParent(parent)
506
+
507
+ FigureCanvas.setSizePolicy(self,
508
+ QtGui.QSizePolicy.Expanding,
509
+ QtGui.QSizePolicy.Expanding)
510
+ FigureCanvas.updateGeometry(self)
511
+
512
+ self.figure.canvas.mpl_connect('motion_notify_event', self.move)
513
+
514
+ # sun shading stuff
515
+ self.pinit = None
516
+ self.qinit = None
517
+ self.phi = -np.pi/4.
518
+ self.theta = np.pi/4.
519
+ self.cell = 100.
520
+ self.alpha = .0
521
+
522
+ # cmyk stuff
523
+ self.kval = 0.01
524
+
525
+ def dat_extent(self, dat):
526
+ """ Gets the extend of the dat variable """
527
+ left = dat.tlx
528
+ top = dat.tly
529
+ right = left + dat.cols*dat.xdim
530
+ bottom = top - dat.rows*dat.ydim
531
+ return (left, right, bottom, top)
532
+
533
+ def init_graph(self):
534
+ """ Initialize the graph """
535
+
536
+ self.axes.clear()
537
+ for i in range(3):
538
+ self.argb[i].clear()
539
+
540
+ x_1, x_2, y_1, y_2 = self.dat_extent(self.data[0])
541
+ self.axes.set_xlim(x_1, x_2)
542
+ self.axes.set_ylim(y_1, y_2)
543
+ self.axes.set_aspect('equal')
544
+
545
+ self.figure.canvas.draw()
546
+ QtGui.QApplication.processEvents()
547
+
548
+ self.background = self.figure.canvas.copy_from_bbox(self.axes.bbox)
549
+ self.bbox_hist_red = self.figure.canvas.copy_from_bbox(
550
+ self.argb[0].bbox)
551
+ self.bbox_hist_green = self.figure.canvas.copy_from_bbox(
552
+ self.argb[1].bbox)
553
+ self.bbox_hist_blue = self.figure.canvas.copy_from_bbox(
554
+ self.argb[2].bbox)
555
+
556
+ self.image = imshow(self.axes, self.data[0].data, origin='upper',
557
+ extent=(x_1, x_2, y_1, y_2))
558
+
559
+ self.update_graph()
560
+
561
+ def lamb_horn(self):
562
+ """ Lambert by horn """
563
+ R = ((1+self.p0*self.p+self.q0*self.q) /
564
+ (self.sqrt_1p2q2+np.sqrt(1+self.p0**2+self.q0**2)))
565
+ return R
566
+
567
+ def move(self, event):
568
+ """ Mouse is moving """
569
+ if len(self.data) == 0 or self.gmode == 'Contour':
570
+ return
571
+
572
+ if event.inaxes == self.axes:
573
+ zval = [-999, -999, -999]
574
+
575
+ for i in self.data:
576
+ for j in range(3):
577
+ if i.dataid == self.hband[j]:
578
+ col = int((event.xdata - i.tlx)/i.xdim)
579
+ row = int((i.tly - event.ydata)/i.ydim)
580
+ zval[j] = i.data[row, col]
581
+
582
+ if self.gmode == 'Single Color Map':
583
+ bnum = self.update_hist_single(zval[0])
584
+ self.figure.canvas.restore_region(self.bbox_hist_red)
585
+ self.argb[0].draw_artist(self.htxt[0])
586
+ self.argb[0].draw_artist(self.hhist[0][2][bnum])
587
+ self.figure.canvas.update()
588
+
589
+ if 'Ternary' in self.gmode:
590
+ bnum = self.update_hist_rgb(zval)
591
+ self.figure.canvas.restore_region(self.bbox_hist_red)
592
+ self.figure.canvas.restore_region(self.bbox_hist_green)
593
+ self.figure.canvas.restore_region(self.bbox_hist_blue)
594
+
595
+ for j in range(3):
596
+ self.argb[j].draw_artist(self.htxt[j])
597
+ self.argb[j].draw_artist(self.hhist[j][2][bnum[j]])
598
+
599
+ self.figure.canvas.update()
600
+
601
+ if self.gmode == 'Sunshade':
602
+ for i in self.sdata:
603
+ for j in [1]:
604
+ if i.dataid == self.hband[j]:
605
+ col = int((event.xdata - i.tlx)/i.xdim)
606
+ row = int((i.tly - event.ydata)/i.ydim)
607
+ zval[j] = i.data[row, col]
608
+ bnum = self.update_hist_sun(zval)
609
+ self.figure.canvas.restore_region(self.bbox_hist_red)
610
+ self.figure.canvas.restore_region(self.bbox_hist_green)
611
+ for j in range(2):
612
+ self.argb[j].draw_artist(self.htxt[j])
613
+ self.argb[j].draw_artist(self.hhist[j][2][bnum[j]])
614
+
615
+ self.figure.canvas.update()
616
+
617
+ def update_contour(self):
618
+ """ Updates the contour map """
619
+ self.image.dtype = 'Single Color Map'
620
+
621
+ x1, x2, y1, y2 = self.dat_extent(self.data[0])
622
+ self.image.set_visible(False)
623
+
624
+ for i in self.data:
625
+ if i.dataid == self.hband[0]:
626
+ dat = i.data
627
+
628
+ self.image.set_data(dat)
629
+ dat = norm2(self.image.smallres)
630
+
631
+ xdim = (x2-x1)/dat.data.shape[1]/2
632
+ ydim = (y2-y1)/dat.data.shape[0]/2
633
+ xi = np.linspace(x1+xdim, x2-xdim, dat.data.shape[1])
634
+ yi = np.linspace(y2-ydim, y1+ydim, dat.data.shape[0])
635
+
636
+ self.cnt = self.axes.contour(xi, yi, dat, extent=(x1, x2, y1, y2),
637
+ linewidths=1, colors='k')
638
+ self.cntf = self.axes.contourf(xi, yi, dat, extent=(x1, x2, y1, y2),
639
+ cmap=self.cbar)
640
+
641
+ self.figure.canvas.draw()
642
+
643
+ def update_graph(self):
644
+ """ Update the plot """
645
+ if len(self.data) == 0 or self.gmode is None:
646
+ return
647
+
648
+ self.image.cbar = self.cbar
649
+ self.image.htype = self.htype
650
+ self.image.hstype = self.hstype
651
+ self.image.alpha = self.alpha
652
+ self.image.cell = self.cell
653
+ self.image.theta = self.theta
654
+ self.image.phi = self.phi
655
+ self.image.kval = self.kval
656
+
657
+ for i in range(3):
658
+ self.argb[i].clear()
659
+
660
+ if self.gmode == 'Single Color Map':
661
+ self.update_single_color_map()
662
+
663
+ if self.gmode == 'Contour':
664
+ self.update_contour()
665
+
666
+ if 'Ternary' in self.gmode:
667
+ self.update_rgb()
668
+
669
+ if self.gmode == 'Sunshade':
670
+ self.update_shade_plot()
671
+
672
+ def update_hist_rgb(self, zval):
673
+ """ updates the rgb histograms """
674
+ hcol = ['r', 'g', 'b']
675
+ if 'CMY' in self.gmode:
676
+ hcol = ['c', 'm', 'y']
677
+
678
+ hst = self.hhist
679
+ bnum = []
680
+
681
+ for i in range(3):
682
+ bins, patches = hst[i][1:]
683
+ for j in patches:
684
+ j.set_color(hcol[i])
685
+
686
+ if np.ma.is_masked(zval[i]) is True:
687
+ bnum.append(0)
688
+ continue
689
+
690
+ binnum = (bins < zval[i]).sum()-1
691
+
692
+ if binnum > -1 and binnum < len(patches):
693
+ patches[binnum].set_color('k')
694
+ bnum.append(binnum)
695
+ else:
696
+ bnum.append(0)
697
+ self.update_hist_text(self.htxt[i], zval[i])
698
+ return bnum
699
+
700
+ def update_hist_single(self, zval, hno=0):
701
+ """ updates the color on a single histogram """
702
+ hst = self.hhist[hno]
703
+ bins, patches = hst[1:]
704
+ binave = np.arange(0, 1, 1/(bins.size-2))
705
+
706
+ if hno == 0:
707
+ bincol = self.cbar(binave)
708
+ else:
709
+ bincol = cm.gray(binave)
710
+
711
+ for j in range(len(patches)):
712
+ patches[j].set_color(bincol[j])
713
+
714
+ # This section draws the black line.
715
+ if np.ma.is_masked(zval) is True:
716
+ return 0
717
+ binnum = (bins < zval).sum()-1
718
+
719
+ if binnum < 0 or binnum >= len(patches):
720
+ return 0
721
+
722
+ patches[binnum].set_color('k')
723
+ self.update_hist_text(self.htxt[hno], zval)
724
+ return binnum
725
+
726
+ def update_hist_sun(self, zval=None):
727
+ """ Updates a sunshade histogram """
728
+ if zval is None:
729
+ zval = [0.0, 0.0]
730
+
731
+ bnum = [None, None]
732
+ bnum[0] = self.update_hist_single(zval[0], 0)
733
+ bnum[1] = self.update_hist_single(zval[1], 1)
734
+ return bnum
735
+
736
+ def update_hist_text(self, hst, zval):
737
+ """ Update the value on the histogram """
738
+ xmin, xmax, ymin, ymax = hst.axes.axis()
739
+ xnew = 0.95*(xmax-xmin)+xmin
740
+ ynew = 0.95*(ymax-ymin)+ymin
741
+ hst.set_position((xnew, ynew))
742
+ hst.set_text(str(zval))
743
+
744
+ def update_rgb(self):
745
+ """ Updates the RGB Ternary Map """
746
+ self.image.dtype = self.gmode
747
+ dat = [None, None, None]
748
+ for i in self.data:
749
+ for j in range(3):
750
+ if i.dataid == self.hband[j]:
751
+ dat[j] = i.data
752
+
753
+ self.image.set_data(dat)
754
+ hdata = self.image.smallres
755
+
756
+ for i in range(3):
757
+ self.hhist[i] = self.argb[i].hist(hdata[:, :, i].compressed(), 50,
758
+ ec='none')
759
+ self.htxt[i] = self.argb[i].text(0., 0., '', ha='right', va='top')
760
+
761
+ self.argb[i].set_xlim(self.hhist[i][1].min(),
762
+ self.hhist[i][1].max())
763
+ self.argb[i].set_ylim(0, self.hhist[i][0].max()*1.2)
764
+
765
+ self.update_hist_rgb([-999, -999, -999])
766
+
767
+ self.figure.canvas.restore_region(self.background)
768
+ self.figure.canvas.restore_region(self.bbox_hist_red)
769
+ self.figure.canvas.restore_region(self.bbox_hist_green)
770
+ self.figure.canvas.restore_region(self.bbox_hist_blue)
771
+
772
+ self.axes.draw_artist(self.image)
773
+
774
+ for j in range(3):
775
+ for i in self.hhist[j][2]:
776
+ self.argb[j].draw_artist(i)
777
+
778
+ self.figure.canvas.update()
779
+
780
+ self.bbox_hist_red = self.figure.canvas.copy_from_bbox(
781
+ self.argb[0].bbox)
782
+ self.bbox_hist_green = self.figure.canvas.copy_from_bbox(
783
+ self.argb[1].bbox)
784
+ self.bbox_hist_blue = self.figure.canvas.copy_from_bbox(
785
+ self.argb[2].bbox)
786
+
787
+ for j in range(3):
788
+ self.argb[j].draw_artist(self.htxt[j])
789
+
790
+ self.figure.canvas.update()
791
+ self.figure.canvas.flush_events()
792
+
793
+ def update_single_color_map(self):
794
+ """ Updates the single color map """
795
+ self.image.dtype = 'Single Color Map'
796
+ for i in self.data:
797
+ if i.dataid == self.hband[0]:
798
+ dat = i.data
799
+
800
+ self.image.set_data(dat)
801
+ dat = self.image.smallres
802
+
803
+ self.hhist[0] = self.argb[0].hist(dat.compressed(), 50, ec='none')
804
+ self.htxt[0] = self.argb[0].text(0.0, 0.0, '', ha='right', va='top')
805
+ self.argb[0].set_xlim(self.hhist[0][1].min(), self.hhist[0][1].max())
806
+ self.argb[0].set_ylim(0, self.hhist[0][0].max()*1.2)
807
+
808
+ self.update_hist_single(0.0)
809
+
810
+ self.figure.canvas.restore_region(self.background)
811
+ self.figure.canvas.restore_region(self.bbox_hist_red)
812
+
813
+ self.axes.draw_artist(self.image)
814
+
815
+ for i in self.hhist[0][2]:
816
+ self.argb[0].draw_artist(i)
817
+
818
+ self.figure.canvas.update()
819
+ self.bbox_hist_red = self.figure.canvas.copy_from_bbox(
820
+ self.argb[0].bbox)
821
+
822
+ self.argb[0].draw_artist(self.htxt[0])
823
+ self.figure.canvas.update()
824
+
825
+ def update_shade_plot(self):
826
+ """ Updates sun shade plot """
827
+ self.image.dtype = 'Sunshade'
828
+ data = [None, None]
829
+
830
+ for i in self.data:
831
+ if i.dataid == self.hband[0]:
832
+ data[0] = i.data
833
+
834
+ for i in self.sdata:
835
+ if i.dataid == self.hband[1]:
836
+ data[1] = i.data
837
+
838
+ self.image.set_data(data)
839
+
840
+ hdata = self.image.smallres
841
+
842
+ for i in range(2):
843
+ self.hhist[i] = self.argb[i].hist(hdata[:, :, i].compressed(), 50,
844
+ ec='none')
845
+ self.htxt[i] = self.argb[i].text(0., 0., '', ha='right', va='top')
846
+ self.argb[i].set_xlim(self.hhist[i][1].min(),
847
+ self.hhist[i][1].max())
848
+ self.argb[i].set_ylim(0, self.hhist[i][0].max()*1.2)
849
+
850
+ zval = [data[0].data.min(), data[1].data.min()]
851
+ self.update_hist_sun(zval)
852
+
853
+ self.figure.canvas.restore_region(self.background)
854
+ self.figure.canvas.restore_region(self.bbox_hist_red)
855
+ self.figure.canvas.restore_region(self.bbox_hist_green)
856
+
857
+ self.axes.draw_artist(self.image)
858
+
859
+ for j in range(2):
860
+ for i in self.hhist[j][2]:
861
+ self.argb[j].draw_artist(i)
862
+
863
+ self.figure.canvas.update()
864
+
865
+ self.bbox_hist_red = self.figure.canvas.copy_from_bbox(
866
+ self.argb[0].bbox)
867
+ self.bbox_hist_green = self.figure.canvas.copy_from_bbox(
868
+ self.argb[1].bbox)
869
+
870
+ for j in range(2):
871
+ self.argb[j].draw_artist(self.htxt[j])
872
+
873
+ self.figure.canvas.update()
874
+ self.figure.canvas.flush_events()
875
+
876
+
877
+ class MySunCanvas(FigureCanvas):
878
+ """
879
+ Canvas for the sunshading tool.
880
+
881
+ Attributes
882
+ ----------
883
+ sun: matplotlib plot instance
884
+ plot of a circle 'o' showing where the sun is
885
+ axes: matplotlib axes instance
886
+ axes on which the sun is drawn
887
+ """
888
+ def __init__(self, parent):
889
+ fig = Figure()
890
+ super(MySunCanvas, self).__init__(fig)
891
+
892
+ self.sun = None
893
+ self.axes = fig.add_subplot(111, polar=True)
894
+
895
+ self.setParent(parent)
896
+ self.setMaximumSize(120, 120)
897
+ self.setMinimumSize(120, 120)
898
+
899
+ def init_graph(self):
900
+ """ Init graph """
901
+ self.axes.clear()
902
+ plt.setp(self.axes.get_xticklabels(), fontsize=8)
903
+ plt.setp(self.axes.get_yticklabels(), visible=False)
904
+
905
+ self.axes.set_autoscaley_on(False)
906
+ self.axes.set_rmax(1.0)
907
+ self.axes.set_rmin(0.0)
908
+
909
+ self.sun, = self.axes.plot(np.pi/4., cos(np.pi/4.), 'o')
910
+ self.figure.canvas.draw()
911
+
912
+
913
+ class PlotInterp(QtGui.QDialog):
914
+ """
915
+ This is the primary class for the raster data interpretation module. The
916
+ main interface is set up from here, as well as monitoring of the mouse
917
+ over the sunshading.
918
+
919
+ The PlotInterp class allows for the display of raster data in a variety of
920
+ modes, as well as the export of that display to GeoTiff format.
921
+
922
+ Attributes
923
+ ----------
924
+ parent : parent
925
+ reference to the parent routine
926
+ indata : dictionary
927
+ dictionary of input datasets
928
+ outdata : dictionary
929
+ dictionary of output datasets
930
+ self.mmc : MyMplCanvas, FigureCanvas
931
+ main canvas containing the image
932
+ self.msc : MySunCanvas, FigureCanvas
933
+ small canvas containing the sunshading control
934
+ """
935
+ def __init__(self, parent=None):
936
+ super(PlotInterp, self).__init__(parent)
937
+ self.indata = {}
938
+ self.outdata = {}
939
+ self.parent = parent
940
+ self.units = {}
941
+
942
+ self.mmc = MyMplCanvas(self)
943
+ self.msc = MySunCanvas(self)
944
+ self.btn_saveimg = QtGui.QPushButton()
945
+ self.cbox_dtype = QtGui.QComboBox()
946
+ self.cbox_band1 = QtGui.QComboBox()
947
+ self.cbox_band2 = QtGui.QComboBox()
948
+ self.cbox_band3 = QtGui.QComboBox()
949
+ self.cbox_htype = QtGui.QComboBox()
950
+ self.cbox_hstype = QtGui.QComboBox()
951
+ self.cbox_cbar = QtGui.QComboBox(self)
952
+ self.kslider = QtGui.QSlider(QtCore.Qt.Horizontal) # cmyK
953
+ self.sslider = QtGui.QSlider(QtCore.Qt.Horizontal) # sunshade
954
+ self.aslider = QtGui.QSlider(QtCore.Qt.Horizontal)
955
+ self.slabel = QtGui.QLabel()
956
+ self.labels = QtGui.QLabel()
957
+ self.labela = QtGui.QLabel()
958
+ self.labelc = QtGui.QLabel()
959
+ self.labelk = QtGui.QLabel()
960
+
961
+ self.setupui()
962
+
963
+ self.change_cbar()
964
+ self.setFocus()
965
+
966
+ self.mmc.gmode = 'Single Color Map'
967
+ self.mmc.argb[0].set_visible(True)
968
+ self.mmc.argb[1].set_visible(False)
969
+ self.mmc.argb[2].set_visible(False)
970
+
971
+ self.slabel.hide()
972
+ self.cbox_hstype.hide()
973
+ self.cbox_band1.show()
974
+ self.cbox_band2.hide()
975
+ self.cbox_band3.hide()
976
+ self.sslider.hide()
977
+ self.aslider.hide()
978
+ self.kslider.hide()
979
+ self.msc.hide()
980
+ self.labela.hide()
981
+ self.labels.hide()
982
+ self.labelk.hide()
983
+
984
+ def setupui(self):
985
+ """ Setup UI """
986
+ helpdocs = menu_default.HelpButton('pygmi.raster.ginterp')
987
+ label1 = QtGui.QLabel()
988
+ label2 = QtGui.QLabel()
989
+ label3 = QtGui.QLabel()
990
+
991
+ vbl_raster = QtGui.QVBoxLayout()
992
+ hbl_all = QtGui.QHBoxLayout(self)
993
+ vbl_right = QtGui.QVBoxLayout()
994
+
995
+ mpl_toolbar = NavigationToolbar(self.mmc, self)
996
+ spacer = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum,
997
+ QtGui.QSizePolicy.Expanding)
998
+ self.sslider.setMinimum(1)
999
+ self.sslider.setMaximum(100)
1000
+ self.sslider.setValue(25)
1001
+ self.aslider.setMinimum(1)
1002
+ self.aslider.setMaximum(100)
1003
+ self.aslider.setSingleStep(1)
1004
+ self.aslider.setValue(75)
1005
+ self.kslider.setMinimum(1)
1006
+ self.kslider.setMaximum(100)
1007
+ self.kslider.setValue(1)
1008
+ tmp = sorted(cm.datad.keys())
1009
+ self.cbox_cbar.addItem('jet')
1010
+ self.cbox_cbar.addItems(tmp)
1011
+ self.cbox_dtype.addItems(['Single Color Map', 'Contour', 'RGB Ternary',
1012
+ 'CMY Ternary', 'Sunshade'])
1013
+ self.cbox_htype.addItems(['Linear', '95% Linear, 5% Compact',
1014
+ 'Histogram Equalization'])
1015
+ self.cbox_hstype.addItems(['Linear', '95% Linear, 5% Compact',
1016
+ 'Histogram Equalization'])
1017
+
1018
+ self.setWindowTitle("Raster Data Interpretation")
1019
+ label1.setText('Display Type:')
1020
+ label2.setText('Data Bands:')
1021
+ label3.setText('Histogram Stretch:')
1022
+ self.slabel.setText('Sunshade Stretch:')
1023
+ self.labelc.setText('Color Bar:')
1024
+ self.labelk.setText('K value:')
1025
+ self.labels.setText('Sunshade Detail')
1026
+ self.labela.setText('Light Reflectance')
1027
+ self.btn_saveimg.setText('Save GeoTiff')
1028
+
1029
+ vbl_raster.addWidget(label1)
1030
+ vbl_raster.addWidget(self.cbox_dtype)
1031
+ vbl_raster.addWidget(label2)
1032
+ vbl_raster.addWidget(self.cbox_band1)
1033
+ vbl_raster.addWidget(self.cbox_band2)
1034
+ vbl_raster.addWidget(self.cbox_band3)
1035
+ vbl_raster.addWidget(label3)
1036
+ vbl_raster.addWidget(self.cbox_htype)
1037
+ vbl_raster.addWidget(self.slabel)
1038
+ vbl_raster.addWidget(self.cbox_hstype)
1039
+ vbl_raster.addWidget(self.labelc)
1040
+ vbl_raster.addWidget(self.cbox_cbar)
1041
+ vbl_raster.addWidget(self.msc)
1042
+ vbl_raster.addWidget(self.labels)
1043
+ vbl_raster.addWidget(self.sslider)
1044
+ vbl_raster.addWidget(self.labela)
1045
+ vbl_raster.addWidget(self.aslider)
1046
+ vbl_raster.addWidget(self.labelk)
1047
+ vbl_raster.addWidget(self.kslider)
1048
+ vbl_raster.addItem(spacer)
1049
+ vbl_raster.addWidget(self.btn_saveimg)
1050
+ vbl_raster.addWidget(helpdocs)
1051
+ vbl_right.addWidget(self.mmc)
1052
+ vbl_right.addWidget(mpl_toolbar)
1053
+
1054
+ hbl_all.addLayout(vbl_raster)
1055
+ hbl_all.addLayout(vbl_right)
1056
+
1057
+ self.cbox_cbar.currentIndexChanged.connect(self.change_cbar)
1058
+ self.cbox_dtype.currentIndexChanged.connect(self.change_dtype)
1059
+ self.cbox_htype.currentIndexChanged.connect(self.change_htype)
1060
+ self.cbox_hstype.currentIndexChanged.connect(self.change_hstype)
1061
+
1062
+ self.sslider.sliderReleased.connect(self.change_dtype)
1063
+ self.aslider.sliderReleased.connect(self.change_dtype)
1064
+ self.kslider.sliderReleased.connect(self.change_dtype)
1065
+ self.msc.figure.canvas.mpl_connect('button_press_event', self.move)
1066
+ self.btn_saveimg.clicked.connect(self.save_img)
1067
+
1068
+ def change_blue(self):
1069
+ """ Combo box to change the blue or third display band"""
1070
+ txt = str(self.cbox_band3.currentText())
1071
+ self.mmc.hband[2] = txt
1072
+ self.mmc.init_graph()
1073
+
1074
+ def change_cbar(self):
1075
+ """ Change the color map for the color bar """
1076
+ txt = str(self.cbox_cbar.currentText())
1077
+ self.mmc.cbar = plt.get_cmap(txt)
1078
+ self.mmc.update_graph()
1079
+
1080
+ def change_dtype(self):
1081
+ """ Combo box to change display type """
1082
+ txt = str(self.cbox_dtype.currentText())
1083
+ self.mmc.gmode = txt
1084
+ self.cbox_band1.show()
1085
+
1086
+ if txt == 'Single Color Map':
1087
+ self.slabel.hide()
1088
+ self.labelc.show()
1089
+ self.labelk.hide()
1090
+ self.cbox_hstype.hide()
1091
+ self.cbox_band2.hide()
1092
+ self.cbox_band3.hide()
1093
+ self.cbox_cbar.show()
1094
+ self.mmc.argb[0].set_visible(True)
1095
+ self.mmc.argb[1].set_visible(False)
1096
+ self.mmc.argb[2].set_visible(False)
1097
+ self.sslider.hide()
1098
+ self.aslider.hide()
1099
+ self.kslider.hide()
1100
+ self.msc.hide()
1101
+ self.labela.hide()
1102
+ self.labels.hide()
1103
+ self.mmc.init_graph()
1104
+
1105
+ if txt == 'Contour':
1106
+ self.labelk.hide()
1107
+ self.slabel.hide()
1108
+ self.labelc.show()
1109
+ self.cbox_hstype.hide()
1110
+ self.cbox_band2.hide()
1111
+ self.cbox_band3.hide()
1112
+ self.cbox_cbar.show()
1113
+ self.mmc.argb[0].set_visible(False)
1114
+ self.mmc.argb[1].set_visible(False)
1115
+ self.mmc.argb[2].set_visible(False)
1116
+ self.sslider.hide()
1117
+ self.aslider.hide()
1118
+ self.kslider.hide()
1119
+ self.msc.hide()
1120
+ self.labela.hide()
1121
+ self.labels.hide()
1122
+ self.mmc.init_graph()
1123
+
1124
+ if 'Ternary' in txt:
1125
+ self.labelk.hide()
1126
+ self.slabel.hide()
1127
+ self.labelc.hide()
1128
+ self.cbox_hstype.hide()
1129
+ self.cbox_band2.show()
1130
+ self.cbox_band3.show()
1131
+ self.cbox_cbar.hide()
1132
+ self.mmc.argb[0].set_visible(True)
1133
+ self.mmc.argb[1].set_visible(True)
1134
+ self.mmc.argb[2].set_visible(True)
1135
+ self.sslider.hide()
1136
+ self.aslider.hide()
1137
+ self.kslider.hide()
1138
+ if 'CMY' in txt:
1139
+ self.kslider.show()
1140
+ self.labelk.show()
1141
+ self.mmc.kval = float(self.kslider.value())/100.
1142
+ self.msc.hide()
1143
+ self.labela.hide()
1144
+ self.labels.hide()
1145
+ self.mmc.init_graph()
1146
+
1147
+ if txt == 'Sunshade':
1148
+ self.labelc.show()
1149
+ self.labelk.hide()
1150
+ self.msc.show()
1151
+ self.sslider.show()
1152
+ self.aslider.show()
1153
+ self.kslider.hide()
1154
+ self.labela.show()
1155
+ self.labels.show()
1156
+ self.slabel.show()
1157
+ self.cbox_hstype.show()
1158
+ self.cbox_band2.show()
1159
+ self.cbox_band3.hide()
1160
+ self.cbox_cbar.show()
1161
+ self.mmc.argb[0].set_visible(True)
1162
+ self.mmc.argb[1].set_visible(True)
1163
+ self.mmc.argb[2].set_visible(False)
1164
+ self.mmc.cell = self.sslider.value()
1165
+ self.mmc.alpha = float(self.aslider.value())/100.
1166
+ QtGui.QApplication.processEvents()
1167
+ self.msc.init_graph()
1168
+ self.mmc.init_graph()
1169
+
1170
+ def change_green(self):
1171
+ """ Combo box to change the greed or second band"""
1172
+ txt = str(self.cbox_band2.currentText())
1173
+ self.mmc.hband[1] = txt
1174
+ self.mmc.init_graph()
1175
+
1176
+ def change_hstype(self):
1177
+ """Change the histogram stretch to apply to the sun shaded data"""
1178
+ txt = str(self.cbox_hstype.currentText())
1179
+ self.mmc.hstype = txt
1180
+ self.mmc.init_graph()
1181
+
1182
+ def change_htype(self):
1183
+ """Change the histogram stretch to apply to the normal data"""
1184
+ txt = str(self.cbox_htype.currentText())
1185
+ self.mmc.htype = txt
1186
+ self.mmc.init_graph()
1187
+
1188
+ def change_red(self):
1189
+ """ Combo box to change the red or first band"""
1190
+ txt = str(self.cbox_band1.currentText())
1191
+ self.mmc.hband[0] = txt
1192
+ self.mmc.init_graph()
1193
+
1194
+ def data_init(self):
1195
+ """ data init - entry point into routine. This entry point exists for
1196
+ the case where data must be initialised before entering at the
1197
+ standard 'settings' sub module."""
1198
+
1199
+ if 'Raster' not in self.indata:
1200
+ return
1201
+
1202
+ if 'Cluster' in self.indata:
1203
+ self.indata = copy.deepcopy(self.indata)
1204
+ self.indata = dataprep.cluster_to_raster(self.indata)
1205
+ self.indata['Raster'] = dataprep.merge(self.indata['Raster'])
1206
+
1207
+ data = self.indata['Raster']
1208
+ sdata = self.indata['Raster']
1209
+
1210
+ for i in data:
1211
+ self.units[i.dataid] = i.units
1212
+
1213
+ self.mmc.data = data
1214
+ self.mmc.sdata = sdata
1215
+ self.mmc.hband[0] = data[0].dataid
1216
+ self.mmc.hband[1] = data[0].dataid
1217
+ self.mmc.hband[2] = data[0].dataid
1218
+
1219
+ blist = []
1220
+ for i in data:
1221
+ blist.append(i.dataid)
1222
+
1223
+ try:
1224
+ self.cbox_band1.currentIndexChanged.disconnect()
1225
+ self.cbox_band2.currentIndexChanged.disconnect()
1226
+ self.cbox_band3.currentIndexChanged.disconnect()
1227
+ except TypeError:
1228
+ pass
1229
+
1230
+ self.cbox_band1.clear()
1231
+ self.cbox_band2.clear()
1232
+ self.cbox_band3.clear()
1233
+ self.cbox_band1.addItems(blist)
1234
+ self.cbox_band2.addItems(blist)
1235
+ self.cbox_band3.addItems(blist)
1236
+
1237
+ self.cbox_band1.currentIndexChanged.connect(self.change_red)
1238
+ self.cbox_band2.currentIndexChanged.connect(self.change_green)
1239
+ self.cbox_band3.currentIndexChanged.connect(self.change_blue)
1240
+
1241
+ def move(self, event):
1242
+ """
1243
+ Move event is used to track changes to the sunshading.
1244
+
1245
+ Parameters
1246
+ ----------
1247
+ event - matplotlib button press event
1248
+ event returned by matplotlib when a button is pressed
1249
+ """
1250
+ if event.inaxes == self.msc.axes:
1251
+ self.msc.sun.set_xdata(event.xdata)
1252
+ self.msc.sun.set_ydata(event.ydata)
1253
+ self.msc.figure.canvas.draw()
1254
+
1255
+ phi = -event.xdata
1256
+ theta = np.pi/2. - np.arccos(event.ydata)
1257
+ self.mmc.phi = phi
1258
+ self.mmc.theta = theta
1259
+ self.mmc.update_graph()
1260
+
1261
+ def save_img(self):
1262
+ """Save image as a GeoTiff"""
1263
+
1264
+ ext = "GeoTiff (*.tif)"
1265
+ filename = QtGui.QFileDialog.getSaveFileName(
1266
+ self.parent, 'Save File', '.', ext)
1267
+ if filename == '':
1268
+ return False
1269
+
1270
+ text, okay = QtGui.QInputDialog.getText(
1271
+ self, "Colorbar", "Enter length in inches:",
1272
+ QtGui.QLineEdit.Normal, "8")
1273
+
1274
+ if not okay:
1275
+ return
1276
+
1277
+ blen = float(text)
1278
+ bwid = blen/16.
1279
+
1280
+ dtype = str(self.cbox_dtype.currentText())
1281
+
1282
+ if 'Ternary' not in dtype:
1283
+ text, okay = QtGui.QInputDialog.getText(
1284
+ self, "Colorbar", "Enter colorbar unit label:",
1285
+ QtGui.QLineEdit.Normal,
1286
+ self.units[str(self.cbox_band1.currentText())])
1287
+
1288
+ if not okay:
1289
+ return
1290
+ else:
1291
+ units = str(self.cbox_band1.currentText())
1292
+ rtext, okay = QtGui.QInputDialog.getText(
1293
+ self, "Ternary Colorbar", "Enter red/cyan label:",
1294
+ QtGui.QLineEdit.Normal, units)
1295
+
1296
+ if not okay:
1297
+ return
1298
+
1299
+ units = str(self.cbox_band2.currentText())
1300
+ gtext, okay = QtGui.QInputDialog.getText(
1301
+ self, "Ternary Colorbar", "Enter green/magenta label:",
1302
+ QtGui.QLineEdit.Normal, units)
1303
+
1304
+ if not okay:
1305
+ return
1306
+
1307
+ units = str(self.cbox_band3.currentText())
1308
+ btext, okay = QtGui.QInputDialog.getText(
1309
+ self, "Ternary Colorbar", "Enter blue/yelow label:",
1310
+ QtGui.QLineEdit.Normal, units)
1311
+
1312
+ if not okay:
1313
+ return
1314
+
1315
+ img = self.mmc.image.get_array()
1316
+ htype = str(self.cbox_htype.currentText())
1317
+ hstype = str(self.cbox_hstype.currentText())
1318
+ cell = self.mmc.cell
1319
+ alpha = self.mmc.alpha
1320
+ phi = self.mmc.phi
1321
+ theta = self.mmc.theta
1322
+
1323
+ if dtype == 'Single Color Map':
1324
+ pseudo = self.mmc.image._full_res.copy()
1325
+ psmall = self.mmc.image.smallres
1326
+ pmask = pseudo.mask.copy()
1327
+
1328
+ pseudo[pseudo < psmall.min()] = psmall.min()
1329
+ pseudo[pseudo > psmall.max()] = psmall.max()
1330
+ pseudo.mask = pmask
1331
+
1332
+ # mask = np.logical_not(pseudo.mask)
1333
+ # pseudo += pseudo.min()
1334
+
1335
+ if htype == '95% Linear, 5% Compact':
1336
+ pseudo = histcomp(pseudo)
1337
+
1338
+ if htype == 'Histogram Equalization':
1339
+ pseudo = histeq(pseudo)
1340
+
1341
+ cmin = pseudo.min()
1342
+ cmax = pseudo.max()
1343
+
1344
+ # The function below normalizes as well.
1345
+ img = img2rgb(pseudo, self.mmc.cbar)
1346
+
1347
+ pseudo = None
1348
+
1349
+ elif dtype == 'Sunshade':
1350
+ # pseudo = self.mmc.image._full_res[0]
1351
+ # sun = self.mmc.image._full_res[1]
1352
+ pseudo = self.mmc.image.smallres[:, :, 0]
1353
+ sun = self.mmc.image.smallres[:, :, 1]
1354
+
1355
+ if htype == '95% Linear, 5% Compact':
1356
+ pseudo = histcomp(pseudo)
1357
+
1358
+ if htype == 'Histogram Equalization':
1359
+ pseudo = histeq(pseudo)
1360
+
1361
+ if hstype == '95% Linear, 5% Compact':
1362
+ sun = histcomp(sun)
1363
+
1364
+ if hstype == 'Histogram Equalization':
1365
+ sun = histeq(sun)
1366
+
1367
+ cmin = pseudo.min()
1368
+ cmax = pseudo.max()
1369
+
1370
+ sunshader = currentshader(sun.data, cell, theta, phi, alpha)
1371
+ snorm = norm2(sunshader)
1372
+
1373
+ # pnorm = norm2(pseudo)
1374
+ # colormap = self.cbar(pnorm)
1375
+
1376
+
1377
+ img = img2rgb(pseudo, self.mmc.cbar)
1378
+ pseudo = None
1379
+ sunshader = None
1380
+
1381
+ img[:, :, 0] = img[:, :, 0]*snorm # red
1382
+ img[:, :, 1] = img[:, :, 1]*snorm # green
1383
+ img[:, :, 2] = img[:, :, 2]*snorm # blue
1384
+ img = img.astype(np.uint8)
1385
+ # mask = np.logical_or(pseudo.mask, sun.mask)
1386
+ # mask = np.logical_not(mask)
1387
+ # img[:, :, 3] = mask
1388
+
1389
+ elif 'Ternary' in dtype:
1390
+ red = self.mmc.image._full_res[0]
1391
+ green = self.mmc.image._full_res[1]
1392
+ blue = self.mmc.image._full_res[2]
1393
+ mask = np.logical_or(red.mask, green.mask)
1394
+ mask = np.logical_or(mask, blue.mask)
1395
+ mask = np.logical_not(mask)
1396
+
1397
+ if htype == '95% Linear, 5% Compact':
1398
+ red = histcomp(red)
1399
+ green = histcomp(green)
1400
+ blue = histcomp(blue)
1401
+
1402
+ if htype == 'Histogram Equalization':
1403
+ red = histeq(red)
1404
+ green = histeq(green)
1405
+ blue = histeq(blue)
1406
+
1407
+ cmin = red.min()
1408
+ cmax = red.max()
1409
+
1410
+ colormap = np.ones((red.shape[0], red.shape[1], 4), dtype=np.uint8)
1411
+ colormap[:, :, 3] = mask*254+1
1412
+
1413
+ if 'CMY' in dtype:
1414
+ colormap[:, :, 0] = (1-norm2(red))*254+1
1415
+ colormap[:, :, 1] = (1-norm2(green))*254+1
1416
+ colormap[:, :, 2] = (1-norm2(blue))*254+1
1417
+ else:
1418
+ colormap[:, :, 0] = norm255(red)
1419
+ colormap[:, :, 1] = norm255(green)
1420
+ colormap[:, :, 2] = norm255(blue)
1421
+
1422
+ img = colormap
1423
+
1424
+ elif dtype == 'Contour':
1425
+ pseudo = self.mmc.image._full_res.copy()
1426
+ psmall = self.mmc.image.smallres
1427
+ pmask = pseudo.mask.copy()
1428
+
1429
+ pseudo[pseudo < psmall.min()] = psmall.min()
1430
+ pseudo[pseudo > psmall.max()] = psmall.max()
1431
+ pseudo.mask = pmask
1432
+
1433
+ if htype == '95% Linear, 5% Compact':
1434
+ pseudo = histcomp(pseudo)
1435
+
1436
+ if htype == 'Histogram Equalization':
1437
+ pseudo = histeq(pseudo)
1438
+
1439
+ cmin = pseudo.min()
1440
+ cmax = pseudo.max()
1441
+
1442
+ self.mmc.figure.set_frameon(False)
1443
+ self.mmc.axes.set_axis_off()
1444
+ tmpsize = self.mmc.figure.get_size_inches()
1445
+ self.mmc.figure.set_size_inches(tmpsize*3)
1446
+ self.mmc.figure.canvas.draw()
1447
+ # fcol = int(self.mmc.figure.get_facecolor()[0]*255)
1448
+ img = np.fromstring(self.mmc.figure.canvas.tostring_argb(),
1449
+ dtype=np.uint8, sep='')
1450
+ w, h = self.mmc.figure.canvas.get_width_height()
1451
+
1452
+ self.mmc.figure.set_size_inches(tmpsize)
1453
+ self.mmc.figure.set_frameon(True)
1454
+ self.mmc.axes.set_axis_on()
1455
+ self.mmc.figure.canvas.draw()
1456
+
1457
+ img.shape = (h, w, 4)
1458
+ img = np.roll(img, 3, axis=2)
1459
+
1460
+ cmask = np.ones(img.shape[1], dtype=bool)
1461
+ for i in range(img.shape[1]):
1462
+ if img[:, i, 3].mean() == 0:
1463
+ cmask[i] = False
1464
+ img = img[:, cmask]
1465
+ rmask = np.ones(img.shape[0], dtype=bool)
1466
+ for i in range(img.shape[0]):
1467
+ if img[i, :, 3].mean() == 0:
1468
+ rmask[i] = False
1469
+ img = img[rmask]
1470
+
1471
+ mask = img[:, :, 3]
1472
+
1473
+ export = iodefs.ExportData(self.parent)
1474
+
1475
+ os.chdir(filename.rpartition('/')[0])
1476
+
1477
+ newimg = [copy.deepcopy(self.mmc.data[0]),
1478
+ copy.deepcopy(self.mmc.data[0]),
1479
+ copy.deepcopy(self.mmc.data[0]),
1480
+ copy.deepcopy(self.mmc.data[0])]
1481
+
1482
+ newimg[0].data = img[:, :, 0]
1483
+ newimg[1].data = img[:, :, 1]
1484
+ newimg[2].data = img[:, :, 2]
1485
+ newimg[3].data = img[:, :, 3]
1486
+
1487
+ mask = img[:, :, 3]
1488
+ newimg[0].data[mask <= 1] = 0
1489
+ newimg[1].data[mask <= 1] = 0
1490
+ newimg[2].data[mask <= 1] = 0
1491
+ # newimg[3].data[mask == 0] = 0
1492
+
1493
+ newimg[0].nullvalue = 0
1494
+ newimg[1].nullvalue = 0
1495
+ newimg[2].nullvalue = 0
1496
+ newimg[3].nullvalue = 0
1497
+
1498
+ imgshape0 = img.shape[0]
1499
+ imgshape1 = img.shape[1]
1500
+
1501
+ newimg[0].xdim = (newimg[0].xdim*newimg[0].cols)/imgshape1
1502
+ newimg[1].xdim = (newimg[1].xdim*newimg[1].cols)/imgshape1
1503
+ newimg[2].xdim = (newimg[2].xdim*newimg[2].cols)/imgshape1
1504
+ newimg[3].xdim = (newimg[3].xdim*newimg[3].cols)/imgshape1
1505
+
1506
+ newimg[0].ydim = (newimg[0].ydim*newimg[0].rows)/imgshape0
1507
+ newimg[1].ydim = (newimg[1].ydim*newimg[1].rows)/imgshape0
1508
+ newimg[2].ydim = (newimg[2].ydim*newimg[2].rows)/imgshape0
1509
+ newimg[3].ydim = (newimg[3].ydim*newimg[3].rows)/imgshape0
1510
+
1511
+
1512
+ newimg[0].cols = imgshape1
1513
+ newimg[1].cols = imgshape1
1514
+ newimg[2].cols = imgshape1
1515
+ newimg[3].cols = imgshape1
1516
+
1517
+ newimg[0].rows = imgshape0
1518
+ newimg[1].rows = imgshape0
1519
+ newimg[2].rows = imgshape0
1520
+ newimg[3].rows = imgshape0
1521
+
1522
+ export.ifile = str(filename)
1523
+ export.ext = filename[-3:]
1524
+ export.export_gdal(newimg, 'GTiff')
1525
+
1526
+ # Section for colorbars
1527
+ if 'Ternary' not in dtype:
1528
+ txt = str(self.cbox_cbar.currentText())
1529
+ cmap = plt.get_cmap(txt)
1530
+ norm = mcolors.Normalize(vmin=cmin, vmax=cmax)
1531
+
1532
+ # Horizontal Bar
1533
+ fig = plt.figure(figsize=(blen, (bwid+0.75)), tight_layout=True)
1534
+ ax = fig.add_subplot(111)
1535
+
1536
+ cb = mcolorbar.ColorbarBase(ax, cmap=cmap, norm=norm,
1537
+ orientation='horizontal')
1538
+ cb.set_label(text)
1539
+
1540
+ fname = filename[:-4]+'_hcbar.tif'
1541
+ fig.savefig(fname, dpi=300)
1542
+
1543
+ # Vertical Bar
1544
+ fig = plt.figure(figsize=((bwid + 1), blen), tight_layout=True)
1545
+ ax = fig.add_subplot(111)
1546
+
1547
+ cb = mcolorbar.ColorbarBase(ax, cmap=cmap, norm=norm,
1548
+ orientation='vertical')
1549
+ cb.set_label(text)
1550
+
1551
+ fname = filename[:-4]+'_vcbar.tif'
1552
+ fig.savefig(fname, dpi=300)
1553
+ else:
1554
+ fig = plt.figure(tight_layout=True)
1555
+
1556
+ redlabel = rtext
1557
+ greenlabel = gtext
1558
+ bluelabel = btext
1559
+
1560
+ tmp = np.array([[list(range(255))]*255])
1561
+ tmp.shape = (255, 255)
1562
+ tmp = tmp.T
1563
+
1564
+ red = ndimage.rotate(tmp, 0)
1565
+ green = ndimage.rotate(tmp, 120)
1566
+ blue = ndimage.rotate(tmp, -120)
1567
+
1568
+ tmp = np.zeros((blue.shape[0], 90))
1569
+ blue = np.hstack((tmp, blue))
1570
+ green = np.hstack((green, tmp))
1571
+
1572
+ rtmp = np.zeros_like(blue)
1573
+ j = 92
1574
+ rtmp[:255, j:j+255] = red
1575
+ red = rtmp
1576
+
1577
+ if 'CMY' in dtype:
1578
+ red = red.max()-red
1579
+ green = green.max()-green
1580
+ blue = blue.max()-blue
1581
+
1582
+ data = np.transpose([red.flatten(), green.flatten(),
1583
+ blue.flatten()])
1584
+ data.shape = (red.shape[0], red.shape[1], 3)
1585
+
1586
+ data = data[:221, 90:350]
1587
+ plt.xlim((-100, 355))
1588
+ plt.ylim((-100, 322))
1589
+
1590
+ path = Path([[0, 0], [127.5, 222], [254, 0], [0, 0]])
1591
+ patch = PathPatch(path, facecolor='none')
1592
+ plt.gca().add_patch(patch)
1593
+
1594
+ im = plt.imshow(data, extent=(0, 255, 0, 222), clip_path=patch,
1595
+ clip_on=True)
1596
+ im.set_clip_path(patch)
1597
+
1598
+ plt.text(0, -5, greenlabel, horizontalalignment='center',
1599
+ verticalalignment='top', size=20)
1600
+ plt.text(254, -5, bluelabel, horizontalalignment='center',
1601
+ verticalalignment='top', size=20)
1602
+ plt.text(127.5, 225, redlabel, horizontalalignment='center',
1603
+ size=20)
1604
+ plt.tick_params(top='off', right='off', bottom='off', left='off',
1605
+ labelbottom='off', labelleft='off')
1606
+
1607
+ plt.axis('off')
1608
+ fname = filename[:-4]+'_tern.tif'
1609
+ fig.savefig(fname, dpi=300)
1610
+
1611
+ QtGui.QMessageBox.information(self, "Information",
1612
+ "Save to GeoTiff is complete!",
1613
+ QtGui.QMessageBox.Ok,
1614
+ QtGui.QMessageBox.Ok)
1615
+
1616
+ def settings(self):
1617
+ """ This is called when the used double clicks the routine from the
1618
+ main PyGMI interface"""
1619
+ self.show()
1620
+ QtGui.QApplication.processEvents()
1621
+
1622
+ self.mmc.init_graph()
1623
+ self.msc.init_graph()
1624
+ return True
1625
+
1626
+
1627
+ def aspect2(data):
1628
+ """
1629
+ Aspect of a dataset
1630
+
1631
+ Parameters
1632
+ ----------
1633
+ data : numpy MxN array
1634
+ input data used for the aspect calculation
1635
+
1636
+ Returns
1637
+ -------
1638
+ adeg : numpy masked array
1639
+ aspect in degrees
1640
+ dzdx : numpy array
1641
+ gradient in x direction
1642
+ dzdy : numpy array
1643
+ gradient in y direction
1644
+ """
1645
+ cdy = np.array([[1., 2., 1.], [0., 0., 0.], [-1., -2., -1.]])
1646
+ cdx = np.array([[1., 0., -1.], [2., 0., -2.], [1., 0., -1.]])
1647
+
1648
+ dzdx = ndimage.convolve(data, cdx) # Use convolve: matrix filtering
1649
+ dzdy = ndimage.convolve(data, cdy) # 'valid' gets reduced array
1650
+
1651
+ dzdx = ne.evaluate('dzdx/8.')
1652
+ dzdy = ne.evaluate('dzdy/8.')
1653
+
1654
+ # Aspect Section
1655
+ pi = np.pi
1656
+ adeg = ne.evaluate('90-arctan2(dzdy, -dzdx)*180./pi')
1657
+ adeg = np.ma.masked_invalid(adeg)
1658
+ adeg[np.ma.less(adeg, 0.)] += 360.
1659
+ adeg[np.logical_and(dzdx == 0, dzdy == 0)] = -1.
1660
+
1661
+ return [adeg, dzdx, dzdy]
1662
+
1663
+
1664
+ def currentshader(data, cell, theta, phi, alpha):
1665
+ """
1666
+ Blinn shader - used for sun shading.
1667
+
1668
+ Parameters
1669
+ ----------
1670
+ phi : float
1671
+ azimuth
1672
+ theta : float
1673
+ sun elevation (also called g in code below)
1674
+ cell : float
1675
+ between 1 and 100 - controls sunshade detail.
1676
+ alpha : float
1677
+ how much incident light is reflected (0 to 1)
1678
+
1679
+ Returns
1680
+ -------
1681
+ R : numpy array
1682
+ array containg the shaded results
1683
+ """
1684
+ asp = aspect2(data)
1685
+ n = 2
1686
+ pinit = asp[1]
1687
+ qinit = asp[2]
1688
+ p = ne.evaluate('pinit/cell')
1689
+ q = ne.evaluate('qinit/cell')
1690
+ sqrt_1p2q2 = ne.evaluate('sqrt(1+p**2+q**2)')
1691
+
1692
+ cosg2 = cos(theta/2)
1693
+ p0 = -cos(phi)*tan(theta)
1694
+ q0 = -sin(phi)*tan(theta)
1695
+ sqrttmp = ne.evaluate('(1+sqrt(1+p0**2+q0**2))')
1696
+ p1 = ne.evaluate('p0 / sqrttmp')
1697
+ q1 = ne.evaluate('q0 / sqrttmp')
1698
+
1699
+ cosi = ne.evaluate('((1+p0*p+q0*q)/(sqrt_1p2q2*sqrt(1+p0**2+q0**2)))')
1700
+ coss = ne.evaluate('((1+p1*p+q1*q)/(sqrt_1p2q2*sqrt(1+p1**2+q1**2)))')
1701
+ Ps = ne.evaluate('coss**n')
1702
+ R = np.ma.masked_invalid(ne.evaluate('((1-alpha)+alpha*Ps)*cosi/cosg2'))
1703
+
1704
+
1705
+ # ldict = locals()
1706
+ # ldict['pinit'] = asp[1]
1707
+ # ldict['qinit'] = asp[2]
1708
+
1709
+ # Update cell
1710
+ # ldict['p'] = ne.evaluate('pinit/cell', ldict)
1711
+ # ldict['q'] = ne.evaluate('qinit/cell', ldict)
1712
+ # ldict['sqrt_1p2q2'] = ne.evaluate('sqrt(1+p**2+q**2)', ldict)
1713
+
1714
+ # Update angle
1715
+ # ldict['cosg2'] = cos(theta/2)
1716
+ # ldict['p0'] = -cos(phi)*tan(theta)
1717
+ # ldict['q0'] = -sin(phi)*tan(theta)
1718
+ # ldict['sqrttmp'] = ne.evaluate('(1+sqrt(1+p0**2+q0**2))', ldict)
1719
+ # ldict['p1'] = ne.evaluate('p0 / sqrttmp', ldict)
1720
+ # ldict['q1'] = ne.evaluate('q0 / sqrttmp', ldict)
1721
+
1722
+
1723
+ # n: how compact the bright patch is
1724
+ # ldict['cosi'] = ne.evaluate('((1+p0*p+q0*q)/'
1725
+ # '(sqrt_1p2q2*sqrt(1+p0**2+q0**2)))', ldict)
1726
+ # ldict['coss'] = ne.evaluate('((1+p1*p+q1*q)/'
1727
+ # '(sqrt_1p2q2*sqrt(1+p1**2+q1**2)))', ldict)
1728
+ # ldict['Ps'] = ne.evaluate('coss**n', ldict)
1729
+ # R = np.ma.masked_invalid(ne.evaluate('((1-alpha)+alpha*Ps)*cosi/cosg2',
1730
+ # ldict))
1731
+
1732
+ return R
1733
+
1734
+
1735
+ def histcomp(img, nbr_bins=256):
1736
+ """
1737
+ Histogram Compaction - this eliminates 5% of the outliers in data, allowing
1738
+ for a cleaner, linear, representation of the data.
1739
+
1740
+ Parameters
1741
+ ----------
1742
+ img : numpy array
1743
+ data to compact
1744
+ nbr_bins : int
1745
+ number of bins to use in compaction
1746
+
1747
+ Returns
1748
+ -------
1749
+ img2 : numpy array
1750
+ compacted array
1751
+ """
1752
+ # get image histogram
1753
+ imask = img.mask
1754
+ tmp = img.compressed()
1755
+ # if tmp.mask.size > 1:
1756
+ # tmp = tmp.data[tmp.mask == 0]
1757
+ imhist, bins = np.histogram(tmp, nbr_bins)
1758
+
1759
+ cdf = imhist.cumsum() # cumulative distribution function
1760
+ cdf = cdf / float(cdf[-1]) # normalize
1761
+
1762
+ perc = 5
1763
+ perc = perc/100.
1764
+
1765
+ # pdb.set_trace()
1766
+
1767
+ sindx = np.arange(nbr_bins)[cdf > perc][0]
1768
+ if cdf[0] > (1-perc):
1769
+ eindx = 1
1770
+ else:
1771
+ eindx = np.arange(nbr_bins)[cdf < (1-perc)][-1]+1
1772
+ svalue = bins[sindx]
1773
+ evalue = bins[eindx]
1774
+
1775
+ scnt = perc*(nbr_bins-1)
1776
+ if scnt > sindx:
1777
+ scnt = sindx
1778
+
1779
+ ecnt = perc*(nbr_bins-1)
1780
+ if ecnt > ((nbr_bins-1)-eindx):
1781
+ ecnt = (nbr_bins-1)-eindx
1782
+
1783
+ img2 = np.empty_like(img, dtype=np.float32)
1784
+ np.copyto(img2, img)
1785
+
1786
+ filt = np.ma.less(img2, svalue)
1787
+ img2[filt] = svalue
1788
+
1789
+ filt = np.ma.greater(img2, evalue)
1790
+ img2[filt] = evalue
1791
+
1792
+ img2 = np.ma.array(img2, mask=imask)
1793
+ # use linear interpolation of cdf to find new pixel values
1794
+ return img2
1795
+
1796
+
1797
+ def histeq(img, nbr_bins=32768):
1798
+ """
1799
+ Histogram Equalization - equalizes the histogram to colors. This allows for
1800
+ seeing as much data as possible in the image, at the expense of knowing the
1801
+ real value of the data at a point. It bins the data equally - flattening
1802
+ the distribution.
1803
+
1804
+ Parameters
1805
+ ----------
1806
+ img : numpy array
1807
+ input data to be equalised
1808
+ nbr_bins : integer
1809
+ number of bins to be used in the calculation
1810
+
1811
+ Returns
1812
+ -------
1813
+ im2 : numpy array
1814
+ output data
1815
+ """
1816
+ # get image histogram
1817
+ imhist, bins = np.histogram(img.compressed(), nbr_bins)
1818
+ bins = (bins[1:]-bins[:-1])/2+bins[:-1]
1819
+
1820
+ cdf = imhist.cumsum() # cumulative distribution function
1821
+ cdf = cdf - cdf[0] # subtract min, which is first val in cdf
1822
+ cdf = cdf.astype(np.int64)
1823
+ cdf = nbr_bins * cdf / cdf[-1] # norm to nbr_bins
1824
+
1825
+ # use linear interpolation of cdf to find new pixel values
1826
+ im2 = np.interp(img, bins, cdf)
1827
+ im2 = np.ma.array(im2, mask=img.mask)
1828
+
1829
+ return im2
1830
+
1831
+
1832
+ def img2rgb(img, cbar):
1833
+ """
1834
+ convert image to 4 channel rgba color image
1835
+
1836
+ Parameters
1837
+ ----------
1838
+ img : numpy array
1839
+ array to be converted to rgba image.
1840
+ cbar : matplotlib color map
1841
+ colormap to apply to the image
1842
+
1843
+ Returns
1844
+ -------
1845
+ im2 : numpy array
1846
+ output rgba image
1847
+ """
1848
+ im2 = img.copy()
1849
+ im2 = norm255(im2)
1850
+ cbartmp = cbar(range(255))
1851
+ cbartmp = np.array([[0., 0., 0., 1.]]+cbartmp.tolist())*255
1852
+ # cbartmp[:, :-1] *= 255
1853
+ cbartmp = cbartmp.round()
1854
+ cbartmp = cbartmp.astype(np.uint8)
1855
+ im2 = cbartmp[im2]
1856
+ im2[:, :, 3] = np.logical_not(img.mask)*254+1
1857
+
1858
+ return im2
1859
+
1860
+
1861
+ def norm2(dat):
1862
+ """
1863
+ Normalise array vector between 0. and 1.
1864
+
1865
+ Parameters
1866
+ ----------
1867
+ dat : numpy array
1868
+ array to be normalised
1869
+
1870
+ Returns
1871
+ -------
1872
+ out : numpy array of floats
1873
+ normalised array
1874
+ """
1875
+ datmin = float(dat.min())
1876
+ datptp = float(dat.ptp())
1877
+ out = np.ma.array(ne.evaluate('(dat-datmin)/datptp'))
1878
+ out.mask = dat.mask
1879
+ return out
1880
+
1881
+
1882
+ def norm255(dat):
1883
+ """
1884
+ Normalise array vector between 1 and 255
1885
+
1886
+ Parameters
1887
+ ----------
1888
+ dat : numpy array
1889
+ array to be normalised
1890
+
1891
+ Returns
1892
+ -------
1893
+ out : numpy array of 8 bit integers
1894
+ normalised array
1895
+ """
1896
+ datmin = float(dat.min())
1897
+ datptp = float(dat.ptp())
1898
+ out = ne.evaluate('254*(dat-datmin)/datptp+1')
1899
+ out = out.round()
1900
+ out = out.astype(np.uint8)
1901
+ return out