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,667 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
# Name: graph_tool.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
|
+
"""
|
|
26
|
+
Graph tool is a multi-function graphing tool for use with cluster analysis
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
import numpy as np
|
|
30
|
+
from PyQt4 import QtGui, QtCore
|
|
31
|
+
from matplotlib.figure import Figure
|
|
32
|
+
import matplotlib.pylab as plt
|
|
33
|
+
from matplotlib.path import Path
|
|
34
|
+
from matplotlib.backends.backend_qt4agg import FigureCanvas
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class GraphHist(FigureCanvas):
|
|
38
|
+
"""
|
|
39
|
+
Plots several lines in distinct colors.
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
parent : parent
|
|
44
|
+
reference to the parent routine.
|
|
45
|
+
"""
|
|
46
|
+
def __init__(self, parent=None):
|
|
47
|
+
self.figure = Figure()
|
|
48
|
+
|
|
49
|
+
FigureCanvas.__init__(self, self.figure)
|
|
50
|
+
self.setParent(parent)
|
|
51
|
+
|
|
52
|
+
self.nullfmt = plt.NullFormatter()
|
|
53
|
+
self.pntxy = None
|
|
54
|
+
self.polyi = None
|
|
55
|
+
self.axhistx = None
|
|
56
|
+
self.axhisty = None
|
|
57
|
+
self.axscatter = None
|
|
58
|
+
self.histx = None
|
|
59
|
+
self.histy = None
|
|
60
|
+
self.xcoord = None
|
|
61
|
+
self.ycoord = None
|
|
62
|
+
self.data = []
|
|
63
|
+
self.cindx = [0, 1, 0]
|
|
64
|
+
self.cdata = []
|
|
65
|
+
self.csp = None
|
|
66
|
+
|
|
67
|
+
def get_hist(self, bins):
|
|
68
|
+
""" Routine to get the scattergram with histogram overlay """
|
|
69
|
+
xyhist = np.zeros((bins + 1, bins + 1))
|
|
70
|
+
xxx = self.xcoord.compressed()
|
|
71
|
+
yyy = self.ycoord.compressed()
|
|
72
|
+
|
|
73
|
+
xyhist = np.histogram2d(xxx, yyy, bins + 1)
|
|
74
|
+
|
|
75
|
+
xymahist = np.ma.masked_equal(xyhist[0], 0)
|
|
76
|
+
return xymahist
|
|
77
|
+
|
|
78
|
+
def get_clust_scat(self, bins, dattmp, ctmp):
|
|
79
|
+
""" Routine to get the scattergram with cluster overlay """
|
|
80
|
+
clust = np.ma.array(dattmp[ctmp[2] - 1].data.flatten())
|
|
81
|
+
clust.mask = self.xcoord.mask
|
|
82
|
+
clust = clust.compressed()
|
|
83
|
+
xxx = self.xcoord.compressed()
|
|
84
|
+
yyy = self.ycoord.compressed()
|
|
85
|
+
xyhist = np.zeros((bins + 1, bins + 1))
|
|
86
|
+
|
|
87
|
+
xyhist[xxx, yyy] = (clust + 1)
|
|
88
|
+
|
|
89
|
+
xymahist = np.ma.masked_equal(xyhist, 0)
|
|
90
|
+
return xymahist
|
|
91
|
+
|
|
92
|
+
def init_graph(self):
|
|
93
|
+
""" Initialize the Graph """
|
|
94
|
+
# definitions for the axes
|
|
95
|
+
self.figure.clf()
|
|
96
|
+
|
|
97
|
+
left, width = 0.1, 0.65
|
|
98
|
+
bottom, height = 0.1, 0.65
|
|
99
|
+
bottom_h = bottom + height + 0.02
|
|
100
|
+
left_h = left + width + 0.02
|
|
101
|
+
|
|
102
|
+
rect_scatter = [left, bottom, width, height]
|
|
103
|
+
rect_histx = [left, bottom_h, width, 0.2]
|
|
104
|
+
rect_histy = [left_h, bottom, 0.2, height]
|
|
105
|
+
|
|
106
|
+
self.axscatter = self.figure.add_axes(rect_scatter, label='s')
|
|
107
|
+
self.axhistx = self.figure.add_axes(rect_histx, label='x')
|
|
108
|
+
self.axhisty = self.figure.add_axes(rect_histy, label='y')
|
|
109
|
+
|
|
110
|
+
# Setup the coordinates
|
|
111
|
+
self.setup_coords()
|
|
112
|
+
|
|
113
|
+
# setup 1d histograms
|
|
114
|
+
self.setup_hist()
|
|
115
|
+
|
|
116
|
+
# Compressed eliminates the masked values so that hist
|
|
117
|
+
xymahist = self.get_hist(50)
|
|
118
|
+
|
|
119
|
+
self.axscatter.get_xaxis().set_visible(False)
|
|
120
|
+
self.axscatter.get_yaxis().set_visible(False)
|
|
121
|
+
|
|
122
|
+
self.csp = self.axscatter.imshow(xymahist.T, interpolation='nearest',
|
|
123
|
+
cmap=plt.cm.jet, aspect='auto')
|
|
124
|
+
|
|
125
|
+
self.figure.canvas.draw()
|
|
126
|
+
|
|
127
|
+
def polyint(self):
|
|
128
|
+
""" Polygon Interactor routine """
|
|
129
|
+
pntxy = np.transpose([self.xcoord, self.ycoord])
|
|
130
|
+
self.polyi = PolygonInteractor(self.axscatter, pntxy)
|
|
131
|
+
self.polyi.ishist = True
|
|
132
|
+
|
|
133
|
+
def setup_coords(self):
|
|
134
|
+
""" Routine to setup the coordinates for the scattergram """
|
|
135
|
+
self.xcoord = self.data[self.cindx[0]].data.flatten()
|
|
136
|
+
self.ycoord = self.data[self.cindx[1]].data.flatten()
|
|
137
|
+
self.xcoord -= self.xcoord.min()
|
|
138
|
+
self.ycoord -= self.ycoord.min()
|
|
139
|
+
xptp = self.xcoord.ptp()
|
|
140
|
+
yptp = self.ycoord.ptp()
|
|
141
|
+
xstep = xptp / 50
|
|
142
|
+
ystep = yptp / 50
|
|
143
|
+
self.xcoord /= xstep
|
|
144
|
+
self.ycoord /= ystep
|
|
145
|
+
self.xcoord = self.xcoord.astype(int)
|
|
146
|
+
self.ycoord = self.ycoord.astype(int)
|
|
147
|
+
|
|
148
|
+
def setup_hist(self):
|
|
149
|
+
""" Routine to setup the 1d histograms """
|
|
150
|
+
self.axhistx.xaxis.set_major_formatter(self.nullfmt)
|
|
151
|
+
self.axhisty.yaxis.set_major_formatter(self.nullfmt)
|
|
152
|
+
self.axhistx.yaxis.set_major_formatter(self.nullfmt)
|
|
153
|
+
self.axhisty.xaxis.set_major_formatter(self.nullfmt)
|
|
154
|
+
xrng = [self.xcoord.min(), self.xcoord.max()]
|
|
155
|
+
yrng = [self.ycoord.min(), self.ycoord.max()]
|
|
156
|
+
self.histx = self.axhistx.hist(self.xcoord.compressed(), 50)
|
|
157
|
+
self.histy = self.axhisty.hist(self.ycoord.compressed(), 50,
|
|
158
|
+
orientation='horizontal')
|
|
159
|
+
self.axhistx.set_xlim(xrng)
|
|
160
|
+
self.axhisty.set_ylim(yrng[::-1])
|
|
161
|
+
|
|
162
|
+
def update_graph(self, clearaxis=False):
|
|
163
|
+
""" Draw Routine """
|
|
164
|
+
if clearaxis is True:
|
|
165
|
+
self.axhistx.cla()
|
|
166
|
+
self.axhisty.cla()
|
|
167
|
+
|
|
168
|
+
self.setup_coords()
|
|
169
|
+
self.polyi.pntxy = np.array([self.xcoord, self.ycoord]).T
|
|
170
|
+
self.setup_hist()
|
|
171
|
+
|
|
172
|
+
if self.cindx[2] > 0:
|
|
173
|
+
xymahist = self.get_clust_scat(50, self.cdata, self.cindx)
|
|
174
|
+
else:
|
|
175
|
+
xymahist = self.get_hist(50)
|
|
176
|
+
|
|
177
|
+
if self.csp is None:
|
|
178
|
+
return
|
|
179
|
+
|
|
180
|
+
self.csp.set_data(xymahist.T)
|
|
181
|
+
self.csp.set_clim(xymahist.min(), xymahist.max())
|
|
182
|
+
self.csp.changed()
|
|
183
|
+
self.figure.canvas.draw()
|
|
184
|
+
self.polyi.draw_callback()
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class GraphMap(FigureCanvas):
|
|
188
|
+
"""
|
|
189
|
+
Plots several lines in distinct colors.
|
|
190
|
+
|
|
191
|
+
Parameters
|
|
192
|
+
----------
|
|
193
|
+
parent : parent
|
|
194
|
+
reference to the parent routine.
|
|
195
|
+
|
|
196
|
+
Attributes
|
|
197
|
+
----------
|
|
198
|
+
parent : parent
|
|
199
|
+
reference to the parent routine
|
|
200
|
+
"""
|
|
201
|
+
def __init__(self, parent):
|
|
202
|
+
self.figure = Figure()
|
|
203
|
+
|
|
204
|
+
FigureCanvas.__init__(self, self.figure)
|
|
205
|
+
self.setParent(parent)
|
|
206
|
+
|
|
207
|
+
self.parent = parent
|
|
208
|
+
self.polyi = None
|
|
209
|
+
self.data = []
|
|
210
|
+
self.cdata = []
|
|
211
|
+
self.mindx = [0, 0]
|
|
212
|
+
self.csp = None
|
|
213
|
+
self.subplot = None
|
|
214
|
+
|
|
215
|
+
# def dat_extent(self, dat):
|
|
216
|
+
# """ Gets the extend of the dat variable """
|
|
217
|
+
# left = dat.tlx
|
|
218
|
+
# top = dat.tly
|
|
219
|
+
# right = left + dat.cols*dat.xdim
|
|
220
|
+
# bottom = top - dat.rows*dat.ydim
|
|
221
|
+
# return (left, right, bottom, top)
|
|
222
|
+
|
|
223
|
+
def init_graph(self):
|
|
224
|
+
""" Initialize the Graph """
|
|
225
|
+
mtmp = self.mindx
|
|
226
|
+
dat = self.data[mtmp[0]]
|
|
227
|
+
|
|
228
|
+
self.figure.clf()
|
|
229
|
+
self.subplot = self.figure.add_subplot(111)
|
|
230
|
+
self.subplot.get_xaxis().set_visible(False)
|
|
231
|
+
self.subplot.get_yaxis().set_visible(False)
|
|
232
|
+
|
|
233
|
+
self.csp = self.subplot.imshow(dat.data, cmap=plt.cm.jet)
|
|
234
|
+
self.subplot.figure.colorbar(self.csp)
|
|
235
|
+
|
|
236
|
+
self.figure.canvas.draw()
|
|
237
|
+
|
|
238
|
+
def polyint(self):
|
|
239
|
+
""" Polygon Integrator """
|
|
240
|
+
mtmp = self.mindx
|
|
241
|
+
dat = self.data[mtmp[0]].data
|
|
242
|
+
|
|
243
|
+
xtmp = np.arange(dat.shape[1])
|
|
244
|
+
ytmp = np.arange(dat.shape[0])
|
|
245
|
+
xmesh, ymesh = np.meshgrid(xtmp, ytmp)
|
|
246
|
+
xmesh = np.ma.array(xmesh, dtype=float, mask=dat.mask)
|
|
247
|
+
ymesh = np.ma.array(ymesh, dtype=float, mask=dat.mask)
|
|
248
|
+
xmesh = xmesh.flatten()
|
|
249
|
+
ymesh = ymesh.flatten()
|
|
250
|
+
xmesh = xmesh.filled(np.nan)
|
|
251
|
+
ymesh = ymesh.filled(np.nan)
|
|
252
|
+
pntxy = np.transpose([xmesh, ymesh])
|
|
253
|
+
self.polyi = PolygonInteractor(self.subplot, pntxy)
|
|
254
|
+
self.polyi.ishist = False
|
|
255
|
+
|
|
256
|
+
def update_graph(self):
|
|
257
|
+
""" Draw routine """
|
|
258
|
+
mtmp = self.mindx
|
|
259
|
+
dat = self.data[mtmp[0]]
|
|
260
|
+
|
|
261
|
+
self.figure.clf()
|
|
262
|
+
self.subplot = self.figure.add_subplot(111)
|
|
263
|
+
self.subplot.get_xaxis().set_visible(False)
|
|
264
|
+
self.subplot.get_yaxis().set_visible(False)
|
|
265
|
+
|
|
266
|
+
if mtmp[1] > 0:
|
|
267
|
+
cdat = self.cdata[mtmp[1] - 1].data + 1
|
|
268
|
+
self.csp = self.subplot.imshow(cdat, cmap=plt.cm.jet)
|
|
269
|
+
vals = np.unique(cdat)
|
|
270
|
+
vals = vals.compressed()
|
|
271
|
+
bnds = (vals - 0.5).tolist() + [vals.max() + .5]
|
|
272
|
+
self.subplot.figure.colorbar(self.csp, boundaries=bnds,
|
|
273
|
+
values=vals, ticks=vals)
|
|
274
|
+
else:
|
|
275
|
+
self.csp = self.subplot.imshow(dat.data, cmap=plt.cm.jet)
|
|
276
|
+
self.subplot.figure.colorbar(self.csp)
|
|
277
|
+
|
|
278
|
+
self.figure.canvas.draw()
|
|
279
|
+
self.polyi.draw_callback()
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
class PolygonInteractor(QtCore.QObject):
|
|
283
|
+
"""
|
|
284
|
+
Polygon Interactor
|
|
285
|
+
|
|
286
|
+
Parameters
|
|
287
|
+
----------
|
|
288
|
+
axtmp : matplotlib axis
|
|
289
|
+
matplotlib axis
|
|
290
|
+
pntxy :
|
|
291
|
+
|
|
292
|
+
"""
|
|
293
|
+
showverts = True
|
|
294
|
+
epsilon = 5 # max pixel distance to count as a vertex hit
|
|
295
|
+
polyi_changed = QtCore.pyqtSignal(list)
|
|
296
|
+
|
|
297
|
+
def __init__(self, axtmp, pntxy):
|
|
298
|
+
QtCore.QObject.__init__(self)
|
|
299
|
+
self.ax = axtmp
|
|
300
|
+
self.poly = plt.Polygon([(1, 1)], animated=True)
|
|
301
|
+
self.ax.add_patch(self.poly)
|
|
302
|
+
self.canvas = self.poly.figure.canvas
|
|
303
|
+
self.poly.set_alpha(0.5)
|
|
304
|
+
self.pntxy = pntxy
|
|
305
|
+
self.ishist = True
|
|
306
|
+
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
|
|
307
|
+
|
|
308
|
+
xtmp, ytmp = list(zip(*self.poly.xy))
|
|
309
|
+
|
|
310
|
+
self.line = plt.Line2D(xtmp, ytmp, marker='o', markerfacecolor='r',
|
|
311
|
+
color='y', animated=True)
|
|
312
|
+
self.ax.add_line(self.line)
|
|
313
|
+
# self._update_line(poly)
|
|
314
|
+
|
|
315
|
+
self.poly.add_callback(self.poly_changed)
|
|
316
|
+
self._ind = None # the active vert
|
|
317
|
+
|
|
318
|
+
self.canvas.mpl_connect('button_press_event',
|
|
319
|
+
self.button_press_callback)
|
|
320
|
+
self.canvas.mpl_connect('button_release_event',
|
|
321
|
+
self.button_release_callback)
|
|
322
|
+
self.canvas.mpl_connect('motion_notify_event',
|
|
323
|
+
self.motion_notify_callback)
|
|
324
|
+
|
|
325
|
+
def draw_callback(self):
|
|
326
|
+
""" Draw callback """
|
|
327
|
+
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
|
|
328
|
+
QtGui.QApplication.processEvents()
|
|
329
|
+
|
|
330
|
+
self.canvas.restore_region(self.background)
|
|
331
|
+
self.ax.draw_artist(self.poly)
|
|
332
|
+
self.ax.draw_artist(self.line)
|
|
333
|
+
# self.canvas.blit(self.ax.bbox)
|
|
334
|
+
self.canvas.update()
|
|
335
|
+
|
|
336
|
+
def new_poly(self, npoly):
|
|
337
|
+
""" New Polygon """
|
|
338
|
+
self.poly.set_xy(npoly)
|
|
339
|
+
self.line.set_data(list(zip(*self.poly.xy)))
|
|
340
|
+
|
|
341
|
+
self.canvas.draw()
|
|
342
|
+
self.update_plots()
|
|
343
|
+
|
|
344
|
+
def poly_changed(self, poly):
|
|
345
|
+
""" Changed Polygon """
|
|
346
|
+
# this method is called whenever the polygon object is called
|
|
347
|
+
# only copy the artist props to the line (except visibility)
|
|
348
|
+
vis = self.line.get_visible()
|
|
349
|
+
plt.Artist.update_from(self.line, poly)
|
|
350
|
+
self.line.set_visible(vis) # don't use the poly visibility state
|
|
351
|
+
|
|
352
|
+
def get_ind_under_point(self, event):
|
|
353
|
+
"""get the index of vertex under point if within epsilon tolerance"""
|
|
354
|
+
|
|
355
|
+
# display coords
|
|
356
|
+
xytmp = np.asarray(self.poly.xy)
|
|
357
|
+
xyt = self.poly.get_transform().transform(xytmp)
|
|
358
|
+
xtt, ytt = xyt[:, 0], xyt[:, 1]
|
|
359
|
+
dtt = np.sqrt((xtt - event.x) ** 2 + (ytt - event.y) ** 2)
|
|
360
|
+
indseq = np.nonzero(np.equal(dtt, np.amin(dtt)))[0]
|
|
361
|
+
ind = indseq[0]
|
|
362
|
+
|
|
363
|
+
if dtt[ind] >= self.epsilon:
|
|
364
|
+
ind = None
|
|
365
|
+
|
|
366
|
+
return ind
|
|
367
|
+
|
|
368
|
+
def button_press_callback(self, event):
|
|
369
|
+
"""whenever a mouse button is pressed"""
|
|
370
|
+
if event.inaxes is None:
|
|
371
|
+
return
|
|
372
|
+
if event.button != 1:
|
|
373
|
+
return
|
|
374
|
+
self._ind = self.get_ind_under_point(event)
|
|
375
|
+
|
|
376
|
+
if self._ind is None:
|
|
377
|
+
xys = self.poly.get_transform().transform(self.poly.xy)
|
|
378
|
+
ptmp = event.x, event.y # display coords
|
|
379
|
+
|
|
380
|
+
if len(xys) == 1:
|
|
381
|
+
self.poly.xy = np.array(
|
|
382
|
+
[(event.xdata, event.ydata)] +
|
|
383
|
+
[(event.xdata, event.ydata)])
|
|
384
|
+
self.line.set_data(list(zip(*self.poly.xy)))
|
|
385
|
+
|
|
386
|
+
self.canvas.restore_region(self.background)
|
|
387
|
+
self.ax.draw_artist(self.poly)
|
|
388
|
+
self.ax.draw_artist(self.line)
|
|
389
|
+
# self.canvas.blit(self.ax.bbox)
|
|
390
|
+
self.canvas.update()
|
|
391
|
+
return
|
|
392
|
+
dmin = -1
|
|
393
|
+
imin = -1
|
|
394
|
+
for i in range(len(xys) - 1):
|
|
395
|
+
s0tmp = xys[i]
|
|
396
|
+
s1tmp = xys[i + 1]
|
|
397
|
+
dtmp = plt.dist_point_to_segment(ptmp, s0tmp, s1tmp)
|
|
398
|
+
if dmin == -1:
|
|
399
|
+
dmin = dtmp
|
|
400
|
+
imin = i
|
|
401
|
+
elif dtmp < dmin:
|
|
402
|
+
dmin = dtmp
|
|
403
|
+
imin = i
|
|
404
|
+
i = imin
|
|
405
|
+
self.poly.xy = np.array(list(self.poly.xy[:i + 1]) +
|
|
406
|
+
[(event.xdata, event.ydata)] +
|
|
407
|
+
list(self.poly.xy[i + 1:]))
|
|
408
|
+
self.line.set_data(list(zip(*self.poly.xy)))
|
|
409
|
+
|
|
410
|
+
self.canvas.restore_region(self.background)
|
|
411
|
+
self.ax.draw_artist(self.poly)
|
|
412
|
+
self.ax.draw_artist(self.line)
|
|
413
|
+
# self.canvas.blit(self.ax.bbox)
|
|
414
|
+
self.canvas.update()
|
|
415
|
+
|
|
416
|
+
def button_release_callback(self, event):
|
|
417
|
+
"""Whenever a mouse button is released"""
|
|
418
|
+
if event.button != 1:
|
|
419
|
+
return
|
|
420
|
+
self._ind = None
|
|
421
|
+
self.update_plots()
|
|
422
|
+
|
|
423
|
+
def update_plots(self):
|
|
424
|
+
""" Update Plots """
|
|
425
|
+
polymask = Path(self.poly.xy).contains_points(self.pntxy)
|
|
426
|
+
self.polyi_changed.emit(polymask.tolist())
|
|
427
|
+
|
|
428
|
+
def motion_notify_callback(self, event):
|
|
429
|
+
"""on mouse movement"""
|
|
430
|
+
if self._ind is None:
|
|
431
|
+
return
|
|
432
|
+
if event.inaxes is None:
|
|
433
|
+
return
|
|
434
|
+
if event.button != 1:
|
|
435
|
+
return
|
|
436
|
+
xtmp, ytmp = event.xdata, event.ydata
|
|
437
|
+
|
|
438
|
+
self.poly.xy[self._ind] = xtmp, ytmp
|
|
439
|
+
if self._ind == 0:
|
|
440
|
+
self.poly.xy[-1] = xtmp, ytmp
|
|
441
|
+
|
|
442
|
+
self.line.set_data(list(zip(*self.poly.xy)))
|
|
443
|
+
|
|
444
|
+
self.canvas.restore_region(self.background)
|
|
445
|
+
self.ax.draw_artist(self.poly)
|
|
446
|
+
self.ax.draw_artist(self.line)
|
|
447
|
+
# self.canvas.blit(self.ax.bbox)
|
|
448
|
+
self.canvas.update()
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
class ScatterPlot(QtGui.QDialog):
|
|
452
|
+
"""
|
|
453
|
+
Main Graph Tool Routine
|
|
454
|
+
|
|
455
|
+
Parameters
|
|
456
|
+
----------
|
|
457
|
+
parent : parent
|
|
458
|
+
reference to the parent routine.
|
|
459
|
+
|
|
460
|
+
Attributes
|
|
461
|
+
----------
|
|
462
|
+
parent : parent
|
|
463
|
+
reference to the parent routine
|
|
464
|
+
indata : dictionary
|
|
465
|
+
dictionary of input datasets
|
|
466
|
+
outdata : dictionary
|
|
467
|
+
dictionary of output datasets
|
|
468
|
+
"""
|
|
469
|
+
def __init__(self, parent):
|
|
470
|
+
QtGui.QDialog.__init__(self, parent)
|
|
471
|
+
self.indata = {}
|
|
472
|
+
self.outdata = {}
|
|
473
|
+
self.parent = parent
|
|
474
|
+
self.m1 = 0
|
|
475
|
+
self.c = [0, 1, 0]
|
|
476
|
+
self.m = [0, 0]
|
|
477
|
+
self.dat_tmp = None
|
|
478
|
+
|
|
479
|
+
self.map = GraphMap(self)
|
|
480
|
+
self.hist = GraphHist(self)
|
|
481
|
+
|
|
482
|
+
self.cp_dpoly = QtGui.QPushButton()
|
|
483
|
+
self.cp_combo = QtGui.QComboBox()
|
|
484
|
+
self.cp_combo2 = QtGui.QComboBox()
|
|
485
|
+
self.cp_combo3 = QtGui.QComboBox()
|
|
486
|
+
self.map_dpoly = QtGui.QPushButton()
|
|
487
|
+
self.map_combo = QtGui.QComboBox()
|
|
488
|
+
self.map_combo2 = QtGui.QComboBox()
|
|
489
|
+
|
|
490
|
+
self.setupui()
|
|
491
|
+
|
|
492
|
+
self.hist.cindx = self.c
|
|
493
|
+
self.map.mindx = self.m
|
|
494
|
+
|
|
495
|
+
def setupui(self):
|
|
496
|
+
""" Setup UI """
|
|
497
|
+
grid_main = QtGui.QGridLayout(self)
|
|
498
|
+
group_cp = QtGui.QGroupBox()
|
|
499
|
+
grid_left = QtGui.QGridLayout(group_cp)
|
|
500
|
+
group_map = QtGui.QGroupBox()
|
|
501
|
+
grid_right = QtGui.QGridLayout(group_map)
|
|
502
|
+
|
|
503
|
+
self.setWindowTitle("Graph Window")
|
|
504
|
+
group_map.setTitle("Map Settings")
|
|
505
|
+
group_cp.setTitle('Cross Plot Settings')
|
|
506
|
+
|
|
507
|
+
lbl_combo_left = QtGui.QLabel()
|
|
508
|
+
lbl_combo2_left = QtGui.QLabel()
|
|
509
|
+
lbl_combo3_left = QtGui.QLabel()
|
|
510
|
+
lbl_combo_right = QtGui.QLabel()
|
|
511
|
+
lbl_combo2_right = QtGui.QLabel()
|
|
512
|
+
|
|
513
|
+
lbl_combo_left.setText('X Data Band:')
|
|
514
|
+
lbl_combo2_left.setText('Y Data Band:')
|
|
515
|
+
lbl_combo3_left.setText('Cluster Overlay:')
|
|
516
|
+
self.cp_dpoly.setText('Delete Polygon')
|
|
517
|
+
lbl_combo_right.setText('Data Band:')
|
|
518
|
+
lbl_combo2_right.setText('Cluster Overlay:')
|
|
519
|
+
self.map_dpoly.setText('Delete Polygon')
|
|
520
|
+
|
|
521
|
+
grid_left.addWidget(lbl_combo_left, 0, 0, 1, 1)
|
|
522
|
+
grid_left.addWidget(lbl_combo2_left, 1, 0, 1, 1)
|
|
523
|
+
grid_left.addWidget(lbl_combo3_left, 2, 0, 1, 1)
|
|
524
|
+
grid_left.addWidget(self.cp_dpoly, 0, 2, 1, 1)
|
|
525
|
+
grid_left.addWidget(self.cp_combo, 0, 1, 1, 1)
|
|
526
|
+
grid_left.addWidget(self.cp_combo2, 1, 1, 1, 1)
|
|
527
|
+
grid_left.addWidget(self.cp_combo3, 2, 1, 1, 1)
|
|
528
|
+
grid_right.addWidget(lbl_combo_right, 0, 0, 1, 1)
|
|
529
|
+
grid_right.addWidget(lbl_combo2_right, 1, 0, 1, 1)
|
|
530
|
+
grid_right.addWidget(self.map_dpoly, 0, 2, 1, 1)
|
|
531
|
+
grid_right.addWidget(self.map_combo, 0, 1, 1, 1)
|
|
532
|
+
grid_right.addWidget(self.map_combo2, 1, 1, 1, 1)
|
|
533
|
+
grid_main.addWidget(self.hist, 0, 0, 1, 1)
|
|
534
|
+
grid_main.addWidget(self.map, 0, 1, 1, 1)
|
|
535
|
+
grid_main.addWidget(group_cp, 1, 0, 1, 1)
|
|
536
|
+
grid_main.addWidget(group_map, 1, 1, 1, 1)
|
|
537
|
+
|
|
538
|
+
self.cp_dpoly.clicked.connect(self.on_cp_dpoly)
|
|
539
|
+
self.map_dpoly.clicked.connect(self.on_map_dpoly)
|
|
540
|
+
|
|
541
|
+
def on_cp_dpoly(self):
|
|
542
|
+
""" cp dpoly """
|
|
543
|
+
self.hist.polyi.new_poly([[10, 10]])
|
|
544
|
+
dattmp = self.map.csp.get_array()
|
|
545
|
+
dattmp.mask = np.zeros_like(dattmp.mask)
|
|
546
|
+
self.map.csp.changed()
|
|
547
|
+
self.map.figure.canvas.draw()
|
|
548
|
+
|
|
549
|
+
def on_map_dpoly(self):
|
|
550
|
+
""" map dpoly """
|
|
551
|
+
self.map.polyi.new_poly([[10, 10]])
|
|
552
|
+
dattmp = self.hist.csp.get_array()
|
|
553
|
+
dattmp.mask = np.ma.masked_equal(dattmp.data, 0.).mask
|
|
554
|
+
self.hist.csp.changed()
|
|
555
|
+
self.hist.figure.canvas.draw()
|
|
556
|
+
|
|
557
|
+
def on_cp_combo(self):
|
|
558
|
+
""" On Combo """
|
|
559
|
+
gstmp = self.cp_combo.currentIndex()
|
|
560
|
+
if gstmp != self.c[0]:
|
|
561
|
+
self.c[0] = gstmp
|
|
562
|
+
self.hist.update_graph(clearaxis=True)
|
|
563
|
+
|
|
564
|
+
def on_cp_combo2(self):
|
|
565
|
+
""" On Combo 2 """
|
|
566
|
+
gstmp = self.cp_combo2.currentIndex()
|
|
567
|
+
if gstmp != self.c[1]:
|
|
568
|
+
self.c[1] = gstmp
|
|
569
|
+
self.hist.update_graph(clearaxis=True)
|
|
570
|
+
|
|
571
|
+
def on_cp_combo3(self):
|
|
572
|
+
""" On combo 3 """
|
|
573
|
+
self.c[2] = self.cp_combo3.currentIndex()
|
|
574
|
+
self.hist.update_graph()
|
|
575
|
+
|
|
576
|
+
def on_map_combo(self):
|
|
577
|
+
""" On map combo """
|
|
578
|
+
self.m[0] = self.map_combo.currentIndex()
|
|
579
|
+
self.map.update_graph()
|
|
580
|
+
|
|
581
|
+
def on_map_combo2(self):
|
|
582
|
+
""" On map combo 2 """
|
|
583
|
+
self.m[1] = self.map_combo2.currentIndex()
|
|
584
|
+
self.map.update_graph()
|
|
585
|
+
|
|
586
|
+
def settings(self):
|
|
587
|
+
""" run """
|
|
588
|
+
if 'Raster' not in self.indata:
|
|
589
|
+
self.parent.showprocesslog('Error: You must have a multi-band ' +
|
|
590
|
+
'raster dataset in addition to your' +
|
|
591
|
+
' cluster analysis results')
|
|
592
|
+
return False
|
|
593
|
+
|
|
594
|
+
self.dat_tmp = self.indata['Raster']
|
|
595
|
+
self.map.data = self.indata['Raster']
|
|
596
|
+
self.hist.data = self.indata['Raster']
|
|
597
|
+
|
|
598
|
+
bands = [i.dataid for i in self.indata['Raster']]
|
|
599
|
+
|
|
600
|
+
self.cp_combo.clear()
|
|
601
|
+
self.cp_combo2.clear()
|
|
602
|
+
self.map_combo.clear()
|
|
603
|
+
|
|
604
|
+
self.cp_combo.addItems(bands)
|
|
605
|
+
self.cp_combo2.addItems(bands)
|
|
606
|
+
self.map_combo.addItems(bands)
|
|
607
|
+
self.cp_combo2.setCurrentIndex(1)
|
|
608
|
+
self.cp_combo.currentIndexChanged.connect(self.on_cp_combo)
|
|
609
|
+
self.cp_combo2.currentIndexChanged.connect(self.on_cp_combo2)
|
|
610
|
+
self.map_combo.currentIndexChanged.connect(self.on_map_combo)
|
|
611
|
+
|
|
612
|
+
cbands = ['Scatter Amplitudes']
|
|
613
|
+
mbands = ['None']
|
|
614
|
+
|
|
615
|
+
if 'Cluster' in self.indata:
|
|
616
|
+
self.hist.cdata = self.indata['Cluster']
|
|
617
|
+
self.map.cdata = self.indata['Cluster']
|
|
618
|
+
cbands += ['Clusters: ' + str(i.data.ptp()) for i in
|
|
619
|
+
self.indata['Cluster']]
|
|
620
|
+
mbands += ['Clusters: ' + str(i.data.ptp()) for i in
|
|
621
|
+
self.indata['Cluster']]
|
|
622
|
+
|
|
623
|
+
self.cp_combo3.clear()
|
|
624
|
+
self.map_combo2.clear()
|
|
625
|
+
|
|
626
|
+
self.cp_combo3.addItems(cbands)
|
|
627
|
+
self.map_combo2.addItems(mbands)
|
|
628
|
+
self.cp_combo3.currentIndexChanged.connect(self.on_cp_combo3)
|
|
629
|
+
self.map_combo2.currentIndexChanged.connect(self.on_map_combo2)
|
|
630
|
+
|
|
631
|
+
self.hist.init_graph()
|
|
632
|
+
self.map.init_graph()
|
|
633
|
+
|
|
634
|
+
self.show()
|
|
635
|
+
|
|
636
|
+
self.hist.polyint()
|
|
637
|
+
self.map.polyint()
|
|
638
|
+
|
|
639
|
+
self.hist.polyi.polyi_changed.connect(self.update_map)
|
|
640
|
+
self.map.polyi.polyi_changed.connect(self.update_hist)
|
|
641
|
+
|
|
642
|
+
return True
|
|
643
|
+
|
|
644
|
+
def update_map(self, polymask):
|
|
645
|
+
""" update """
|
|
646
|
+
if max(polymask) is False:
|
|
647
|
+
return
|
|
648
|
+
polymask = np.array(polymask)
|
|
649
|
+
dattmp = self.map.csp.get_array()
|
|
650
|
+
dattmp.mask = polymask
|
|
651
|
+
self.map.csp.changed()
|
|
652
|
+
self.map.figure.canvas.draw()
|
|
653
|
+
|
|
654
|
+
def update_hist(self, polymask):
|
|
655
|
+
""" update """
|
|
656
|
+
if max(polymask) is False:
|
|
657
|
+
return
|
|
658
|
+
|
|
659
|
+
polymask = np.array(polymask)
|
|
660
|
+
dattmp = self.hist.csp.get_array()
|
|
661
|
+
atmp = np.array([self.hist.xcoord[polymask],
|
|
662
|
+
self.hist.ycoord[polymask]]).T
|
|
663
|
+
dattmp.mask = np.ones_like(dattmp.mask)
|
|
664
|
+
for i in atmp:
|
|
665
|
+
dattmp.mask[i[1], i[0]] = False
|
|
666
|
+
self.hist.csp.changed()
|
|
667
|
+
self.hist.figure.canvas.draw()
|