def drawVA(ax, data, vals=None, usePos=True, pseudosection=False, **kwargs): """Draw apparent velocities as matrix into an axis. Parameters ---------- ax : mpl.Axes data : pg.DataContainer() Datacontainer with 's' and 'g' Sensorindieces and 't' traveltimes. usePos: bool [True] Use sensor positions for axes tick labels pseudosection : bool [False] Show in pseudosection style. vals : iterable Traveltimes, if None data need to contain 't' values. """ if isinstance(vals, str): vals = data(vals) if vals is None: vals = data('t') px = pg.x(data) gx = np.asarray([px[g] for g in data.id("g")]) sx = np.asarray([px[s] for s in data.id("s")]) offset = shotReceiverDistances(data, full=True) if min(vals) < 1e-10: print(vals) pg.error('zero traveltimes found.') va = offset / vals if pseudosection: midpoint = (gx + sx) / 2 gci = pg.viewer.mpl.dataview.drawVecMatrix(ax, midpoint, offset, va, queeze=True, label=pg.unit('as')) else: gci = pg.viewer.mpl.dataview.drawVecMatrix(ax, gx, sx, va, squeeze=True, label=pg.unit('as')) # A = np.ones((data.sensorCount(), data.sensorCount())) * np.nan # for i in range(data.size()): # A[int(data('s')[i]), int(data('g')[i])] = va[i] # gci = ax.imshow(A, interpolation='nearest') # ax.grid(True) if usePos: xt = np.arange(0, data.sensorCount(), 50) ax.set_xticks(xt) ax.set_xticklabels([str(int(px[xti])) for xti in xt]) ax.set_yticks(xt) ax.set_yticklabels([str(int(px[xti])) for xti in xt]) return gci
def restore(self): """Read data from json infos""" if os.path.exists(self._name + '.json'): # Fricking mpl kills locale setting to system default .. this went # horrible wrong for german 'decimal_point': ',' pg.checkAndFixLocaleDecimal_point(verbose=False) try: with open(self._name + '.json') as file: self.info = json.load(file) # if len(self.info['type']) != 1: # pg.error('only single return caches supported for now.') #pg._y(pg.pf(self.info)) if self.info['type'] == 'DataContainerERT': self._value = pg.DataContainerERT(self.info['file'], removeInvalid=False) # print(self._value) elif self.info['type'] == 'RVector': self._value = pg.Vector() self._value.load(self.info['file'], format=pg.core.Binary) elif self.info['type'] == 'Mesh': pg.tic() self._value = pg.Mesh() self._value.loadBinaryV2(self.info['file'] + '.bms') pg.debug("Restoring cache took:", pg.dur(), "s") elif self.info['type'] == 'ndarray': self._value = np.load(self.info['file'] + '.npy', allow_pickle=True) elif self.info['type'] == 'Cm05Matrix': self._value = pg.matrix.Cm05Matrix(self.info['file']) elif self.info['type'] == 'GeostatisticConstraintsMatrix': self._value = pg.matrix.GeostatisticConstraintsMatrix( self.info['file']) else: self._value = np.load(self.info['file'] + '.npy', allow_pickle=True) if self.value is not None: self.info['restored'] = self.info['restored'] + 1 self.updateCacheInfo() pg.info('Cache {3} restored ({1}s x {0}): {2}'.\ format(self.info['restored'], round(self.info['dur'], 1), self._name, self.info['codeinfo'])) else: # default try numpy pg.warn('Could not restore cache of type {0}.'.format(self.info['type'])) pg.debug("Restoring cache took:", pg.dur(), "s") except Exception as e: import traceback traceback.print_exc(file=sys.stdout) print(self.info) pg.error('Cache restoring failed.')
def showMatrix(mat, ax=None, **kwargs): """Show various pyGIMLi matrices using matplotlib. Args ---- mat: matrix ax: mpl.axes Keyword Args ------------ **kwargs : forwarded to mpl plotting commands Returns ------- mpl.axes, Colorbar """ if ax is None: print(ax) ax = pg.show()[0] try: from scipy.sparse import spmatrix if isinstance(mat, spmatrix): gci = drawSparseMatrix(ax, mat, **kwargs) return ax, None except ImportError: pass if isinstance(mat, (pg.core.RSparseMapMatrix, pg.core.RSparseMatrix)): gci = drawSparseMatrix(ax, mat, **kwargs) cBar = None elif isinstance(mat, pg.matrix.BlockMatrix): gci, cBar = drawBlockMatrix(ax, mat, **kwargs) if cBar is None: uniqueIDs = pg.unique([e.matrixID for e in mat.entries()]) cMap = pg.plt.cm.get_cmap("Set3", len(uniqueIDs)) sm = pg.plt.cm.ScalarMappable(cmap=cMap) cBar = createColorBar(sm, ax=ax, label="Matrix ID", cMin=-0.5, cMax=len(uniqueIDs) - 0.5) ticks = np.arange(len(uniqueIDs)) cBar.set_ticks(ticks) labels = [] for ID in uniqueIDs: label = "{:d}".format(ID) labels.append(label) cBar.set_ticklabels(labels) else: pg.error("Matrix type not supported yet.") return ax, cBar
def setCbarLevels(cbar, cMin=None, cMax=None, nLevs=5, levels=None): """Set colorbar levels given a number of levels and min/max values.""" if cMin is None: if hasattr(cbar, 'mappable'): cMin = cbar.mappable.get_clim()[0] else: pg.error('no cbar mappable. Cannot find cmin') if cMax is None: if hasattr(cbar, 'mappable'): cMax = cbar.mappable.get_clim()[1] else: pg.error('no cbar mappable. Cannot find cmax') if cMin == cMax: cMin *= 0.999 cMax *= 1.001 norm = None if hasattr(cbar, 'mappable'): norm = cbar.mappable.norm elif hasattr(cbar, 'norm'): norm = cbar.norm #norm.clip = True if levels is not None: cbarLevels = levels else: if isinstance(norm, mpl.colors.LogNorm): cbarLevels = np.logspace(np.log10(cMin), np.log10(cMax), nLevs) else: #if cMax < cMin: cbarLevels = np.linspace(cMin, cMax, nLevs) # FIXME: [10.1, 10.2, 10.3] mapped to [10 10 10] cbarLevelsString = [] if np.all(np.array(cbarLevels) < 1e-2): pg.debug("All values smaller than 1e-4, avoiding additional rounding.") roundValue = False else: roundValue = True for i in cbarLevels: cbarLevelsString.append(prettyFloat(i, roundValue)) if hasattr(cbar, 'mappable'): #cbar.set_clim(cMin, cMax) cbar.mappable.set_clim(vmin=cMin, vmax=cMax) cbar.set_ticks(cbarLevels) cbar.set_ticklabels(cbarLevelsString) cbar.draw_all() # necessary since mpl 3.0 cbar.ax.minorticks_off()
def checkError(self, err, dataVals): """Return relative error.""" if isinstance(err, pg.DataContainer): if not err.haveData('err'): pg.error('DataContainer has no "err" values. Fallback to 3%') return np.ones(err.size()) * 0.03 return err['err'] / dataVals return err
def regionProperties(self, regionNr=None): """Return dictionary of all properties for region number regionNr.""" if regionNr is None: return self._regionProperties try: return self._regionProperties[regionNr] except KeyError: print(self._regionProperties) pg.error("no region for region #:", regionNr)
def checkError(self, err, dataVals=None): """Return relative error. Default we assume 'err' are relative values. Overwrite is derived class if needed. """ if isinstance(err, pg.DataContainer): if not err.haveData('err'): pg.error('Datacontainer have no "err" values. ' 'Fallback set to 0.01') return err['err'] return err
def showMesh3DVista(mesh, data=None, **kwargs): """ Make use of the actual 3D visualization tool kit Parameters ---------- data: pg.Vector or np.ndarray Dictionary of cell values, sorted by key. The values need to be numpy arrays. Returns ------- plotter: pyvista.Plotter The plotter from pyvista. gui: Show3D [None] The small gui based on pyvista. Note that this is returned as 'None' if gui is passed as 'False'. Note ---- Not having PyQt5 installed results in displaying the first key (and values) from the dictionary. """ hold = kwargs.pop('hold', False) cmap = kwargs.pop('cmap', 'viridis') notebook = kwargs.pop('notebook', _inlineBackend_) gui = kwargs.pop('gui', False) # add given data from argument if gui: app = Qt.QApplication(sys.argv) s3d = Show3D(app) s3d.addMesh(mesh, data, cmap=cmap, **kwargs) if not hold: s3d.wait() return s3d.plotter, s3d # plotter, gui else: if notebook: pyvista.set_plot_theme('document') try: plotter = drawModel(None, mesh, data, notebook=notebook, cmap=cmap, **kwargs) except Exception as e: print(e) pg.error("fix pyvista bindings") if not hold: plotter.show() return plotter, None
def filterIndex(seq, idx): """TODO DOCUMENTME.""" pg.error('filterIndex in use?') if isinstance(seq, pg.Vector): # return seq(idx) ret = pg.Vector(len(idx)) else: ret = list(range(len(idx))) for i, ix in enumerate(idx): ret[i] = seq[ix] return ret
def pgMesh2pvMesh(mesh, data=None, label=None): """ pyGIMLi's mesh format is different from pyvista's needs, some preparation is necessary. Parameters ---------- mesh: pg.Mesh Structure generated by pyGIMLi to display. data: iterable Parameter to distribute to cells/nodes. """ _, tmp = tempfile.mkstemp(suffix=".vtk") # export given mesh temporarily is the easiest and fastest option ATM mesh.exportVTK(tmp) grid = pv.read(tmp) # check for parameters inside the pg.Mesh for key, values in mesh.dataMap(): if len(values) == mesh.cellCount(): grid.cell_arrays[key] = np.asarray(values) elif len(values) == mesh.nodeCount(): grid.point_arrays[key] = np.asarray(values) # check the given data as well try: if data is not None: if len(data) == mesh.cellCount(): grid.cell_arrays[label] = np.asarray(data) elif len(data) == mesh.nodeCount(): grid.point_arrays[label] = np.asarray(data) else: pg.warn("Given data fits neither cell count nor node count:") pg.warn("{} vs. {} vs. {}".format(len(data), mesh.cellCount(), mesh.nodeCount())) except Exception as e: print(e) pg.error("fix pyvista bindings") if label is None: # last data that was added label = grid.array_names[-1] elif label not in grid.array_names: pg.warn("Given label '{}' was not found.".format(label)) label = grid.array_names[-1] grid.set_active_scalars(label) return grid
def getIndex(seq, f): """TODO DOCUMENTME.""" pg.error('getIndex in use?') # DEPRECATED_SLOW idx = [] if isinstance(seq, pg.Vector): for i, _ in enumerate(seq): v = seq[i] if f(v): idx.append(i) else: for i, d in enumerate(seq): if f(d): idx.append(i) return idx
def showmymatrix(mat, x, y, dx=2, dy=1, xlab=None, ylab=None, cbar=None): """What is this good for?.""" pg.error('who use this?') plt.imshow(mat, interpolation='nearest') plt.xticks(np.arange(0, len(x), dx), ["%g" % rndig(xi, 2) for xi in x]) plt.yticks(np.arange(0, len(y), dy), ["%g" % rndig(yi, 2) for yi in y]) plt.ylim((len(y) - 0.5, -0.5)) if xlab is not None: plt.xlabel(xlab) if ylab is not None: plt.ylabel(ylab) plt.axis('auto') if cbar is not None: plt.colorbar(orientation=cbar) return
def createMeshPatches(ax, mesh, verbose=True): """Utility function to create 2d mesh patches within a given ax.""" if not mesh: pg.error("drawMeshBoundaries(ax, mesh): invalid mesh:", mesh) return if mesh.nodeCount() < 2: pg.error("drawMeshBoundaries(ax, mesh): to few nodes:", mesh) return pg.tic() polys = [_createCellPolygon(c) for c in mesh.cells()] patches = mpl.collections.PolyCollection(polys, picker=True) if verbose: pg.info("Creation of mesh patches took = ", pg.toc()) return patches
def startModel(self, model): """ model: [float] | float Model used as starting model. Float value is used as constant model. """ if model is None: self._startModel = None elif isinstance(model, float) or isinstance(model, int): self._startModel = np.ones(self.parameterCount) * float(model) pg.info("Startmodel set from given value.", float(model)) elif hasattr(model, '__iter__'): if len(model) == self.parameterCount: pg.info("Startmodel set from given array.", model) self._startModel = model else: pg.error("Startmodel size invalid {0} != {0}.".format( len(model), self.parameterCount))
def drawSlice(ax, mesh, normal=[1, 0, 0], **kwargs): """ Parameters ---------- ax: pyvista.Plotter The Plotter to draw on. mesh: pg.Mesh The mesh to take the slice out of. normal: list [[1, 0, 0]] Coordinates to orientate the slice. Returns ------- ax: pyvista.Plotter The plotter containing the mesh and drawn electrode positions. Note ---- Possible kwargs are: normal: tuple(float), str origin: tuple(float) generate_triangles: bool, optional contour: bool, optional They can be found at https://docs.pyvista.org/core/filters.html#pyvista.CompositeFilters.slice """ label = kwargs.pop('label', None) data = kwargs.pop('data', None) mesh = pgMesh2pvMesh(mesh, data, label) try: single_slice = mesh.slice(normal, **kwargs) except AssertionError as e: # 'contour' kwarg only works with point data and breaks execution pg.error(e) else: # REVIEW: bounds and axes might be confused with the outline..?! outline = mesh.outline() ax.add_mesh(outline, color="k") ax.add_mesh(single_slice) return ax
def createMeshPatches(ax, mesh, verbose=True, rasterized=False): """Utility function to create 2d mesh patches within a given ax.""" if not mesh: pg.error("drawMeshBoundaries(ax, mesh): invalid mesh:", mesh) return if mesh.nodeCount() < 2: pg.error("drawMeshBoundaries(ax, mesh): to few nodes:", mesh) return pg.tic() polys = [_createCellPolygon(c) for c in mesh.cells()] patches = mpl.collections.PolyCollection(polys, picker=True, rasterized=rasterized) if verbose: pg.info("Creation of mesh patches took = ", pg.toc()) return patches
def _drawField(ax, mesh, data, kwargs): ### kwargs as reference here to set defaults valid outside too validData = True if len(data) == mesh.cellCount(): kwargs['nCols'] = kwargs.pop('nCols', 256) gci = drawModel(ax, mesh, data, **kwargs) elif len(data) == mesh.nodeCount(): kwargs['nLevs'] = kwargs.pop('nLevs', 5) kwargs['nCols'] = kwargs.pop('nCols', kwargs['nLevs'] - 1) gci = drawField(ax, mesh, data, **kwargs) else: pg.error("Data size invalid") print("Data: ", len(data), min(data), max(data), pg.core.haveInfNaN(data)) print("Mesh: ", mesh) validData = False drawMesh(ax, mesh) return gci, validData
def createPath(pathList): """Create the path structure specified by list. Parameters ---------- pathList: str | list(str) Create Path with option subpaths """ if hasattr(pathList, '__iter__'): path = os.path.join('', *pathList) else: path = os.path.join('', pathList) try: os.makedirs(path) except FileExistsError: print(f'Path {path} already exists. Skipping') except OSError as e: pg.error(f'Unable to create path "{path}".') raise e return path
def fixLayers(self, fixLayers): """Fix layer thicknesses. Parameters ---------- fixLayers : bool | [float] Fix all layers to the last value or set the fix layer thickness for all layers """ if fixLayers is False: self.fop.setRegionProperties(0, modelControl=1.0) elif fixLayers is not None: # how do we fix values without modelControl? # maybe set the region to be fixed here self.fop.setRegionProperties(0, modelControl=1e6) if hasattr(fixLayers, '__iter__'): if len(fixLayers) != self.fop.nLayers: print("fixLayers:", fixLayers) pg.error("fixlayers needs to have a length of nLayers-1=" + str(self.fop.nLayers - 1)) self.fop.setRegionProperties(0, startModel=fixLayers)
def valHash(a): if isinstance(a, str): return strHash(a) elif isinstance(a, int): return a elif isinstance(a, list): hsh = 0 for item in a: hsh = hsh ^ valHash(item) return hsh elif isinstance(a, np.ndarray): if a.ndim == 1: return hash(pg.Vector(a)) elif a.ndim == 2: # convert to RVector to use memcopy return hash(pg.Vector(a.reshape((1,a.shape[0]*a.shape[1]))[0])) else: print(a) pg.error('no hash for numpy array') return hash(a)
def createPath(pathList): """Create the path structure specified by list. Parameters ---------- pathList: str | list(str) Create Path with option subpaths """ if hasattr(pathList, '__iter__'): path = os.path.join('', *pathList) else: path = os.path.join('', pathList) try: os.makedirs(path) except OSError as e: if os.path.exists(path): print('Path "{}" already exists.'.format(path)) else: pg.error('Unable to create path "{}".'.format(path)) raise e return path
def convertStartModel(self, model): """Convert scalar or array into startmodel with valid range or self.fop.parameterCount, if possible. Attributes ---------- model: float|int|array|None """ if model is None: return None elif isinstance(model, float) or isinstance(model, int): pg.info("Homogeneous starting model set to:", float(model)) return np.full(self.fop.parameterCount, float(model)) elif hasattr(model, '__iter__'): if len(model) == self.fop.parameterCount: pg.info("Starting model set from given array.", model) return model else: pg.error("Starting model size invalid {0} != {1}.". format(len(model), self.fop.parameterCount)) return None
def createCrossholeData(sensors): """ Create crosshole scheme assuming two boreholes with equal sensor numbers. Parameters ---------- sensors : array (Nx2) Array with position of sensors. Returns ------- scheme : DataContainer Data container with `sensors` predefined sensor indices 's' and 'g' for shot and receiver numbers. """ from itertools import product if len(sensors) % 2 > 0: pg.error("createCrossholeData is only defined for an equal number of" " sensors in two boreholes.") n = len(sensors) // 2 numbers = np.arange(n) rays = np.array(list(product(numbers, numbers + n))) # Empty container scheme = pg.DataContainer() # Add sensors for sen in sensors: scheme.createSensor(sen) # Add measurements scheme.resize(len(rays)) scheme["s"] = rays[:, 0] scheme["g"] = rays[:, 1] scheme["valid"] = np.ones(len(rays)) scheme.registerSensorIndex("s") scheme.registerSensorIndex("g") return scheme
def unit(name, unit='auto'): """ Return the name of a physical quantity with its unit. TODO ---- * example * localization Parameters ---------- """ q = quantity(name) if unit == 'auto' and q is None: ## fall back if the name is given instead of the abbreviation print(quants) pg.error('Please give abbreviation or full name ' 'for the quantity name: {0}'.format(name)) else: if rc['lang'] == 'german' or rc['lang'] == 'de' or rc['lang'] == 'ger': name = q['ger'] else: name = q['name'] if unit == 'auto': unit = q['unit'] if unit is None: return '{0}'.format(name) if rc['unitStyle'] == 1 or \ rc['lang'] == 'german' or rc['lang'] == 'de' or rc['lang'] == 'ger': return '{0} in {1}'.format(name, unit) elif rc['unitStyle'] == 2: return '{0} ({1})'.format(name, unit) elif rc['unitStyle'] == 3: return '{0} [{1}]'.format(name, unit)
def readGmsh(fname, verbose=False): r"""Read :term:`Gmsh` ASCII file and return instance of GIMLI::Mesh class. Parameters ---------- fname : string Filename of the file to read (\\*.msh). The file must conform to the `MSH ASCII file version 2 <http://gmsh.info/doc/texinfo/gmsh.html#MSH-ASCII-file-format>`_ format verbose : boolean, optional Be verbose during import. Notes ----- Physical groups specified in Gmsh are interpreted as follows: - Points with the physical number 99 are interpreted as sensors. - Physical Lines and Surfaces define boundaries in 2D and 3D, respectively. - Physical Number 1: Homogeneous Neumann condition - Physical Number 2: Mixed boundary condition - Physical Number 3: Homogeneous Dirichlet condition - Physical Number 4: Dirichlet condition - Physical Surfaces and Volumes define regions in 2D and 3D, respectively. - Physical Number 1: No inversion region - Physical Number >= 2: Inversion region Examples -------- >>> import tempfile, os >>> from pygimli.meshtools import readGmsh >>> gmsh = ''' ... $MeshFormat ... 2.2 0 8 ... $EndMeshFormat ... $Nodes ... 3 ... 1 0 0 0 ... 2 0 1 0 ... 3 1 1 0 ... $EndNodes ... $Elements ... 7 ... 1 15 2 0 1 1 ... 2 15 2 0 2 2 ... 3 15 2 0 3 3 ... 4 1 2 0 1 2 3 ... 5 1 2 0 2 3 1 ... 6 1 2 0 3 1 2 ... 7 2 2 0 5 1 2 3 ... $EndElements ... ''' >>> fname = tempfile.mktemp() >>> with open(fname, "w") as f: ... f.writelines(gmsh) >>> mesh = readGmsh(fname) >>> print(mesh) Mesh: Nodes: 3 Cells: 1 Boundaries: 3 >>> os.remove(fname) """ inNodes, inElements, ncount = 0, 0, 0 fid = open(fname) if verbose: print('Reading %s... \n' % fname) for line in fid: if line[0] == '$': if line.find('Nodes') > 0: inNodes = 1 if line.find('EndNodes') > 0: inNodes = 0 if line.find('Elements') > 0: inElements = 1 if line.find('EndElements') > 0: inElements = 0 else: if inNodes == 1: if len(line.split()) == 1: nodes = np.zeros((int(line), 3)) if verbose: print(' Nodes: %s' % int(line)) else: nodes[ncount, :] = np.array(line.split(), 'float')[1:] ncount += 1 elif inElements == 1: if len(line.split()) == 1: if verbose: print(' Entries: %s' % int(line)) points, lines, triangles, tets = [], [], [], [] else: entry = [int(e_) for e_ in line.split()][1:] if entry[0] == 15: points.append((entry[-2], entry[-3])) elif entry[0] == 1: lines.append((entry[-2], entry[-1], entry[2])) elif entry[0] == 2: triangles.append((entry[-3], entry[-2], entry[-1], entry[2])) elif entry[0] == 4: tets.append((entry[-4], entry[-3], entry[-2], entry[-1], entry[2])) elif entry[0] in [3, 6]: pg.error("Qudrangles and prisms are not supported yet.") fid.close() lines = np.asarray(lines) triangles = np.asarray(triangles) tets = np.asarray(tets) if verbose: print(' Points: %s' % len(points)) print(' Lines: %s' % len(lines)) print(' Triangles: %s' % len(triangles)) print(' Tetrahedra: %s \n' % len(tets)) print('Creating mesh object... \n') # check dimension if len(tets) == 0: dim, bounds, cells = 2, lines, triangles zero_dim = np.abs(nodes.sum(0)).argmin() # identify zero dimension else: dim, bounds, cells = 3, triangles, tets if verbose: print(' Dimension: %s-D' % dim) # creating instance of GIMLI::Mesh class mesh = pg.Mesh(dim) # replacing boundary markers (gmsh does not allow negative phys. regions) bound_marker = (pg.MARKER_BOUND_HOMOGEN_NEUMANN, pg.MARKER_BOUND_MIXED, pg.MARKER_BOUND_HOMOGEN_DIRICHLET, pg.MARKER_BOUND_DIRICHLET) if bounds.any(): for i in range(4): bounds[:, dim][bounds[:, dim] == i + 1] = bound_marker[i] # account for CEM markers bounds[:, dim][bounds[:, dim] >= 10000] *= -1 if verbose: bound_types = np.unique(bounds[:, dim]) print(' Boundary types: %s ' % len(bound_types) + str( tuple(bound_types))) else: print("WARNING: No boundary conditions found.", "Setting Neumann on the outer edges by default.") if verbose: regions = np.unique(cells[:, dim + 1]) print(' Regions: %s ' % len(regions) + str(tuple(regions))) for node in nodes: if dim == 2: mesh.createNode(node[0], node[3 - zero_dim], 0) else: mesh.createNode(node) for cell in cells: if dim == 2: mesh.createTriangle( mesh.node(int(cell[0] - 1)), mesh.node(int(cell[1] - 1)), mesh.node(int(cell[2] - 1)), marker=int(cell[3])) else: mesh.createTetrahedron( mesh.node(int(cell[0] - 1)), mesh.node(int(cell[1] - 1)), mesh.node(int(cell[2] - 1)), mesh.node(int(cell[3] - 1)), marker=int(cell[4])) mesh.createNeighbourInfos() # Set Neumann on outer edges by default (can be overriden by Gmsh info) for b in mesh.boundaries(): if not b.leftCell() or not b.rightCell(): b.setMarker(pg.MARKER_BOUND_HOMOGEN_NEUMANN) for bound in bounds: if dim == 2: mesh.createEdge( mesh.node(int(bound[0] - 1)), mesh.node(int(bound[1] - 1)), marker=int(bound[2])) else: mesh.createTriangleFace( mesh.node(int(bound[0] - 1)), mesh.node(int(bound[1] - 1)), mesh.node(int(bound[2] - 1)), marker=int(bound[3])) # assign marker to corresponding nodes (sensors, reference nodes, etc.) if points: for point in points: mesh.node(point[0] - 1).setMarker(-point[1]) if verbose: if points: points = np.asarray(points) node_types = np.unique(points[:, 1]) print(' Marked nodes: %s ' % len(points) + str(tuple(node_types))) print('\nDone. \n') print(' ' + str(mesh)) return mesh
def run(self, dataVals, errorVals, **kwargs): """Run inversion. The inversion will always start from the starting model taken from the forward operator. If you want to run the inversion from a specified prior model, e.g., from a other run, set this model as starting model to the FOP (fop.setStartModel). Any self.inv.setModel() settings will be overwritten. Parameters ---------- dataVals : iterable Data values errorVals : iterable Relative error values. dv / v Keyword Arguments ----------------- maxIter : int Overwrite class settings for maximal iterations number. dPhi : float [1] Overwrite class settings for delta data phi aborting criteria. Default is 1% """ self.reset() if self.isFrameWork: pg.critical('in use?') return self._inv.run(dataVals, errorVals, **kwargs) if self.fop is None: raise Exception( "Need a valid forward operator for the inversion run.") maxIter = kwargs.pop('maxIter', self.maxIter) minDPhi = kwargs.pop('dPhi', self.minDPhi) self.verbose = kwargs.pop('verbose', self.verbose) self.debug = kwargs.pop('debug', self.debug) self.robustData = kwargs.pop('robustData', False) lam = kwargs.pop('lam', 20) progress = kwargs.pop('progress', None) showProgress = kwargs.pop('showProgress', False) self.inv.setTransModel(self.fop.modelTrans) self.dataVals = dataVals self.errorVals = errorVals sm = kwargs.pop('startModel', None) if sm is not None: self.startModel = sm self.inv.setData(self._dataVals) self.inv.setRelativeError(self._errorVals) self.inv.setLambda(lam) # temporary set max iter to one for the initial run call maxIterTmp = self.maxIter self.maxIter = 1 if self.verbose: pg.info('Starting inversion.') print("fop:", self.inv.fop()) if isinstance(self.dataTrans, pg.trans.TransCumulative): print("Data transformation (cumulative):") for i in range(self.dataTrans.size()): print("\t", i, self.dataTrans.at(i)) else: print("Data transformation:", self.dataTrans) if isinstance(self.modelTrans, pg.trans.TransCumulative): print("Model transformation (cumulative):") for i in range(self.modelTrans.size()): if i < 10: print("\t", i, self.modelTrans.at(i)) else: print(".", end='') else: print("Model transformation:", self.modelTrans) print("min/max (data): {0}/{1}".format(pf(min(self._dataVals)), pf(max(self._dataVals)))) print("min/max (error): {0}%/{1}%".format( pf(100 * min(self._errorVals)), pf(100 * max(self._errorVals)))) print("min/max (start model): {0}/{1}".format( pf(min(self.startModel)), pf(max(self.startModel)))) ### To ensure reproduceability of the run() call inv.start() will ### reset self.inv.model() to fop.startModel(). self.fop.setStartModel(self.startModel) self.inv.setReferenceModel(self.startModel) if self.verbose: print("-" * 80) if self._preStep and callable(self._preStep): self._preStep(0, self) self.inv.start() self.maxIter = maxIterTmp if self._postStep and callable(self._postStep): self._postStep(0, self) if showProgress: self.showProgress(showProgress) lastPhi = self.phi() self.chi2History = [self.chi2()] self.modelHistory = [self.startModel] for i in range(1, maxIter): if self._preStep and callable(self._preStep): self._preStep(i, self) if self.verbose: print("-" * 80) print("inv.iter", i + 1, "... ", end='') try: self.inv.oneStep() except RuntimeError as e: print(e) pg.error('One step failed. ' 'Aborting and going back to last model') if np.isnan(self.model).any(): print(model) pg.critical('invalid model') resp = self.inv.response() chi2 = self.inv.chi2() self.chi2History.append(chi2) self.modelHistory.append(self.model) if showProgress: self.showProgress(showProgress) if self._postStep and callable(self._postStep): self._postStep(i, self) ### we need to check the following before oder after chi2 calc?? self.inv.setLambda(self.inv.getLambda() * self.inv.lambdaFactor()) if self.robustData: self.inv.robustWeighting() if self.inv.blockyModel(): self.inv.constrainBlocky() phi = self.phi() dPhi = phi / lastPhi if self.verbose: print("chi² = {0} (dPhi = {1}%) lam: {2}".format( round(chi2, 2), round((1 - dPhi) * 100, 2), self.inv.getLambda())) if chi2 <= 1 and self.stopAtChi1: print("\n") if self.verbose: pg.boxprint("Abort criterion reached: chi² <= 1 (%.2f)" % chi2) break if (dPhi > (1.0 - minDPhi / 100.0)) and i > 2: # if dPhi < -minDPhi: if self.verbose: pg.boxprint( "Abort criteria reached: dPhi = {0} (< {1}%)".format( round((1 - dPhi) * 100, 2), minDPhi)) break lastPhi = phi ### will never work as expected until we unpack kwargs .. any idea for # better strategy? # if len(kwargs.keys()) > 0: # print("Warning! unused keyword arguments", kwargs) self.model = self.inv.model() return self.model
def show(mesh=None, data=None, **kwargs): """Mesh and model visualization. Syntactic sugar to show a mesh with data. Forwards to :py:mod:`pygimli.viewer.showMesh` or :py:mod:`pygimli.viewer.mayaview.showMesh3D` to show most of the typical 2D and 3D content. See tutorials and examples for usage hints. An empty show call create an empty ax window. Parameters ---------- mesh : :gimliapi:`GIMLI::Mesh` or list of meshes 2D or 3D GIMLi mesh **kwargs : * fitView : bool [True] Scale x and y limits to match the view. * ax : axe [None] Matplotlib axes object. Create a new if necessary. * Will be forwarded to the appropriate show functions. Returns ------- Return the results from the showMesh* functions. See Also -------- showMesh """ if "axes" in kwargs: print("Deprecation Warning: Please use keyword `ax` instead of `axes`") kwargs['ax'] = kwargs.pop('axes', None) if isinstance(mesh, list): ax = kwargs.pop('ax', None) fitView = kwargs.pop('fitView', True) ax, cbar = show(mesh[0], data, hold=1, ax=ax, fitView=fitView, **kwargs) xmin = mesh[0].xmin() xmax = mesh[0].xmax() ymin = mesh[0].ymin() ymax = mesh[0].ymax() for m in mesh[1:]: ax, cbar = show(m, data, ax=ax, hold=1, fitView=False, **kwargs) xmin = min(xmin, m.xmin()) xmax = max(xmax, m.xmax()) ymin = min(ymin, m.ymin()) ymax = max(ymax, m.ymax()) # ax.relim() # ax.autoscale_view(tight=True) if fitView is not False: ax.set_xlim([xmin, xmax]) ax.set_ylim([ymin, ymax]) # print(ax.get_data_interval()) return ax, cbar if isinstance(mesh, pg.Mesh): if mesh.dim() == 2: if pg.zero(pg.y(mesh)): pg.info("swap z<->y coordinates for visualization.") meshSwap = pg.Mesh(mesh) for n in meshSwap.nodes(): n.pos()[1] = n.pos()[2] return showMesh(meshSwap, data, **kwargs) return showMesh(mesh, data, **kwargs) elif mesh.dim() == 3: from .mayaview import showMesh3D return showMesh3D(mesh, data, **kwargs) else: pg.error("ERROR: Mesh not valid.", mesh) ax = kwargs.pop('ax', None) if ax is None: ax = plt.subplots()[1] return ax, None
def drawModel(ax, mesh, data=None, logScale=True, cMin=None, cMax=None, xlabel=None, ylabel=None, verbose=False, tri=False, rasterized=False, **kwargs): """Draw a 2d mesh and color the cell by the data. Parameters ---------- mesh : :gimliapi:`GIMLI::Mesh` The plotted mesh to browse through. ax : mpl axis instance, optional Axis instance where the mesh is plotted (default is current axis). data : array, optional Data to draw. Should either equal numbers of cells or nodes of the corresponding `mesh`. tri : boolean, optional use MPL tripcolor (experimental) rasterized : boolean, optional Rasterize mesh patches to reduce file size and avoid zooming artifacts in some PDF viewers. **kwargs : Additional keyword arguments Will be forwarded to the draw functions and matplotlib methods, respectively. Returns ------- gci : matplotlib graphics object Examples -------- >>> import numpy as np >>> import matplotlib.pyplot as plt >>> import pygimli as pg >>> from pygimli.mplviewer import drawModel >>> n = np.linspace(0, -2, 11) >>> mesh = pg.createGrid(x=n, y=n) >>> mx = pg.x(mesh.cellCenter()) >>> my = pg.y(mesh.cellCenter()) >>> data = np.cos(1.5 * mx) * np.sin(1.5 * my) >>> fig, ax = plt.subplots() >>> drawModel(ax, mesh, data) <matplotlib.collections.PolyCollection object at ...> """ # deprecated .. remove me if 'cMap' in kwargs or 'cmap' in kwargs: pg.warn('cMap|cmap argument is deprecated for draw functions. ' + 'Please use show or customize a colorbar.') # deprecated .. remove me if mesh.nodeCount() == 0: pg.error("drawModel: The mesh is empty.", mesh) if tri: gci = drawMPLTri(ax, mesh, data, cMin=cMin, cMax=cMax, logScale=logScale, **kwargs) else: gci = pg.mplviewer.createMeshPatches(ax, mesh, verbose=verbose, rasterized=rasterized) ax.add_collection(gci) if data is None: data = pg.RVector(mesh.cellCount()) if len(data) != mesh.cellCount(): print(data, mesh) pg.info("drawModel have wrong data length .. " + " indexing data from cellMarkers()") viewdata = data[mesh.cellMarkers()] else: viewdata = data if min(data) <= 0: logScale = False pg.mplviewer.setMappableData(gci, viewdata, cMin=cMin, cMax=cMax, logScale=logScale) gci.set_antialiased(True) gci.set_linewidths(0.1) gci.set_edgecolors("face") if xlabel is not None: ax.set_xlabel(xlabel) if ylabel is not None: ax.set_ylabel(ylabel) if kwargs.pop('fitView', True): ax.set_xlim(mesh.xmin(), mesh.xmax()) ax.set_ylim(mesh.ymin(), mesh.ymax()) ax.set_aspect('equal') updateAxes_(ax) return gci
def show(mesh=None, data=None, **kwargs): """Mesh and model visualization. Syntactic sugar to show a mesh with data. Forwards to :py:mod:`pygimli.viewer.showMesh` or :py:mod:`pygimli.viewer.mayaview.showMesh3D` to show most of the typical 2D and 3D content. See tutorials and examples for usage hints. An empty show call creates an empty ax window. Parameters ---------- mesh : :gimliapi:`GIMLI::Mesh` or list of meshes 2D or 3D GIMLi mesh **kwargs : * fitView : bool [True] Scale x and y limits to match the view. * ax : axe [None] Matplotlib axes object. Create a new if necessary. * Will be forwarded to the appropriate show functions. Returns ------- Return the results from the showMesh* functions. See Also -------- showMesh """ if "axes" in kwargs: print("Deprecation Warning: Please use keyword `ax` instead of `axes`") kwargs['ax'] = kwargs.pop('axes', None) if isinstance(mesh, list): ax = kwargs.pop('ax', None) fitView = kwargs.pop('fitView', True) ax, cbar = show(mesh[0], data, hold=1, ax=ax, fitView=fitView, **kwargs) xmin = mesh[0].xmin() xmax = mesh[0].xmax() ymin = mesh[0].ymin() ymax = mesh[0].ymax() for m in mesh[1:]: ax, cbar = show(m, data, ax=ax, hold=1, fitView=False, **kwargs) xmin = min(xmin, m.xmin()) xmax = max(xmax, m.xmax()) ymin = min(ymin, m.ymin()) ymax = max(ymax, m.ymax()) # ax.relim() # ax.autoscale_view(tight=True) if fitView is not False: ax.set_xlim([xmin, xmax]) ax.set_ylim([ymin, ymax]) # print(ax.get_data_interval()) return ax, cbar if isinstance(mesh, pg.Mesh): if mesh.dim() == 2: if pg.zero(pg.y(mesh)): pg.info("swap z<->y coordinates for visualization.") meshSwap = pg.Mesh(mesh) for n in meshSwap.nodes(): n.pos()[1] = n.pos()[2] return showMesh(meshSwap, data, **kwargs) return showMesh(mesh, data, **kwargs) elif mesh.dim() == 3: from .mayaview import showMesh3D return showMesh3D(mesh, data, **kwargs) else: pg.error("ERROR: Mesh not valid.", mesh) ax = kwargs.pop('ax', None) if ax is None: ax = plt.subplots()[1] return ax, None
def readGmsh(fname, verbose=False): r"""Read :term:`Gmsh` ASCII file and return instance of GIMLI::Mesh class. Parameters ---------- fname : string Filename of the file to read (\\*.msh). The file must conform to the `MSH ASCII file version 2 <http://gmsh.info/doc/texinfo/gmsh.html#MSH-ASCII-file-format>`_ format verbose : boolean, optional Be verbose during import. Notes ----- Physical groups specified in Gmsh are interpreted as follows: - Points with the physical number 99 are interpreted as sensors. - Physical Lines and Surfaces define boundaries in 2D and 3D, respectively. - Physical Number 1: Homogeneous Neumann condition - Physical Number 2: Mixed boundary condition - Physical Number 3: Homogeneous Dirichlet condition - Physical Number 4: Dirichlet condition - Physical Surfaces and Volumes define regions in 2D and 3D, respectively. - Physical Number 1: No inversion region - Physical Number >= 2: Inversion region Examples -------- >>> import tempfile, os >>> from pygimli.meshtools import readGmsh >>> gmsh = ''' ... $MeshFormat ... 2.2 0 8 ... $EndMeshFormat ... $Nodes ... 3 ... 1 0 0 0 ... 2 0 1 0 ... 3 1 1 0 ... $EndNodes ... $Elements ... 7 ... 1 15 2 0 1 1 ... 2 15 2 0 2 2 ... 3 15 2 0 3 3 ... 4 1 2 0 1 2 3 ... 5 1 2 0 2 3 1 ... 6 1 2 0 3 1 2 ... 7 2 2 0 5 1 2 3 ... $EndElements ... ''' >>> fname = tempfile.mktemp() >>> with open(fname, "w") as f: ... f.writelines(gmsh) >>> mesh = readGmsh(fname) >>> print(mesh) Mesh: Nodes: 3 Cells: 1 Boundaries: 3 >>> os.remove(fname) """ inNodes, inElements, ncount = 0, 0, 0 fid = open(fname) if verbose: print('Reading %s... \n' % fname) for line in fid: if line[0] == '$': if line.find('Nodes') > 0: inNodes = 1 if line.find('EndNodes') > 0: inNodes = 0 if line.find('Elements') > 0: inElements = 1 if line.find('EndElements') > 0: inElements = 0 else: if inNodes == 1: if len(line.split()) == 1: nodes = np.zeros((int(line), 3)) if verbose: print(' Nodes: %s' % int(line)) else: nodes[ncount, :] = np.array(line.split(), 'float')[1:] ncount += 1 elif inElements == 1: if len(line.split()) == 1: if verbose: print(' Entries: %s' % int(line)) points, lines, triangles, tets = [], [], [], [] else: entry = [int(e_) for e_ in line.split()][1:] if entry[0] == 15: points.append((entry[-2], entry[-3])) elif entry[0] == 1: lines.append((entry[-2], entry[-1], entry[2])) elif entry[0] == 2: triangles.append( (entry[-3], entry[-2], entry[-1], entry[2])) elif entry[0] == 4: tets.append((entry[-4], entry[-3], entry[-2], entry[-1], entry[2])) elif entry[0] in [3, 6]: pg.error( "Qudrangles and prisms are not supported yet.") fid.close() lines = np.asarray(lines) triangles = np.asarray(triangles) tets = np.asarray(tets) if verbose: print(' Points: %s' % len(points)) print(' Lines: %s' % len(lines)) print(' Triangles: %s' % len(triangles)) print(' Tetrahedra: %s \n' % len(tets)) print('Creating mesh object... \n') # check dimension if len(tets) == 0: dim, bounds, cells = 2, lines, triangles zero_dim = np.abs(nodes.sum(0)).argmin() # identify zero dimension else: dim, bounds, cells = 3, triangles, tets if verbose: print(' Dimension: %s-D' % dim) # creating instance of GIMLI::Mesh class mesh = pg.Mesh(dim) # replacing boundary markers (gmsh does not allow negative phys. regions) bound_marker = (pg.MARKER_BOUND_HOMOGEN_NEUMANN, pg.MARKER_BOUND_MIXED, pg.MARKER_BOUND_HOMOGEN_DIRICHLET, pg.MARKER_BOUND_DIRICHLET) if bounds.any(): for i in range(4): bounds[:, dim][bounds[:, dim] == i + 1] = bound_marker[i] # account for CEM markers bounds[:, dim][bounds[:, dim] >= 10000] *= -1 if verbose: bound_types = np.unique(bounds[:, dim]) print(' Boundary types: %s ' % len(bound_types) + str(tuple(bound_types))) else: print("WARNING: No boundary conditions found.", "Setting Neumann on the outer edges by default.") if verbose: regions = np.unique(cells[:, dim + 1]) print(' Regions: %s ' % len(regions) + str(tuple(regions))) for node in nodes: if dim == 2: mesh.createNode(node[0], node[3 - zero_dim], 0) else: mesh.createNode(node) for cell in cells: if dim == 2: mesh.createTriangle(mesh.node(int(cell[0] - 1)), mesh.node(int(cell[1] - 1)), mesh.node(int(cell[2] - 1)), marker=int(cell[3])) else: mesh.createTetrahedron(mesh.node(int(cell[0] - 1)), mesh.node(int(cell[1] - 1)), mesh.node(int(cell[2] - 1)), mesh.node(int(cell[3] - 1)), marker=int(cell[4])) mesh.createNeighbourInfos() # Set Neumann on outer edges by default (can be overriden by Gmsh info) for b in mesh.boundaries(): if not b.leftCell() or not b.rightCell(): b.setMarker(pg.MARKER_BOUND_HOMOGEN_NEUMANN) for bound in bounds: if dim == 2: mesh.createEdge(mesh.node(int(bound[0] - 1)), mesh.node(int(bound[1] - 1)), marker=int(bound[2])) else: mesh.createTriangleFace(mesh.node(int(bound[0] - 1)), mesh.node(int(bound[1] - 1)), mesh.node(int(bound[2] - 1)), marker=int(bound[3])) # assign marker to corresponding nodes (sensors, reference nodes, etc.) if points: for point in points: mesh.node(point[0] - 1).setMarker(-point[1]) if verbose: if points: points = np.asarray(points) node_types = np.unique(points[:, 1]) print(' Marked nodes: %s ' % len(points) + str(tuple(node_types))) print('\nDone. \n') print(' ' + str(mesh)) return mesh
def response(self, model): """Solve forward task. Create apparent resistivity values for a given resistivity distribution for self.mesh. """ ### NOTE TODO can't be MT until mixed boundary condition depends on ### self.resistivity pg.tic() if not self.data.allNonZero('k'): pg.error('Need valid geometric factors: "k".') pg.warn('Fallback "k" values to -sign("rhoa")') self.data.set('k', -pg.math.sign(self.data('rhoa'))) mesh = self.mesh() nDof = mesh.nodeCount() elecs = self.data.sensorPositions() nEle = len(elecs) nData = self.data.size() self.resistivity = res = self.createMappedModel(model, -1.0) if self.verbose: print("Calculate response for model:", min(res), max(res)) rMin = elecs[0].dist(elecs[1]) / 2.0 rMax = elecs[0].dist(elecs[-1]) * 2.0 k, w = self.getIntegrationWeights(rMin, rMax) self.k = k self.w = w # pg.show(mesh, res, label='res') # pg.wait() rhs = self.createRHS(mesh, elecs) # store all potential fields u = np.zeros((nEle, nDof)) self.subPotentials = [pg.Matrix(nEle, nDof) for i in range(len(k))] for i, ki in enumerate(k): ws = dict() uE = pg.solve(mesh, a=1. / res, b=-(ki * ki) / res, f=rhs, bc={'Robin': ['*', self.mixedBC]}, userData={ 'sourcePos': elecs, 'k': ki }, verbose=False, stats=0, debug=False) self.subPotentials[i] = uE u += w[i] * uE # collect potential matrix, # i.e., potential for all electrodes and all injections pM = np.zeros((nEle, nEle)) for i in range(nEle): pM[i] = pg.interpolate(mesh, u[i, :], destPos=elecs) # collect resistivity values for all 4 pole measurements r = np.zeros(nData) for i in range(nData): iA = int(self.data('a')[i]) iB = int(self.data('b')[i]) iM = int(self.data('m')[i]) iN = int(self.data('n')[i]) uAB = pM[iA] - pM[iB] r[i] = uAB[iM] - uAB[iN] self.lastResponse = r * self.data('k') if self.verbose: print("Resp min/max: {0} {1} {2}s".format(min(self.lastResponse), max(self.lastResponse), pg.dur())) return self.lastResponse
def show(obj=None, data=None, **kwargs): """Mesh and model visualization. Syntactic sugar to show a obj with data. Forwards to a known visualization for obj. Typical is :py:mod:`pygimli.viewer.showMesh` or :py:mod:`pygimli.viewer.mayaview.showMesh3D` to show most of the typical 2D and 3D content. See tutorials and examples for usage hints. An empty show call creates an empty ax window. Parameters ---------- obj: obj obj can be so far. * :gimliapi:`GIMLI::Mesh` or list of meshes * DataContainer * pg.core.Sparse[Map]Matrix data: iterable Optionally data to visualize. See appropriate show function. Keyword Arguments ----------------- **kwargs Additional kwargs forward to appropriate show functions. * ax : axe [None] Matplotlib axes object. Create a new if necessary. * fitView : bool [True] Scale x and y limits to match the view. Returns ------- Return the results from the showMesh* functions. Usually the axe object and a colorbar. See Also -------- showMesh """ if "axes" in kwargs: print("Deprecation Warning: Please use keyword `ax` instead of `axes`") kwargs['ax'] = kwargs.pop('axes', None) if isinstance(obj, pg.DataContainerERT): from pygimli.physics.ert import showERTData return showERTData(obj, vals=kwargs.pop('vals', data), **kwargs) if isinstance(obj, pg.core.MatrixBase): ax, _ = pg.show() return drawMatrix(ax, obj, **kwargs) mesh = kwargs.pop('mesh', obj) if isinstance(mesh, list): ax = kwargs.pop('ax', None) fitView = kwargs.pop('fitView', ax is None) ax, cBar = show(mesh[0], data, hold=1, ax=ax, fitView=fitView, **kwargs) xMin = mesh[0].xMin() xMax = mesh[0].xMax() yMin = mesh[0].yMin() yMax = mesh[0].yMax() for m in mesh[1:]: ax, cBar = show(m, data, ax=ax, hold=1, fitView=False, **kwargs) xMin = min(xMin, m.xMin()) xMax = max(xMax, m.xMax()) yMin = min(yMin, m.yMin()) yMax = max(yMax, m.yMax()) # ax.relim() # ax.autoscale_view(tight=True) if fitView is not False: ax.set_xlim([xMin, xMax]) ax.set_ylim([yMin, yMax]) # print(ax.get_data_interval()) return ax, cBar if isinstance(mesh, pg.Mesh): if mesh.dim() == 2: if pg.zero(pg.y(mesh)): pg.info("swap z<->y coordinates for visualization.") meshSwap = pg.Mesh(mesh) for n in meshSwap.nodes(): n.pos()[1] = n.pos()[2] return showMesh(meshSwap, data, **kwargs) return showMesh(mesh, data, **kwargs) elif mesh.dim() == 3: from .vistaview import showMesh3D return showMesh3D(mesh, data, **kwargs) else: pg.error("ERROR: Mesh not valid.", mesh) ax = kwargs.pop('ax', None) if ax is None: ax = plt.subplots()[1] return ax, None
def showMesh(mesh, data=None, hold=False, block=False, colorBar=None, label=None, coverage=None, ax=None, savefig=None, showMesh=False, showBoundary=None, markers=False, **kwargs): """2D Mesh visualization. Create an axis object and plot a 2D mesh with given node or cell data. Returns the axis and the color bar. The type of data determines the appropriate draw method. Parameters ---------- mesh: :gimliapi:`GIMLI::Mesh` 2D or 3D GIMLi mesh data: iterable [None] Optionally data to visualize. . None (draw mesh only) forward to :py:mod:`pygimli.viewer.mpl.drawMesh` or if no cells are given: forward to :py:mod:`pygimli.viewer.mpl.drawPLC` . [[marker, value], ...] List of Cellvalues per cell marker forward to :py:mod:`pygimli.viewer.mpl.drawModel` . float per cell -- model, patch forward to :py:mod:`pygimli.viewer.mpl.drawModel` . float per node -- scalar field forward to :py:mod:`pygimli.viewer.mpl.drawField` . iterable of type [float, float] -- vector field forward to :py:mod:`pygimli.viewer.mpl.drawStreams` . pg.core.R3Vector -- vector field forward to :py:mod:`pygimli.viewer.mpl.drawStreams` . pg.core.stdVectorRVector3 -- sensor positions forward to :py:mod:`pygimli.viewer.mpl.drawSensors` hold: bool [false] Set interactive plot mode for matplotlib. If this is set to false [default] your script will open a window with the figure and draw your content. If set to true nothing happens until you either force another show with hold=False, you call plt.show() or pg.wait(). If you want show with stopping your script set block = True. block: bool [false] Force show drawing your content and block the script until you close the current figure. colorBar: bool [None], Colorbar Create and show a colorbar. If colorBar is a valid colorbar then only its values will be updated. label: str Set colorbar label. If set colorbar is toggled to True. [None] coverage: iterable [None] Weight data by the given coverage array and fadeout the color. ax: matplotlib.Axes [None] Instead of creating a new and empty ax, just draw into the given one. Useful to combine multiple plots into one figure. savefig: string Filename for a direct save to disc. The matplotlib pdf-output is a little bit big so we try an epstopdf if the .eps suffix is found in savefig showMesh: bool [False] Shows the mesh itself additional. showBoundary: bool [None] Shows all boundary with marker != 0. A value None means automatic True for cell data and False for node data. marker: bool [False] Show mesh and boundary marker. Keyword Arguments ----------------- **kwargs: * xlabel: str [None] Add label to the x axis * ylabel: str [None] Add label to the y axis fitView: bool Fit the axes limits to the view object. Default is True if ax is None else is set to False. All remaining will be forwarded to the draw functions and matplotlib methods, respectively. Examples -------- >>> import pygimli as pg >>> import pygimli.meshtools as mt >>> world = mt.createWorld(start=[-10, 0], end=[10, -10], ... layers=[-3, -7], worldMarker=False) >>> mesh = mt.createMesh(world, quality=32, area=0.2, smooth=[1, 10]) >>> _ = pg.viewer.showMesh(mesh, markers=True) Returns ------- ax : matplotlib.axes colobar : matplotlib.colorbar """ renameKwarg('cmap', 'cMap', kwargs) cMap = kwargs.pop('cMap', 'viridis') nCols = None cBarOrientation = kwargs.pop('orientation', 'horizontal') fitViewDefault = False if ax is None: fitViewDefault = True ax = plt.subplots()[1] # plt.subplots() resets locale setting to system default .. this went # horrible wrong for german 'decimal_point': ',' pg.checkAndFixLocaleDecimal_point(verbose=False) if block: hold = True lastHoldStatus = pg.viewer.mpl.utils.holdAxes__ if not lastHoldStatus or hold: pg.viewer.mpl.hold(val=1) hold = True gci = None validData = False if markers: kwargs["boundaryMarker"] = True if mesh.cellCount() > 0: uniquemarkers, uniqueidx = np.unique(np.array(mesh.cellMarkers()), return_inverse=True) label = "Cell markers" cMap = plt.cm.get_cmap("Set3", len(uniquemarkers)) kwargs["logScale"] = False kwargs["cMin"] = -0.5 kwargs["cMax"] = len(uniquemarkers) - 0.5 data = np.arange(len(uniquemarkers))[uniqueidx] if data is None: showMesh = True mesh.createNeighborInfos() if showBoundary is None: showBoundary = True elif isinstance(data, pg.core.stdVectorRVector3): drawSensors(ax, data, **kwargs) elif isinstance(data, pg.core.R3Vector): drawStreams(ax, mesh, data, **kwargs) else: ### data=[[marker, val], ....] if isinstance(data, list) and \ isinstance(data[0], list) and isinstance(data[0][0], int): data = pg.solver.parseMapToCellArray(data, mesh) if hasattr(data[0], '__len__') and not \ isinstance(data, np.ma.core.MaskedArray): if len(data) == 2: # [u,v] x N data = np.array(data).T if data.shape[1] == 2: drawStreams(ax, mesh, data, **kwargs) elif data.shape[1] == 3: # probably N x [u,v,w] # if sum(data[:, 0]) != sum(data[:, 1]): # drawStreams(ax, mesh, data, **kwargs) drawStreams(ax, mesh, data[:, 0:2], **kwargs) else: pg.warn("No valid stream data:", data.shape, data.ndim) showMesh = True # elif min(data) == max(data): # or pg.core.haveInfNaN(data): # pg.warn("No valid data: ", min(data), max(data), pg.core.haveInfNaN(data)) # showMesh = True else: validData = True if bool(colorBar) is not False: colorBar = True try: if len(data) == mesh.cellCount(): kwargs['nCols'] = kwargs.pop('nCols', 256) if label is None: label = "" gci = drawModel(ax, mesh, data, **kwargs) if showBoundary is None: showBoundary = True elif len(data) == mesh.nodeCount(): kwargs['nLevs'] = kwargs.pop('nLevs', 5) kwargs['nCols'] = kwargs.pop('nCols', kwargs['nLevs'] - 1) if label is None: label = "" gci = drawField(ax, mesh, data, **kwargs) else: pg.error("Data size invalid") print("Data: ", len(data), min(data), max(data), pg.core.haveInfNaN(data)) print("Mesh: ", mesh) validData = False drawMesh(ax, mesh) if cMap is not None and gci is not None: gci.set_cmap(cmapFromName(cMap)) #gci.cmap.set_under('k') except BaseException as e: pg.error("Exception occurred: ", e) if mesh.cellCount() == 0: showMesh = False if mesh.boundaryCount() == 0: pg.viewer.mpl.drawPLC(ax, mesh, showNodes=True, fillRegion=False, showBoundary=False, **kwargs) showBoundary = False #ax.plot(pg.x(mesh), pg.y(mesh), '.', color='black') else: pg.viewer.mpl.drawPLC(ax, mesh, **kwargs) if showMesh: if gci is not None and hasattr(gci, 'set_antialiased'): gci.set_antialiased(True) gci.set_linewidth(0.3) gci.set_edgecolor("0.1") else: pg.viewer.mpl.drawSelectedMeshBoundaries(ax, mesh.boundaries(), color=kwargs.pop( 'color', "0.1"), linewidth=0.3) #drawMesh(ax, mesh, **kwargs) if showBoundary == True or showBoundary == 1: b = mesh.boundaries(mesh.boundaryMarkers() != 0) pg.viewer.mpl.drawSelectedMeshBoundaries(ax, b, color=(0.0, 0.0, 0.0, 1.0), linewidth=1.4) fitView = kwargs.pop('fitView', fitViewDefault) if fitView: ax.set_xlim(mesh.xMin(), mesh.xMax()) ax.set_ylim(mesh.yMin(), mesh.yMax()) ax.set_aspect('equal') cBar = None if label is not None and colorBar is None: colorBar = True if colorBar and validData: labels = ['cMin', 'cMax', 'nCols', 'nLevs', 'logScale', 'levels'] subkwargs = {key: kwargs[key] for key in labels if key in kwargs} subkwargs['label'] = label subkwargs['cMap'] = cMap subkwargs['orientation'] = cBarOrientation if bool(colorBar): cBar = createColorBar(gci, size=kwargs.pop('size', 0.2), pad=kwargs.pop('pad', None), **subkwargs) elif colorBar is not False: cBar = updateColorBar(colorBar, **subkwargs) if markers: ticks = np.arange(len(uniquemarkers)) cBar.set_ticks(ticks) labels = [] for marker in uniquemarkers: labels.append(str((marker))) cBar.set_ticklabels(labels) if coverage is not None: if len(data) == mesh.cellCount(): addCoverageAlpha(gci, coverage, dropThreshold=kwargs.pop('dropThreshold', 0.4)) else: raise BaseException('toImplement') # addCoverageAlpha(gci, pg.core.cellDataToPointData(mesh, coverage)) if not hold or block is not False and plt.get_backend().lower() != "agg": if data is not None: if len(data) == mesh.cellCount(): CellBrowser(mesh, data, ax=ax) plt.show(block=block) try: plt.pause(0.01) except BaseException as _: pass if hold: pg.viewer.mpl.hold(val=lastHoldStatus) if savefig: print('saving: ' + savefig + ' ...') if '.' not in savefig: savefig += '.pdf' ax.figure.savefig(savefig, bbox_inches='tight') # rc params savefig.format=pdf if '.eps' in savefig: try: print("trying eps2pdf ... ") os.system('epstopdf ' + savefig) except BaseException: pass print('.. done') return ax, cBar
def testTraceback2(): pg.error("Start error test.: int", 1, " vec", pg.RVector(2))