Skip to content

Commit

Permalink
Added two new methods, which are just wrappers to numpy.save and nump…
Browse files Browse the repository at this point in the history
…y.load

The idea I had was that since pickling matplotlib figures is so tricky,
it would still be beneficial to be able to generate the figures without having to preprocess everything all over again. So once you have your data analyzed,
dump it into a numpy binary .npy file and load it up in a separate figure generation script.

Added some basic array roundtrip checks, for coverage purposes.
  • Loading branch information
underchemist committed Dec 26, 2015
1 parent a9c9fe0 commit 2b97131
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 4 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,4 @@ cover/keybd_open.png
nanonispy.sublime-project
nanonispy.sublime-workspace
dev_test.py
MANIFEST
MANIFEST.in
conda_build/
67 changes: 65 additions & 2 deletions nanonispy/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@


class NanonisFile:

"""
Base class for Nanonis data files (grid, scan, point spectroscopy).
Expand All @@ -23,6 +24,8 @@ class NanonisFile:
Just the filename, no path.
fname : str
Full path of Nanonis file.
filetype : str
filetype corresponding to filename extension.
byte_offset : int
Size of header in bytes.
header_raw : str
Expand Down Expand Up @@ -121,6 +124,7 @@ def start_byte(self):
return byte_offset

class Grid(NanonisFile):

"""
Nanonis grid file class.
Expand Down Expand Up @@ -252,6 +256,7 @@ def _extract_topo(self):


class Scan(NanonisFile):

"""
Nanonis scan file class.
Expand Down Expand Up @@ -338,6 +343,7 @@ def _load_data(self):


class Spec(NanonisFile):

"""
Nanonis point spectroscopy file class.
Expand Down Expand Up @@ -397,13 +403,15 @@ def _load_data(self):


class UnhandledFileError(Exception):

"""
To be raised when unknown file extension is passed.
"""
pass


class FileHeaderNotFoundError(Exception):

"""
To be raised when no header information could be determined.
"""
Expand Down Expand Up @@ -575,6 +583,63 @@ def _split_header_entry(entry, multiple=False):
return val_str.strip('"')


def save_array(file, arr, allow_pickle=True):
"""
Wrapper to numpy.save method for arrays.
The idea would be to use this to save a processed array for later
use in a matplotlib figure generation scripts. See numpy.save
documentation for details.
Parameters
----------
file : file or str
File or filename to which the data is saved. If file is a file-
object, then the filename is unchanged. If file is a string, a
``.npy`` extension will be appended to the file name if it does
not already have one.
arr : array_like
Array data to be saved.
allow_pickle : bool, optional
Allow saving object arrays using Python pickles. Reasons for
disallowing pickles include security (loading pickled data can
execute arbitrary code) and portability (pickled objects may not
be loadable on different Python installations, for example if
the stored objects require libraries that are not available, and
not all pickled data is compatible between Python 2 and Python
3). Default: True
"""
np.save(file, arr, allow_pickle=allow_pickle)


def load_array(file, allow_pickle=True):
"""
Wrapper to numpy.load method for binary files.
See numpy.load documentation for more details.
Parameters
----------
file : file or str
The file to read. File-like objects must support the
``seek()`` and ``read()`` methods. Pickled files require that the
file-like object support the ``readline()`` method as well.
allow_pickle : bool, optional
Allow loading pickled object arrays stored in npy files. Reasons
for disallowing pickles include security, as loading pickled
data can execute arbitrary code. If pickles are disallowed,
loading object arrays will fail. Default: True
Returns
-------
result : array, tuple, dict, etc.
Data stored in the file. For ``.npz`` files, the returned
instance of NpzFile class must be closed to avoid leaking file
descriptors.
"""
return np.load(file)


def _parse_scan_header_table(table_list):
"""
Parse scan file header entries whose values are tab-separated
Expand All @@ -600,5 +665,3 @@ def _is_valid_file(fname, ext):
"""
if fname[-3:] != ext:
raise UnhandledFileError('{} is not a {} file'.format(fname, ext))


17 changes: 17 additions & 0 deletions nanonispy/tests/test_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,5 +293,22 @@ def test_header_entries(self):
b = ''.join(sorted(test_dict[key]))
self.assertEqual(a, b)


class TestUtilFunctions(unittest.TestCase):

def setUp(self):
self.temp_dir = tempfile.TemporaryDirectory()

def tearDown(self):
self.temp_dir.cleanup()

def test_arr_roundtrip(self):
fname = self.temp_dir.name + '/test_roundtrip.npy'
a = np.linspace(0, 1.00, dtype='>f4')
nap.read.save_array(fname, a)
b = nap.read.load_array(fname)

np.testing.assert_array_equal(a, b)

if __name__ == '__main__':
unittest.main()

0 comments on commit 2b97131

Please sign in to comment.