Skip to content

Instantly share code, notes, and snippets.

@joferkington
Created March 16, 2019 22:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joferkington/dcc3e235f7b6467d183a4e9af5486098 to your computer and use it in GitHub Desktop.
Save joferkington/dcc3e235f7b6467d183a4e9af5486098 to your computer and use it in GitHub Desktop.
"""
Converts one or more zmap grids to ascii x,y,z tab-delimited files. Exported
files will be saved to the current directory with a ".xyz" extension and the
same file name as the original. Null grid values will not be included unless
the "--with_nulls" option is specified.
Usage:
zmap2xyz.py [options] INPUT_FILES...
Options:
-h --help Show this message
--with_nulls Include null grid points in the output
"""
import os
import numpy as np
from docopt import docopt
def main(args):
for filename in args['INPUT_FILES']:
process_file(filename, args['--with_nulls'])
def process_file(filename, include_nulls=False):
x, y, z = grid2xyz(filename)
if include_nulls:
x, y, z = [item.ravel() for item in [x, y, z]]
else:
x, y, z = [item.compressed() for item in [x, y, z]]
base, ext = os.path.splitext(filename)
np.savetxt(base + '.xyz', np.vstack([x, y, z]).T)
def grid2xyz(filename):
grid = ZmapGridReader(filename)
# Note the reversed y-order!! (Grid is flipped up/down)
y, x = np.mgrid[grid.ymax:grid.ymin:1j*grid.nrows,
grid.xmin:grid.xmax:1j*grid.ncols]
x = np.ma.masked_array(x, grid.data.mask)
y = np.ma.masked_array(y, grid.data.mask)
return x, y, grid.data
class ZmapGridReader(object):
def __init__(self, filename):
self.filename = filename
with open(self.filename, 'r') as infile:
values = self._parse_header(infile)
null, nrows, ncols, xmin, xmax, ymin, ymax = values
self.null = float(null)
self.nrows, self.ncols = int(nrows), int(ncols)
self.xmin, self.xmax = float(xmin), float(xmax)
self.ymin, self.ymax = float(ymin), float(ymax)
self.data = self._read_values()
def _skip_comments(self, infile):
while True:
last_position = infile.tell()
if not infile.readline()[0].startswith('!'):
break
infile.seek(last_position)
def _parse_header(self, infile):
def line(infile):
return infile.readline().replace(',', ' ').strip().split()
infile.seek(0)
self._skip_comments(infile)
header = infile.readline()
width, null = line(infile)[:2]
nrows, ncols, xmin, xmax, ymin, ymax = line(infile)[:6] # Trailing ,
return null, nrows, ncols, xmin, xmax, ymin, ymax
def _read_values(self):
def value_iter(infile):
for line in infile:
line = line.strip().split()
for item in line:
yield float(item)
with open(self.filename, 'r') as infile:
for line in infile:
if line.strip() == '@':
break
data = np.fromiter(value_iter(infile), dtype=float)
data = data.reshape(self.ncols, self.nrows).T
return np.ma.masked_equal(data, self.null)
if __name__ == '__main__':
main(docopt(__doc__))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment