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.
- pygmi-2.2.7/LICENSE.txt +623 -0
- pygmi-2.2.7/MANIFEST.in +7 -0
- pygmi-2.2.7/PKG-INFO +47 -0
- pygmi-2.2.7/README.md +55 -0
- pygmi-2.2.7/README.rst +20 -0
- pygmi-2.2.7/log.txt +242 -0
- pygmi-2.2.7/pygmi/__init__.py +22 -0
- pygmi-2.2.7/pygmi/clust/__init__.py +4 -0
- pygmi-2.2.7/pygmi/clust/crisp_clust.py +708 -0
- pygmi-2.2.7/pygmi/clust/datatypes.py +65 -0
- pygmi-2.2.7/pygmi/clust/fuzzy_clust.py +906 -0
- pygmi-2.2.7/pygmi/clust/graphs.py +421 -0
- pygmi-2.2.7/pygmi/clust/graphtool.py +667 -0
- pygmi-2.2.7/pygmi/clust/menu.py +139 -0
- pygmi-2.2.7/pygmi/clust/var_ratio.py +92 -0
- pygmi-2.2.7/pygmi/clust/xie_beni.py +93 -0
- pygmi-2.2.7/pygmi/helpdocs/linepointer.png +0 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.main.html +31 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.ddisp.html +15 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.iodefs.exportkmz.html +13 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.iodefs.importpicture.html +16 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.layer.html +17 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.mext.html +44 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.misc.rangedcopy.html +16 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.param.html +37 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.prof.html +32 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.pview.html +26 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.gradients.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.tilt.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.visibility.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datagrid.html +13 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datamerge.html +11 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datareproj.html +11 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.rtp.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.ginterp.html +31 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.igrf.html +20 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.normalisation.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.smooth.html +22 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.tiltdepth.html +20 -0
- pygmi-2.2.7/pygmi/images/Help.png +0 -0
- pygmi-2.2.7/pygmi/images/bringtofront.png +0 -0
- pygmi-2.2.7/pygmi/images/cgs2.emf +0 -0
- pygmi-2.2.7/pygmi/images/delete.png +0 -0
- pygmi-2.2.7/pygmi/images/linepointer.png +0 -0
- pygmi-2.2.7/pygmi/images/logo256.ico +0 -0
- pygmi-2.2.7/pygmi/images/logo256.png +0 -0
- pygmi-2.2.7/pygmi/images/pointer.png +0 -0
- pygmi-2.2.7/pygmi/images/pygmi.png +0 -0
- pygmi-2.2.7/pygmi/images/sendtoback.png +0 -0
- pygmi-2.2.7/pygmi/main.py +1037 -0
- pygmi-2.2.7/pygmi/menu_default.py +327 -0
- pygmi-2.2.7/pygmi/misc.py +147 -0
- pygmi-2.2.7/pygmi/pfmod/__init__.py +6 -0
- pygmi-2.2.7/pygmi/pfmod/cubes.py +1488 -0
- pygmi-2.2.7/pygmi/pfmod/datatypes.py +292 -0
- pygmi-2.2.7/pygmi/pfmod/grvmag3d.py +1265 -0
- pygmi-2.2.7/pygmi/pfmod/iodefs.py +1001 -0
- pygmi-2.2.7/pygmi/pfmod/menu.py +107 -0
- pygmi-2.2.7/pygmi/pfmod/misc.py +301 -0
- pygmi-2.2.7/pygmi/pfmod/pfmod.py +248 -0
- pygmi-2.2.7/pygmi/pfmod/tab_ddisp.py +425 -0
- pygmi-2.2.7/pygmi/pfmod/tab_layer.py +490 -0
- pygmi-2.2.7/pygmi/pfmod/tab_mext.py +544 -0
- pygmi-2.2.7/pygmi/pfmod/tab_param.py +548 -0
- pygmi-2.2.7/pygmi/pfmod/tab_prof.py +946 -0
- pygmi-2.2.7/pygmi/pfmod/tab_pview.py +740 -0
- pygmi-2.2.7/pygmi/raster/IGRF11.COF +1635 -0
- pygmi-2.2.7/pygmi/raster/__init__.py +14 -0
- pygmi-2.2.7/pygmi/raster/cooper.py +718 -0
- pygmi-2.2.7/pygmi/raster/dataprep.py +1640 -0
- pygmi-2.2.7/pygmi/raster/datatypes.py +123 -0
- pygmi-2.2.7/pygmi/raster/equation_editor.py +256 -0
- pygmi-2.2.7/pygmi/raster/ginterp.py +1901 -0
- pygmi-2.2.7/pygmi/raster/graphs.py +531 -0
- pygmi-2.2.7/pygmi/raster/igrf.py +860 -0
- pygmi-2.2.7/pygmi/raster/iodefs.py +813 -0
- pygmi-2.2.7/pygmi/raster/menu.py +307 -0
- pygmi-2.2.7/pygmi/raster/normalisation.py +187 -0
- pygmi-2.2.7/pygmi/raster/show_table.py +245 -0
- pygmi-2.2.7/pygmi/raster/smooth.py +406 -0
- pygmi-2.2.7/pygmi/raster/tiltdepth.py +590 -0
- pygmi-2.2.7/pygmi/seis/__init__.py +0 -0
- pygmi-2.2.7/pygmi/seis/beachball.py +751 -0
- pygmi-2.2.7/pygmi/seis/datatypes.py +605 -0
- pygmi-2.2.7/pygmi/seis/del_rec.py +410 -0
- pygmi-2.2.7/pygmi/seis/iodefs.py +1261 -0
- pygmi-2.2.7/pygmi/seis/menu.py +136 -0
- pygmi-2.2.7/pygmi/seis/scan_imp.py +795 -0
- pygmi-2.2.7/pygmi/test/__init__.py +6 -0
- pygmi-2.2.7/pygmi/test/pfmod.py +212 -0
- pygmi-2.2.7/pygmi/test/tests.py +39 -0
- pygmi-2.2.7/pygmi/vector/__init__.py +7 -0
- pygmi-2.2.7/pygmi/vector/datatypes.py +74 -0
- pygmi-2.2.7/pygmi/vector/graphs.py +443 -0
- pygmi-2.2.7/pygmi/vector/iodefs.py +345 -0
- pygmi-2.2.7/pygmi/vector/menu.py +127 -0
- pygmi-2.2.7/pygmi.egg-info/PKG-INFO +47 -0
- pygmi-2.2.7/pygmi.egg-info/SOURCES.txt +105 -0
- pygmi-2.2.7/pygmi.egg-info/dependency_links.txt +1 -0
- pygmi-2.2.7/pygmi.egg-info/entry_points.txt +3 -0
- pygmi-2.2.7/pygmi.egg-info/not-zip-safe +1 -0
- pygmi-2.2.7/pygmi.egg-info/requires.txt +7 -0
- pygmi-2.2.7/pygmi.egg-info/top_level.txt +1 -0
- pygmi-2.2.7/quickstart.py +35 -0
- pygmi-2.2.7/setup.cfg +8 -0
- 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
|