micress-micpy 0.2.16b0__py3-none-any.whl → 0.3.0b0__py3-none-any.whl
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.
- micpy/bin.py +219 -235
- micpy/geo.py +25 -24
- micpy/matplotlib.py +2 -32
- micpy/tab.py +9 -9
- micpy/utils.py +0 -11
- micpy/version.py +1 -1
- micress_micpy-0.3.0b0.dist-info/METADATA +46 -0
- micress_micpy-0.3.0b0.dist-info/RECORD +12 -0
- micress_micpy-0.2.16b0.dist-info/METADATA +0 -186
- micress_micpy-0.2.16b0.dist-info/RECORD +0 -12
- {micress_micpy-0.2.16b0.dist-info → micress_micpy-0.3.0b0.dist-info}/LICENSE +0 -0
- {micress_micpy-0.2.16b0.dist-info → micress_micpy-0.3.0b0.dist-info}/WHEEL +0 -0
- {micress_micpy-0.2.16b0.dist-info → micress_micpy-0.3.0b0.dist-info}/top_level.txt +0 -0
micpy/bin.py
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""The `micpy.bin` module provides methods to read and write binary files."""
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Callable, IO, List, Tuple,
|
|
4
|
+
from typing import Callable, Generator, IO, List, Optional, Tuple, Union
|
|
5
5
|
|
|
6
6
|
import gzip
|
|
7
7
|
import os
|
|
8
8
|
import sys
|
|
9
|
-
import warnings
|
|
10
9
|
import zlib
|
|
11
10
|
|
|
12
11
|
import numpy as np
|
|
@@ -16,7 +15,7 @@ from micpy import utils
|
|
|
16
15
|
from micpy.matplotlib import matplotlib, pyplot
|
|
17
16
|
|
|
18
17
|
|
|
19
|
-
__all__ = ["File"]
|
|
18
|
+
__all__ = ["File", "Field", "Series", "plot", "PlotArgs"]
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
@dataclass
|
|
@@ -263,9 +262,9 @@ class Index(List[Position]):
|
|
|
263
262
|
class Field(np.ndarray):
|
|
264
263
|
"""A field."""
|
|
265
264
|
|
|
266
|
-
def __new__(cls, data, time: float, spacing: float
|
|
265
|
+
def __new__(cls, data, time: float, spacing: Tuple[float, float, float]):
|
|
267
266
|
obj = np.asarray(data).view(cls)
|
|
268
|
-
obj.time =
|
|
267
|
+
obj.time = time
|
|
269
268
|
obj.spacing = spacing
|
|
270
269
|
return obj
|
|
271
270
|
|
|
@@ -353,221 +352,100 @@ class Field(np.ndarray):
|
|
|
353
352
|
|
|
354
353
|
return Field.from_bytes(field_data, shape=shape, spacing=spacing)
|
|
355
354
|
|
|
356
|
-
def
|
|
357
|
-
"""Write the field to a binary file.
|
|
358
|
-
file.write(self.to_bytes())
|
|
355
|
+
def to_file(self, file: IO[bytes], geometry: bool = True):
|
|
356
|
+
"""Write the field to a binary file.
|
|
359
357
|
|
|
360
|
-
|
|
361
|
-
|
|
358
|
+
Args:
|
|
359
|
+
file (IO[bytes]): Binary file.
|
|
360
|
+
geometry (bool, optional): `True` if geometry should be written, `False`
|
|
361
|
+
otherwise. Defaults to `True`.
|
|
362
|
+
"""
|
|
362
363
|
|
|
363
|
-
|
|
364
|
-
raise ValueError("Invalid plane")
|
|
364
|
+
file.write(self.to_bytes())
|
|
365
365
|
|
|
366
|
-
|
|
366
|
+
if geometry:
|
|
367
|
+
geo_filename, geo_data = geo.build(file.name, self.shape, self.spacing)
|
|
368
|
+
geo.write(geo_filename, geo_data, geo.Type.BASIC)
|
|
367
369
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
reshape_operations = {
|
|
371
|
-
1: lambda data: data.reshape((z, 1)),
|
|
372
|
-
2: lambda data: data.reshape((z, x)),
|
|
373
|
-
3: lambda data: data,
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
data = reshape_operations[dimensions](self)
|
|
377
|
-
|
|
378
|
-
slice_operations = {
|
|
379
|
-
1: {
|
|
380
|
-
"xz": lambda data: data,
|
|
381
|
-
"zx": lambda data: data.T,
|
|
382
|
-
"xy": lambda data: data[slice_id : slice_id + 1],
|
|
383
|
-
"yx": lambda data: data[slice_id : slice_id + 1],
|
|
384
|
-
"zy": lambda data: data.T,
|
|
385
|
-
"yz": lambda data: data,
|
|
386
|
-
},
|
|
387
|
-
2: {
|
|
388
|
-
"xz": lambda data: data,
|
|
389
|
-
"zx": lambda data: data.T,
|
|
390
|
-
"xy": lambda data: data[slice_id : slice_id + 1],
|
|
391
|
-
"yx": lambda data: data[slice_id : slice_id + 1].T,
|
|
392
|
-
"zy": lambda data: data.T[slice_id : slice_id + 1],
|
|
393
|
-
"yz": lambda data: data.T[slice_id : slice_id + 1].T,
|
|
394
|
-
},
|
|
395
|
-
3: {
|
|
396
|
-
"xy": lambda data: data[slice_id, :, :],
|
|
397
|
-
"yx": lambda data: data[slice_id, :, :].T,
|
|
398
|
-
"xz": lambda data: data[:, slice_id, :],
|
|
399
|
-
"zx": lambda data: data[:, slice_id, :].T,
|
|
400
|
-
"yz": lambda data: data[:, :, slice_id],
|
|
401
|
-
"zy": lambda data: data[:, :, slice_id].T,
|
|
402
|
-
},
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
return slice_operations[dimensions][plane](data)
|
|
406
|
-
|
|
407
|
-
# pylint: disable=too-many-arguments
|
|
408
|
-
def plot(
|
|
370
|
+
def write(
|
|
409
371
|
self,
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
xlabel: str = None,
|
|
414
|
-
ylabel: str = None,
|
|
415
|
-
figsize: Tuple[float, float] = None,
|
|
416
|
-
dpi: int = None,
|
|
417
|
-
aspect: str = "equal",
|
|
418
|
-
ax: "matplotlib.Axes" = None,
|
|
419
|
-
cax: "matplotlib.Axes" = None,
|
|
420
|
-
vmin: float = None,
|
|
421
|
-
vmax: float = None,
|
|
422
|
-
cmap: str = "micpy",
|
|
372
|
+
filename: str,
|
|
373
|
+
compressed: bool = True,
|
|
374
|
+
geometry: bool = True,
|
|
423
375
|
):
|
|
424
|
-
"""
|
|
376
|
+
"""Write the field to a binary file.
|
|
425
377
|
|
|
426
378
|
Args:
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
figsize (Tuple[float, float], optional): Figure size. Defaults to None (auto).
|
|
433
|
-
dpi (int, optional): Figure DPI. Defaults to None (auto).
|
|
434
|
-
aspect (str, optional): Aspect ratio. Defaults to "equal".
|
|
435
|
-
ax (Axes, optional): Axes to plot on. Defaults to None.
|
|
436
|
-
cax (Axes, optional): Axes to plot color bar on. Defaults to None.
|
|
437
|
-
vmin (float, optional): Minimum value of the color bar. Defaults to None.
|
|
438
|
-
vmax (float, optional): Maximum value of the color bar. Defaults to None.
|
|
439
|
-
cmap (str, optional): Color map. Defaults to "micpy".
|
|
440
|
-
|
|
441
|
-
Returns:
|
|
442
|
-
Tuple[Figure, Axes]: Figure and axes of the plot.
|
|
379
|
+
filename (str): Filename of the binary file.
|
|
380
|
+
compressed (bool, optional): `True` if file should be compressed, `False`
|
|
381
|
+
otherwise. Defaults to `True`.
|
|
382
|
+
geometry (bool, optional): `True` if geometry should be written, `False`
|
|
383
|
+
otherwise. Defaults to `True`.
|
|
443
384
|
"""
|
|
444
|
-
if matplotlib is None:
|
|
445
|
-
raise ImportError("matplotlib is not installed")
|
|
446
|
-
|
|
447
|
-
slice = self.get_slice(plane, slice_id) if self.ndim == 3 else self
|
|
448
|
-
|
|
449
|
-
fig, ax = (
|
|
450
|
-
pyplot.subplots(figsize=figsize, dpi=dpi)
|
|
451
|
-
if ax is None
|
|
452
|
-
else (ax.get_figure(), ax)
|
|
453
|
-
)
|
|
454
|
-
|
|
455
|
-
if title is not None:
|
|
456
|
-
ax.set_title(title)
|
|
457
|
-
else:
|
|
458
|
-
ax.set_title(f"t={np.round(self.time, 7)}s")
|
|
459
|
-
if xlabel is not None:
|
|
460
|
-
ax.set_xlabel(xlabel)
|
|
461
|
-
else:
|
|
462
|
-
ax.set_xlabel(plane[0])
|
|
463
|
-
if ylabel is not None:
|
|
464
|
-
ax.set_ylabel(ylabel)
|
|
465
|
-
else:
|
|
466
|
-
ax.set_ylabel(plane[1])
|
|
467
|
-
if aspect is not None:
|
|
468
|
-
ax.set_aspect(aspect)
|
|
469
|
-
ax.set_frame_on(False)
|
|
470
|
-
|
|
471
|
-
mesh = ax.pcolormesh(slice, cmap=cmap, vmin=vmin, vmax=vmax)
|
|
472
|
-
|
|
473
|
-
bar = pyplot.colorbar(mesh, ax=ax, cax=cax)
|
|
474
|
-
bar.locator = matplotlib.ticker.MaxNLocator(
|
|
475
|
-
integer=np.issubdtype(slice.dtype, np.integer)
|
|
476
|
-
)
|
|
477
|
-
bar.outline.set_visible(False)
|
|
478
|
-
bar.update_ticks()
|
|
479
|
-
|
|
480
|
-
return fig, ax
|
|
481
|
-
|
|
482
385
|
|
|
483
|
-
class FieldList(List[Field]):
|
|
484
|
-
"""A list of fields."""
|
|
485
|
-
|
|
486
|
-
def __init__(self, fields: List[Field] = None):
|
|
487
|
-
super().__init__(fields if fields else [])
|
|
488
|
-
|
|
489
|
-
def append(self, field: Field):
|
|
490
|
-
"""Append a field to the list."""
|
|
491
|
-
super().append(field)
|
|
492
|
-
|
|
493
|
-
def extend(self, fields: List[Field]):
|
|
494
|
-
"""Extend the list with fields."""
|
|
495
|
-
super().extend(fields)
|
|
496
|
-
|
|
497
|
-
def write(self, filename: str, compressed: bool = True, write_geo: bool = True):
|
|
498
|
-
"""Write the fields to a binary file."""
|
|
499
386
|
file_open = gzip.open if compressed else open
|
|
500
387
|
with file_open(filename, "wb") as file:
|
|
501
|
-
|
|
502
|
-
field.write(file)
|
|
388
|
+
self.to_file(file, geometry)
|
|
503
389
|
|
|
504
|
-
if write_geo:
|
|
505
|
-
geo_filename, geo_data, geo_type = geo.get_basic(
|
|
506
|
-
filename, self[0].shape, self[0].spacing
|
|
507
|
-
)
|
|
508
|
-
geo.write(geo_filename, geo_data, geo_type, compressed=compressed)
|
|
509
390
|
|
|
510
|
-
|
|
511
|
-
def
|
|
512
|
-
self
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
sharex: bool = False,
|
|
516
|
-
sharey: bool = False,
|
|
517
|
-
figsize: Tuple[float, float] = None,
|
|
518
|
-
dpi: int = None,
|
|
519
|
-
**kwargs,
|
|
520
|
-
):
|
|
521
|
-
"""Plot the fields in a grid.
|
|
391
|
+
class Series:
|
|
392
|
+
def __init__(self, fields: List[Field]):
|
|
393
|
+
self.stack = np.stack(fields)
|
|
394
|
+
self.times = [field.time for field in fields]
|
|
395
|
+
self.spacings = [field.spacing for field in fields]
|
|
522
396
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
normalize (bool, optional): Normalize the color bar. Defaults to False.
|
|
526
|
-
sharex (bool, optional): Share x-axis. Defaults to False.
|
|
527
|
-
sharey (bool, optional): Share y-axis. Defaults to False.
|
|
528
|
-
figsize (Tuple[float, float], optional): Figure size. Defaults to None (auto).
|
|
529
|
-
dpi (int, optional): Figure DPI. Defaults to None (auto).
|
|
530
|
-
**kwargs: Keyword arguments passed to Field.plot().
|
|
397
|
+
def __array__(self):
|
|
398
|
+
return self.stack
|
|
531
399
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
"""
|
|
535
|
-
if matplotlib is None:
|
|
536
|
-
raise ImportError("matplotlib is not installed")
|
|
400
|
+
def __len__(self):
|
|
401
|
+
return len(self.stack)
|
|
537
402
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
403
|
+
def __iter__(self):
|
|
404
|
+
for item, time, spacing in zip(self.stack, self.times, self.spacings):
|
|
405
|
+
yield Field(item, time, spacing)
|
|
406
|
+
|
|
407
|
+
def __getitem__(self, index):
|
|
408
|
+
if isinstance(index, int):
|
|
409
|
+
return Field(self.stack[index], self.times[index], self.spacings[index])
|
|
410
|
+
elif isinstance(index, slice):
|
|
411
|
+
return Series(
|
|
412
|
+
[
|
|
413
|
+
Field(item, time, spacing)
|
|
414
|
+
for item, time, spacing in zip(
|
|
415
|
+
self.stack[index], self.times[index], self.spacings[index]
|
|
416
|
+
)
|
|
417
|
+
]
|
|
418
|
+
)
|
|
419
|
+
raise TypeError("Invalid argument type")
|
|
542
420
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
)
|
|
421
|
+
def __getattr__(self, name):
|
|
422
|
+
return getattr(self.stack, name)
|
|
546
423
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
if normalize
|
|
550
|
-
else kwargs.pop("vmin", None)
|
|
551
|
-
)
|
|
552
|
-
vmax = (
|
|
553
|
-
max(field.max() for field in self)
|
|
554
|
-
if normalize
|
|
555
|
-
else kwargs.pop("vmax", None)
|
|
556
|
-
)
|
|
424
|
+
def __dir__(self) -> List[str]:
|
|
425
|
+
return list(set(dir(type(self)) + dir(self.stack)))
|
|
557
426
|
|
|
558
|
-
|
|
427
|
+
def __repr__(self):
|
|
428
|
+
return repr(self.stack)
|
|
559
429
|
|
|
560
|
-
|
|
561
|
-
|
|
430
|
+
def __str__(self):
|
|
431
|
+
return str(self.stack)
|
|
562
432
|
|
|
563
|
-
|
|
564
|
-
|
|
433
|
+
def write(self, filename: str, compressed: bool = True, geometry: bool = True):
|
|
434
|
+
"""Write the series to a binary file.
|
|
565
435
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
436
|
+
Args:
|
|
437
|
+
filename (str): Filename of the binary file.
|
|
438
|
+
compressed (bool, optional): `True` if file should be compressed, `False`
|
|
439
|
+
otherwise. Defaults to `True`.
|
|
440
|
+
geometry (bool, optional): `True` if geometry should be written, `False`
|
|
441
|
+
otherwise. Defaults to `True`.
|
|
442
|
+
"""
|
|
569
443
|
|
|
570
|
-
|
|
444
|
+
file_open = gzip.open if compressed else open
|
|
445
|
+
with file_open(filename, "wb") as file:
|
|
446
|
+
for field in self:
|
|
447
|
+
field.to_file(file, geometry)
|
|
448
|
+
geometry = False
|
|
571
449
|
|
|
572
450
|
|
|
573
451
|
class File:
|
|
@@ -583,11 +461,12 @@ class File:
|
|
|
583
461
|
|
|
584
462
|
Args:
|
|
585
463
|
filename (str): File name.
|
|
586
|
-
chunk_size (int, optional): Chunk size in bytes. Defaults to 8388608
|
|
587
|
-
|
|
464
|
+
chunk_size (int, optional): Chunk size in bytes. Defaults to `8388608`
|
|
465
|
+
(8 MiB).
|
|
466
|
+
verbose (bool, optional): Verbose output. Defaults to `True`.
|
|
588
467
|
|
|
589
468
|
Raises:
|
|
590
|
-
FileNotFoundError
|
|
469
|
+
`FileNotFoundError`: If file is not found.
|
|
591
470
|
"""
|
|
592
471
|
if not os.path.isfile(filename):
|
|
593
472
|
raise FileNotFoundError(f"File not found: {filename}")
|
|
@@ -606,12 +485,12 @@ class File:
|
|
|
606
485
|
self.spacing: np.ndarray[(3,), np.float32] = None
|
|
607
486
|
|
|
608
487
|
try:
|
|
609
|
-
self.
|
|
488
|
+
self.find_geometry()
|
|
610
489
|
except (geo.GeometryFileNotFoundError, geo.MultipleGeometryFilesError):
|
|
611
490
|
if self._verbose:
|
|
612
491
|
self._warn("Caution: A geometry file was not found.")
|
|
613
492
|
|
|
614
|
-
def __getitem__(self, key: int
|
|
493
|
+
def __getitem__(self, key: Union[int, slice, list, Callable[[Field], bool]]):
|
|
615
494
|
return self.read(key)
|
|
616
495
|
|
|
617
496
|
def __enter__(self):
|
|
@@ -697,11 +576,13 @@ class File:
|
|
|
697
576
|
"""Get the times of the fields in the file.
|
|
698
577
|
|
|
699
578
|
Returns:
|
|
700
|
-
List
|
|
579
|
+
List of times.
|
|
701
580
|
"""
|
|
702
581
|
return [position.time for position in self.index()]
|
|
703
582
|
|
|
704
|
-
def
|
|
583
|
+
def set_geometry(
|
|
584
|
+
self, shape: Tuple[int, int, int], spacing: Tuple[float, float, float]
|
|
585
|
+
):
|
|
705
586
|
"""Set the geometry.
|
|
706
587
|
|
|
707
588
|
Args:
|
|
@@ -712,46 +593,42 @@ class File:
|
|
|
712
593
|
self.shape = np.array(shape)
|
|
713
594
|
self.spacing = np.array(spacing)
|
|
714
595
|
|
|
715
|
-
self.
|
|
596
|
+
self.print_geometry()
|
|
716
597
|
|
|
717
|
-
def
|
|
718
|
-
self, filename: str, type: geo.Type = geo.Type.EXTENDED, compressed: bool = True
|
|
719
|
-
):
|
|
598
|
+
def read_geometry(self, filename: str, compressed: Optional[bool] = None):
|
|
720
599
|
"""Read geometry from a file.
|
|
721
600
|
|
|
722
601
|
Args:
|
|
723
602
|
filename (str): Filename of a geometry file.
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
Defaults to True.
|
|
603
|
+
compressed (bool, optional): `True` if file is compressed, `False`
|
|
604
|
+
otherwise. Defaults to `None` (auto).
|
|
727
605
|
"""
|
|
728
|
-
|
|
606
|
+
if compressed is None:
|
|
607
|
+
compressed = utils.is_compressed(filename)
|
|
608
|
+
|
|
609
|
+
geometry = geo.read(filename, type=geo.Type.BASIC, compressed=compressed)
|
|
729
610
|
|
|
730
|
-
shape =
|
|
731
|
-
spacing =
|
|
611
|
+
shape = geometry["shape"]
|
|
612
|
+
spacing = geometry["spacing"]
|
|
732
613
|
|
|
733
|
-
self.
|
|
614
|
+
self.set_geometry(shape, spacing)
|
|
734
615
|
|
|
735
|
-
def
|
|
616
|
+
def find_geometry(self, compressed: Optional[bool] = None):
|
|
736
617
|
"""Find geometry file and read it.
|
|
737
618
|
|
|
738
619
|
Args:
|
|
739
|
-
type (Type, optional): Data type to be read. Defaults to Type.EXTENDED.
|
|
740
620
|
compressed (bool, optional): True if file is compressed, False otherwise.
|
|
741
|
-
Defaults to None (auto).
|
|
621
|
+
Defaults to `None` (auto).
|
|
742
622
|
|
|
743
623
|
Raises:
|
|
744
|
-
GeometryFileNotFoundError
|
|
745
|
-
MultipleGeometryFilesError
|
|
624
|
+
`GeometryFileNotFoundError`: If no geometry file is found.
|
|
625
|
+
`MultipleGeometryFilesError`: If multiple geometry files are found.
|
|
746
626
|
"""
|
|
747
627
|
filename = geo.find(self._filename)
|
|
748
628
|
|
|
749
|
-
|
|
750
|
-
compressed = utils.is_compressed(filename)
|
|
751
|
-
|
|
752
|
-
self.read_geo(filename, type=type, compressed=compressed)
|
|
629
|
+
self.read_geometry(filename, compressed=compressed)
|
|
753
630
|
|
|
754
|
-
def
|
|
631
|
+
def print_geometry(self):
|
|
755
632
|
"""Get a string representation of the geometry."""
|
|
756
633
|
|
|
757
634
|
if self.shape is None or self.spacing is None:
|
|
@@ -760,7 +637,7 @@ class File:
|
|
|
760
637
|
|
|
761
638
|
dimensions = Field.dimensions(self.shape)
|
|
762
639
|
cells = self.shape
|
|
763
|
-
spacing = np.round(self.spacing, 7)
|
|
640
|
+
spacing = 1e4 * np.round(self.spacing.astype(float), 7)
|
|
764
641
|
size = cells * spacing
|
|
765
642
|
|
|
766
643
|
self._info(f"Geometry: {dimensions}-Dimensional Grid")
|
|
@@ -768,28 +645,30 @@ class File:
|
|
|
768
645
|
self._info(f"Grid Shape (Cell Count): {tuple(cells)}")
|
|
769
646
|
self._info(f"Grid Spacing (Cell Size): {tuple(spacing)}μm³")
|
|
770
647
|
|
|
771
|
-
def iterate(self):
|
|
648
|
+
def iterate(self) -> Generator[Field, None, None]:
|
|
772
649
|
"""Iterate over fields in the file.
|
|
773
650
|
|
|
774
651
|
Returns:
|
|
775
|
-
|
|
652
|
+
A generator of fields.
|
|
776
653
|
"""
|
|
777
654
|
for position in self.index():
|
|
778
655
|
yield Field.read(position, shape=self.shape, spacing=self.spacing)
|
|
779
656
|
|
|
780
|
-
def read(
|
|
781
|
-
|
|
657
|
+
def read(
|
|
658
|
+
self, key: Optional[Union[int, slice, list, Callable[[Field], bool]]] = None
|
|
659
|
+
) -> Series:
|
|
660
|
+
"""Read field data from the file.
|
|
782
661
|
|
|
783
662
|
Args:
|
|
784
|
-
key (int
|
|
663
|
+
key (Union[int, slice, list, Callable[[Field], bool], optional): Key to
|
|
785
664
|
list of field IDs, a slice object, or a condition function.
|
|
786
|
-
Defaults to None
|
|
665
|
+
Defaults to `None`.
|
|
787
666
|
|
|
788
667
|
Returns:
|
|
789
|
-
|
|
668
|
+
A series of fields.
|
|
790
669
|
"""
|
|
791
670
|
|
|
792
|
-
def read_field(self, field_id: int
|
|
671
|
+
def read_field(self, field_id: Union[int, slice, list]):
|
|
793
672
|
position = self._index[field_id]
|
|
794
673
|
return Field.read(position, shape=self.shape, spacing=self.spacing)
|
|
795
674
|
|
|
@@ -816,4 +695,109 @@ class File:
|
|
|
816
695
|
else:
|
|
817
696
|
raise TypeError("Invalid argument type")
|
|
818
697
|
|
|
819
|
-
return
|
|
698
|
+
return Series(fields)
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
@dataclass
|
|
702
|
+
class PlotArgs:
|
|
703
|
+
"""Arguments for plotting a field.
|
|
704
|
+
|
|
705
|
+
Args:
|
|
706
|
+
title (str, optional): Title of the plot. Defaults to `None`.
|
|
707
|
+
xlabel (str, optional): Label of the x-axis. Defaults to `None`.
|
|
708
|
+
ylabel (str, optional): Label of the y-axis. Defaults to `None`.
|
|
709
|
+
figsize (Tuple[float, float], optional): Figure size. Defaults to `None`.
|
|
710
|
+
dpi (int, optional): Figure DPI. Defaults to `None`.
|
|
711
|
+
aspect (str, optional): Aspect ratio. Defaults to `equal`.
|
|
712
|
+
ax (matplotlib.Axes, optional): Axes of the plot. Defaults to `None`.
|
|
713
|
+
cax (matplotlib.Axes, optional): Axes of the color bar. Defaults to `None`.
|
|
714
|
+
vmin (float, optional): Minimum value of the color bar. Defaults to `None`.
|
|
715
|
+
vmax (float, optional): Maximum value of the color bar. Defaults to `None`.
|
|
716
|
+
cmap (str, optional): Colormap. Defaults to `
|
|
717
|
+
"""
|
|
718
|
+
|
|
719
|
+
title: Optional[str] = None
|
|
720
|
+
xlabel: Optional[str] = None
|
|
721
|
+
ylabel: Optional[str] = None
|
|
722
|
+
figsize: Optional[Tuple[float, float]] = None
|
|
723
|
+
dpi: Optional[int] = None
|
|
724
|
+
aspect: str = "equal"
|
|
725
|
+
ax: "matplotlib.Axes" = None
|
|
726
|
+
cax: "matplotlib.Axes" = None
|
|
727
|
+
vmin: Optional[float] = None
|
|
728
|
+
vmax: Optional[float] = None
|
|
729
|
+
cmap: str = "micpy"
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
def plot(
|
|
733
|
+
field: Field,
|
|
734
|
+
axis: str = "y",
|
|
735
|
+
index: int = 0,
|
|
736
|
+
args: Optional[PlotArgs] = None,
|
|
737
|
+
) -> Tuple["matplotlib.Figure", "matplotlib.Axes"]:
|
|
738
|
+
"""Plot a slice of the field.
|
|
739
|
+
|
|
740
|
+
Args:
|
|
741
|
+
field (Field): Field to plot.
|
|
742
|
+
axis (str, optional): Axis to plot. Possible values are `x`, `y`, and `z`.
|
|
743
|
+
Defaults to `y`.
|
|
744
|
+
index (int, optional): Index of the slice. Defaults to `0`.
|
|
745
|
+
args (PlotArgs, optional): Arguments for plotting. Defaults to `None`.
|
|
746
|
+
|
|
747
|
+
Returns:
|
|
748
|
+
Matplotlib figure and axes of the plot.
|
|
749
|
+
"""
|
|
750
|
+
|
|
751
|
+
if matplotlib is None:
|
|
752
|
+
raise ImportError("matplotlib is not installed")
|
|
753
|
+
|
|
754
|
+
if axis not in ["x", "y", "z"]:
|
|
755
|
+
raise ValueError("Invalid axis")
|
|
756
|
+
|
|
757
|
+
if args is None:
|
|
758
|
+
args = PlotArgs()
|
|
759
|
+
|
|
760
|
+
if axis == "z":
|
|
761
|
+
x, y = "x", "y"
|
|
762
|
+
slice_2d = field[index, :, :]
|
|
763
|
+
elif axis == "y":
|
|
764
|
+
x, y = "x", "z"
|
|
765
|
+
slice_2d = field[:, index, :]
|
|
766
|
+
if Field.dimensions(field.shape) == 2:
|
|
767
|
+
slice_2d = slice_2d.reshape(slice_2d.shape[1], slice_2d.shape[0])
|
|
768
|
+
elif axis == "x":
|
|
769
|
+
x, y = "y", "z"
|
|
770
|
+
slice_2d = field[:, :, index]
|
|
771
|
+
|
|
772
|
+
fig, ax = (
|
|
773
|
+
pyplot.subplots(figsize=args.figsize, dpi=args.dpi)
|
|
774
|
+
if args.ax is None
|
|
775
|
+
else (args.ax.get_figure(), args.ax)
|
|
776
|
+
)
|
|
777
|
+
|
|
778
|
+
if args.title is not None:
|
|
779
|
+
ax.set_title(args.title)
|
|
780
|
+
else:
|
|
781
|
+
ax.set_title(f"t={np.round(field.time, 7)}s")
|
|
782
|
+
if args.xlabel is not None:
|
|
783
|
+
ax.set_xlabel(args.xlabel)
|
|
784
|
+
else:
|
|
785
|
+
ax.set_xlabel(x)
|
|
786
|
+
if args.ylabel is not None:
|
|
787
|
+
ax.set_ylabel(args.ylabel)
|
|
788
|
+
else:
|
|
789
|
+
ax.set_ylabel(y)
|
|
790
|
+
if args.aspect is not None:
|
|
791
|
+
ax.set_aspect(args.aspect)
|
|
792
|
+
ax.set_frame_on(False)
|
|
793
|
+
|
|
794
|
+
mesh = ax.pcolormesh(slice_2d, cmap=args.cmap, vmin=args.vmin, vmax=args.vmax)
|
|
795
|
+
|
|
796
|
+
bar = pyplot.colorbar(mesh, ax=ax, cax=args.cax)
|
|
797
|
+
bar.locator = matplotlib.ticker.MaxNLocator(
|
|
798
|
+
integer=np.issubdtype(slice_2d.dtype, np.integer)
|
|
799
|
+
)
|
|
800
|
+
bar.outline.set_visible(False)
|
|
801
|
+
bar.update_ticks()
|
|
802
|
+
|
|
803
|
+
return fig, ax
|
micpy/geo.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""The `micpy.geo` modules provides methods to read and write geometry files."""
|
|
2
2
|
|
|
3
3
|
import enum
|
|
4
4
|
import gzip
|
|
5
5
|
|
|
6
6
|
from typing import Tuple
|
|
7
7
|
from pathlib import Path
|
|
8
|
+
from typing import Optional
|
|
8
9
|
|
|
9
10
|
import numpy as np
|
|
10
11
|
from numpy import ndarray
|
|
@@ -31,11 +32,11 @@ BASIC_MODEL = [
|
|
|
31
32
|
|
|
32
33
|
EXTENSION_MODEL = [
|
|
33
34
|
("extension_header", np.int32),
|
|
34
|
-
("version", np.
|
|
35
|
-
("compile_date", np.
|
|
36
|
-
("run_date", np.
|
|
37
|
-
("platform", np.
|
|
38
|
-
("precision", np.
|
|
35
|
+
("version", np.bytes_, 10),
|
|
36
|
+
("compile_date", np.bytes_, 10),
|
|
37
|
+
("run_date", np.bytes_, 10),
|
|
38
|
+
("platform", np.bytes_, 10),
|
|
39
|
+
("precision", np.bytes_, 10),
|
|
39
40
|
("extension_footer", np.int32),
|
|
40
41
|
]
|
|
41
42
|
|
|
@@ -59,7 +60,7 @@ class MultipleGeometryFilesError(GeometryFileError):
|
|
|
59
60
|
"""Raised when multiple potential geometry files are found."""
|
|
60
61
|
|
|
61
62
|
|
|
62
|
-
def find(filename: str) ->
|
|
63
|
+
def find(filename: str) -> Path:
|
|
63
64
|
"""Find the geometry file for a given binary file.
|
|
64
65
|
|
|
65
66
|
This method assumes that (a) both files share a common basename and (b) the
|
|
@@ -69,7 +70,7 @@ def find(filename: str) -> str:
|
|
|
69
70
|
filename (str): Filename of a binary file.
|
|
70
71
|
|
|
71
72
|
Returns:
|
|
72
|
-
Path
|
|
73
|
+
Path to the geometry file.
|
|
73
74
|
"""
|
|
74
75
|
basename = _get_basename(Path(filename))
|
|
75
76
|
matches = list(basename.parent.glob(f"{basename.name}[._]geoF*"))
|
|
@@ -89,12 +90,12 @@ def read(filename: str, type: Type = Type.EXTENDED, compressed: bool = True) ->
|
|
|
89
90
|
|
|
90
91
|
Args:
|
|
91
92
|
filename (str): Filename of a geometry file.
|
|
92
|
-
type (Type, optional): Data type to be read.
|
|
93
|
+
type (Type, optional): Data type to be read. Defaults to `Type.EXTENDED`.
|
|
93
94
|
compressed (bool, optional): True if file is compressed, False otherwise.
|
|
94
|
-
Defaults to True
|
|
95
|
+
Defaults to `True`.
|
|
95
96
|
|
|
96
97
|
Returns:
|
|
97
|
-
|
|
98
|
+
Dictionary representation of the geometry file.
|
|
98
99
|
"""
|
|
99
100
|
array_data = read_ndarray(filename, type, compressed)
|
|
100
101
|
return _ndarray_to_dict(array_data)
|
|
@@ -107,12 +108,12 @@ def read_ndarray(
|
|
|
107
108
|
|
|
108
109
|
Args:
|
|
109
110
|
filename (str): Filename of a geometry file.
|
|
110
|
-
type (Type, optional): Data type to be read. Defaults to Type.EXTENDED
|
|
111
|
-
compressed (bool, optional): True if file is compressed, False otherwise.
|
|
112
|
-
Defaults to True
|
|
111
|
+
type (Type, optional): Data type to be read. Defaults to `Type.EXTENDED`.
|
|
112
|
+
compressed (bool, optional): `True` if file is compressed, `False` otherwise.
|
|
113
|
+
Defaults to `True`.
|
|
113
114
|
|
|
114
115
|
Returns:
|
|
115
|
-
|
|
116
|
+
NumPy array representation of the geometry file.
|
|
116
117
|
"""
|
|
117
118
|
opener = gzip.open if compressed else open
|
|
118
119
|
with opener(filename, "rb") as f:
|
|
@@ -130,9 +131,9 @@ def write(
|
|
|
130
131
|
Args:
|
|
131
132
|
filename (str): Filename of a geometry file.
|
|
132
133
|
data (dict): Dictionary representation of a geometry file.
|
|
133
|
-
type (Type, optional): Data type to be written. Defaults to Type.EXTENDED
|
|
134
|
-
compressed (bool, optional): True if file should be compressed, False
|
|
135
|
-
Defaults to True
|
|
134
|
+
type (Type, optional): Data type to be written. Defaults to `Type.EXTENDED`.
|
|
135
|
+
compressed (bool, optional): `True` if file should be compressed, `False`
|
|
136
|
+
otherwise. Defaults to `True`.
|
|
136
137
|
"""
|
|
137
138
|
array_data = _dict_to_ndarray(data, type)
|
|
138
139
|
write_ndarray(filename, array_data, compressed)
|
|
@@ -144,8 +145,8 @@ def write_ndarray(filename: str, data: ndarray, compressed: bool = True):
|
|
|
144
145
|
Args:
|
|
145
146
|
filename (str): Filename of a geometry file.
|
|
146
147
|
data (ndarray): NumPy array representation of a geometry file.
|
|
147
|
-
compressed (bool, optional): True if file should be compressed, False
|
|
148
|
-
Defaults to True
|
|
148
|
+
compressed (bool, optional): `True` if file should be compressed, `False`
|
|
149
|
+
otherwise. Defaults to `True`.
|
|
149
150
|
"""
|
|
150
151
|
if not _validate_data_type(data):
|
|
151
152
|
raise ValueError("Invalid data type")
|
|
@@ -157,7 +158,7 @@ def write_ndarray(filename: str, data: ndarray, compressed: bool = True):
|
|
|
157
158
|
f.write(data.tobytes())
|
|
158
159
|
|
|
159
160
|
|
|
160
|
-
def
|
|
161
|
+
def build(
|
|
161
162
|
filename: str, shape: Tuple[int, int, int], spacing: Tuple[float, float, float]
|
|
162
163
|
) -> Tuple[str, dict, Type]:
|
|
163
164
|
"""Create a basic geometry.
|
|
@@ -174,13 +175,13 @@ def get_basic(
|
|
|
174
175
|
"spacing": spacing,
|
|
175
176
|
"basic_footer": 24,
|
|
176
177
|
}
|
|
177
|
-
return geo_filename, geo_data
|
|
178
|
+
return geo_filename, geo_data
|
|
178
179
|
|
|
179
180
|
|
|
180
181
|
def _get_basename(path: Path) -> Path:
|
|
181
182
|
"""Extract the basename from a binary filename.
|
|
182
183
|
|
|
183
|
-
A specific check for the
|
|
184
|
+
A specific check for the `.mcr` extension is added due to historical naming
|
|
184
185
|
conventions related to the association of binary files and their geometry files.
|
|
185
186
|
"""
|
|
186
187
|
if not path.name:
|
|
@@ -194,7 +195,7 @@ def _get_basename(path: Path) -> Path:
|
|
|
194
195
|
return path.with_suffix("")
|
|
195
196
|
|
|
196
197
|
|
|
197
|
-
def _validate_data_type(data: np.ndarray) -> bool:
|
|
198
|
+
def _validate_data_type(data: Optional[np.ndarray]) -> bool:
|
|
198
199
|
"""Validate the data type."""
|
|
199
200
|
if not isinstance(data, np.ndarray):
|
|
200
201
|
return False
|
micpy/matplotlib.py
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
from distutils.version import LooseVersion
|
|
3
|
-
|
|
1
|
+
from packaging import version
|
|
4
2
|
|
|
5
3
|
try:
|
|
6
4
|
import matplotlib
|
|
@@ -31,14 +29,12 @@ def _register_colormaps():
|
|
|
31
29
|
"#fffbb4",
|
|
32
30
|
]
|
|
33
31
|
|
|
34
|
-
version = LooseVersion(matplotlib.__version__) >= LooseVersion("3.7")
|
|
35
|
-
|
|
36
32
|
create = matplotlib.colors.LinearSegmentedColormap.from_list
|
|
37
33
|
|
|
38
34
|
colormap = create(name="micpy", colors=colors, N=1024)
|
|
39
35
|
colormap_r = create(name="micpy_r", colors=colors[::-1], N=1024)
|
|
40
36
|
|
|
41
|
-
if version:
|
|
37
|
+
if version.parse(matplotlib.__version__) >= version.parse("3.7"):
|
|
42
38
|
register = matplotlib.colormaps.register
|
|
43
39
|
register(colormap)
|
|
44
40
|
register(colormap_r)
|
|
@@ -48,28 +44,6 @@ def _register_colormaps():
|
|
|
48
44
|
register("micpy_r", colormap_r)
|
|
49
45
|
|
|
50
46
|
|
|
51
|
-
def _set_aixvipmap_font():
|
|
52
|
-
font = "IBM Plex Sans"
|
|
53
|
-
if font in matplotlib.font_manager.get_font_names():
|
|
54
|
-
pyplot.rcParams["font.family"] = font
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def _set_aixvipmap_colors():
|
|
58
|
-
colors = [
|
|
59
|
-
"#00549F",
|
|
60
|
-
"#F6A800",
|
|
61
|
-
"#57AB27",
|
|
62
|
-
"#CC071E",
|
|
63
|
-
"#612158",
|
|
64
|
-
"#006165",
|
|
65
|
-
"#E30066",
|
|
66
|
-
"#0098A1",
|
|
67
|
-
"#BDCD00",
|
|
68
|
-
"#0098A1",
|
|
69
|
-
]
|
|
70
|
-
pyplot.rcParams["axes.prop_cycle"] = pyplot.cycler(color=colors)
|
|
71
|
-
|
|
72
|
-
|
|
73
47
|
def configure():
|
|
74
48
|
if not matplotlib:
|
|
75
49
|
return
|
|
@@ -78,7 +52,3 @@ def configure():
|
|
|
78
52
|
_register_colormaps()
|
|
79
53
|
except ValueError:
|
|
80
54
|
pass
|
|
81
|
-
|
|
82
|
-
if "AIXVIPMAP_HOME" in os.environ:
|
|
83
|
-
_set_aixvipmap_font()
|
|
84
|
-
_set_aixvipmap_colors()
|
micpy/tab.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""The `micpy.tab` module provides methods to read and parse tabular files."""
|
|
2
2
|
|
|
3
3
|
import io
|
|
4
4
|
import re
|
|
@@ -20,15 +20,15 @@ def parse(
|
|
|
20
20
|
|
|
21
21
|
Args:
|
|
22
22
|
string (str): The content of a tabular file as a string.
|
|
23
|
-
parse_header (bool, optional): Whether to parse the header. Defaults to True
|
|
23
|
+
parse_header (bool, optional): Whether to parse the header. Defaults to `True`.
|
|
24
24
|
ignore_invalid_header (bool, optional): Whether to ignore invalid headers.
|
|
25
|
-
Defaults to True
|
|
25
|
+
Defaults to `True`.
|
|
26
26
|
|
|
27
27
|
Raises:
|
|
28
|
-
FormatError
|
|
28
|
+
`FormatError`: If the number of columns in the header does not match the body.
|
|
29
29
|
|
|
30
30
|
Returns:
|
|
31
|
-
|
|
31
|
+
The content of the file as a pandas DataFrame.
|
|
32
32
|
"""
|
|
33
33
|
lines = string.splitlines()
|
|
34
34
|
return _parse_lines(lines, parse_header, ignore_invalid_header)
|
|
@@ -41,15 +41,15 @@ def read(
|
|
|
41
41
|
|
|
42
42
|
Args:
|
|
43
43
|
filename (str): Path to the file.
|
|
44
|
-
parse_header (bool, optional): Whether to parse the header. Defaults to True
|
|
44
|
+
parse_header (bool, optional): Whether to parse the header. Defaults to `True`.
|
|
45
45
|
ignore_invalid_header (bool, optional): Whether to ignore invalid headers.
|
|
46
|
-
Defaults to True
|
|
46
|
+
Defaults to `True`.
|
|
47
47
|
|
|
48
48
|
Raises:
|
|
49
|
-
FormatError
|
|
49
|
+
`FormatError`: If the number of columns in the header does not match the body.
|
|
50
50
|
|
|
51
51
|
Returns:
|
|
52
|
-
|
|
52
|
+
The content of the file as a pandas DataFrame.
|
|
53
53
|
"""
|
|
54
54
|
with open(filename, mode="r", encoding="utf8") as file:
|
|
55
55
|
lines = file.readlines()
|
micpy/utils.py
CHANGED
|
@@ -4,17 +4,6 @@ import sys
|
|
|
4
4
|
import time
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
def convert_si(value, unit_in, unit_out):
|
|
8
|
-
"""Convert value from one SI unit to another SI unit."""
|
|
9
|
-
SI = {"μm": 0.000001, "mm": 0.001, "cm": 0.01, "m": 1.0}
|
|
10
|
-
|
|
11
|
-
if isinstance(value, (float, int)):
|
|
12
|
-
return value * SI[unit_in] / SI[unit_out]
|
|
13
|
-
elif isinstance(value, (tuple, list)):
|
|
14
|
-
return [v * SI[unit_in] / SI[unit_out] for v in value]
|
|
15
|
-
raise ValueError("Unsupported value type.")
|
|
16
|
-
|
|
17
|
-
|
|
18
7
|
def progress_indicator(iterable, description="Progress", unit="Iteration", start=1):
|
|
19
8
|
"""Progress indicator for iterable."""
|
|
20
9
|
|
micpy/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.
|
|
1
|
+
__version__ = "0.3.0b0"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: micress-micpy
|
|
3
|
+
Version: 0.3.0b0
|
|
4
|
+
Summary: MicPy is a Python package to facilitate MICRESS workflows.
|
|
5
|
+
Author: Lukas Koschmieder
|
|
6
|
+
Author-email: l.koschmieder@access-technology.de
|
|
7
|
+
License: BSD-3-Clause (Copyright (c) 2024 Access e.V.)
|
|
8
|
+
Keywords: MICRESS
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: Natural Language :: English
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: matplotlib
|
|
18
|
+
Requires-Dist: pandas
|
|
19
|
+
|
|
20
|
+
<center>
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+
|
|
24
|
+
</center>
|
|
25
|
+
|
|
26
|
+
# MicPy
|
|
27
|
+
|
|
28
|
+
MicPy is a Python package to facilitate [MICRESS](https://www.micress.de) workflows. Whether you aim to visualize, convert, or manipulate MICRESS data, MicPy provides the necessary tools.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
pip install micress-micpy
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Dependencies
|
|
37
|
+
|
|
38
|
+
MicPy requires the following dependencies:
|
|
39
|
+
|
|
40
|
+
- Python (>= 3.9)
|
|
41
|
+
- Pandas (>= 1.1)
|
|
42
|
+
- Matplotlib (>= 3) as an optional dependency for plotting
|
|
43
|
+
|
|
44
|
+
## Documentation
|
|
45
|
+
|
|
46
|
+
https://docs.micress.de/micpy
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
micpy/__init__.py,sha256=7wQUaseppjQYZW1iAVNm2WSDjvBLlqtY8tiHsfDaW5Q,148
|
|
2
|
+
micpy/bin.py,sha256=6CiN1KUrIVDn5pXtf05n-A7D7yOFAUXAbfBUeXpgcGs,25521
|
|
3
|
+
micpy/geo.py,sha256=lVRTtPnTEykkSXNyLm3wnxXOwz72PFu0Spv8ZGHyUHo,7417
|
|
4
|
+
micpy/matplotlib.py,sha256=GF2ghyBORC5RRjW00DdsHu5aSkpMFdI9wqg6d_psPsI,1198
|
|
5
|
+
micpy/tab.py,sha256=QCnfggxRWkKgS9-zGj8kyCjhfUw7QeTgGZWedHh4MTw,3548
|
|
6
|
+
micpy/utils.py,sha256=Kt1AvhMvWer9uftbb88X7N27aXtQdJl26grHmmm2vOQ,859
|
|
7
|
+
micpy/version.py,sha256=v6LLclreYkCiqxCP6QRdhtVAzCVndQ77c0lTMqPZjXk,25
|
|
8
|
+
micress_micpy-0.3.0b0.dist-info/LICENSE,sha256=seHdCiArizUoWZ6bEFg6N3K2ZtfPK35wvOwg0kH-f6o,1488
|
|
9
|
+
micress_micpy-0.3.0b0.dist-info/METADATA,sha256=RbN1IrUFx14nsUJB2fIeLxrxFD49sF1sujNg1vBmlpA,1229
|
|
10
|
+
micress_micpy-0.3.0b0.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
11
|
+
micress_micpy-0.3.0b0.dist-info/top_level.txt,sha256=RiopkpW0AGNYdtOW2eQUWgm3yHGC13q9pWlHb2alhiE,6
|
|
12
|
+
micress_micpy-0.3.0b0.dist-info/RECORD,,
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: micress-micpy
|
|
3
|
-
Version: 0.2.16b0
|
|
4
|
-
Summary: MicPy is a Python package to facilitate MICRESS workflows.
|
|
5
|
-
Author: Lukas Koschmieder
|
|
6
|
-
Author-email: l.koschmieder@access-technology.de
|
|
7
|
-
License: BSD-3-Clause (Copyright (c) 2024 Access e.V.)
|
|
8
|
-
Keywords: MICRESS
|
|
9
|
-
Classifier: Development Status :: 4 - Beta
|
|
10
|
-
Classifier: Intended Audience :: Science/Research
|
|
11
|
-
Classifier: Natural Language :: English
|
|
12
|
-
Classifier: Operating System :: OS Independent
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
-
Requires-Python: >=3.9
|
|
15
|
-
Description-Content-Type: text/markdown
|
|
16
|
-
License-File: LICENSE
|
|
17
|
-
Requires-Dist: matplotlib
|
|
18
|
-
Requires-Dist: pandas
|
|
19
|
-
|
|
20
|
-
<center>
|
|
21
|
-
|
|
22
|
-

|
|
23
|
-
|
|
24
|
-
</center>
|
|
25
|
-
|
|
26
|
-
# MicPy
|
|
27
|
-
|
|
28
|
-
MicPy is a Python package to facilitate [MICRESS](https://www.micress.de) workflows. Whether you aim to visualize, convert, or manipulate MICRESS data, MicPy provides the necessary tools.
|
|
29
|
-
|
|
30
|
-
## Installation
|
|
31
|
-
|
|
32
|
-
```
|
|
33
|
-
pip install micress-micpy
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Dependencies
|
|
37
|
-
|
|
38
|
-
MicPy requires the following dependencies:
|
|
39
|
-
|
|
40
|
-
- Python (>= 3.9)
|
|
41
|
-
- Pandas (>= 1.1)
|
|
42
|
-
- Matplotlib (>= 3) as an optional dependency for plotting
|
|
43
|
-
|
|
44
|
-
## Examples
|
|
45
|
-
|
|
46
|
-
Below are some examples demonstrating how to use MicPy.
|
|
47
|
-
|
|
48
|
-
### `bin` module
|
|
49
|
-
|
|
50
|
-
#### Read one field at a time
|
|
51
|
-
|
|
52
|
-
```python
|
|
53
|
-
from micpy import bin
|
|
54
|
-
|
|
55
|
-
for field in bin.File("A001_Delta_Gamma.conc1"):
|
|
56
|
-
print(field)
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
#### Read all fields
|
|
60
|
-
|
|
61
|
-
```python
|
|
62
|
-
|
|
63
|
-
from micpy import bin
|
|
64
|
-
|
|
65
|
-
with bin.File("A001_Delta_Gamma.conc1") as file:
|
|
66
|
-
fields = file.read()
|
|
67
|
-
|
|
68
|
-
print(fields)
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
#### Read a subset of fields providing a list of indices
|
|
72
|
-
|
|
73
|
-
```python
|
|
74
|
-
from micpy import bin
|
|
75
|
-
|
|
76
|
-
with bin.File("A001_Delta_Gamma.conc1") as file:
|
|
77
|
-
fields = file.read([0, 1, -2, -1])
|
|
78
|
-
|
|
79
|
-
print(fields)
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
#### Read a subset of fields providing a condition function
|
|
83
|
-
|
|
84
|
-
```python
|
|
85
|
-
from micpy import bin
|
|
86
|
-
|
|
87
|
-
with bin.File("A001_Delta_Gamma.conc1") as file:
|
|
88
|
-
fields = file.read(lambda field: field.time >= 10 and field.time <= 20)
|
|
89
|
-
|
|
90
|
-
print(fields)
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
#### Read fields opening and closing the file manually
|
|
94
|
-
|
|
95
|
-
```python
|
|
96
|
-
from micpy import bin
|
|
97
|
-
|
|
98
|
-
file = bin.File("A001_Delta_Gamma.conc1")
|
|
99
|
-
|
|
100
|
-
file.open()
|
|
101
|
-
|
|
102
|
-
first_field = file.read(0)
|
|
103
|
-
second_field = file.read(1)
|
|
104
|
-
|
|
105
|
-
file.close()
|
|
106
|
-
|
|
107
|
-
print(first_field, second_field)
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
#### Plot a field
|
|
111
|
-
|
|
112
|
-
```python
|
|
113
|
-
from micpy import bin
|
|
114
|
-
|
|
115
|
-
with bin.File("A001_Delta_Gamma.conc1") as file:
|
|
116
|
-
field = file[-1]
|
|
117
|
-
|
|
118
|
-
fig, ax = field.plot()
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
#### Plot a list of fields normalizing the data
|
|
122
|
-
|
|
123
|
-
```python
|
|
124
|
-
from micpy import bin
|
|
125
|
-
|
|
126
|
-
with bin.File("A001_Delta_Gamma.conc1") as file:
|
|
127
|
-
fields = file[[0, 1, -2, -1]]
|
|
128
|
-
|
|
129
|
-
fig, ax = fields.plot(normalize=True, figsize=(8, 8))
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
#### Plot a specific plane of a field
|
|
133
|
-
|
|
134
|
-
```python
|
|
135
|
-
from micpy import bin
|
|
136
|
-
|
|
137
|
-
with bin.File("A005_Grain_Growth_Misorientation_3D.korn") as file:
|
|
138
|
-
field = file[0]
|
|
139
|
-
|
|
140
|
-
fig, ax = field.plot(plane="xy", slice=50)
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### `tab` module
|
|
144
|
-
|
|
145
|
-
#### Read a table
|
|
146
|
-
|
|
147
|
-
```python
|
|
148
|
-
from micpy import tab
|
|
149
|
-
|
|
150
|
-
table = tab.read("A001_Delta_Gamma.TabF")
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
#### Plot a table
|
|
154
|
-
|
|
155
|
-
```python
|
|
156
|
-
from micpy import tab
|
|
157
|
-
|
|
158
|
-
table = tab.read("A001_Delta_Gamma.TabF")
|
|
159
|
-
|
|
160
|
-
fig, ax = table.plot(x=1, y=[2, 3, 4])
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
#### Extract a subset of a table
|
|
164
|
-
|
|
165
|
-
```python
|
|
166
|
-
from micpy import tab
|
|
167
|
-
|
|
168
|
-
table = tab.read("A001_Delta_Gamma.TabF")
|
|
169
|
-
|
|
170
|
-
table.loc[
|
|
171
|
-
table["Fraction Phase 2 FCC_A1"] > 0,
|
|
172
|
-
["Temperature [K]", "Fraction Phase 1 BCC_A2", "Fraction Phase 2 FCC_A1"]
|
|
173
|
-
]
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
#### Convert a table to different file formats
|
|
177
|
-
|
|
178
|
-
```python
|
|
179
|
-
from micpy import tab
|
|
180
|
-
|
|
181
|
-
table = tab.read("A001_Delta_Gamma.TabF")
|
|
182
|
-
|
|
183
|
-
table.to_csv("A001_Delta_Gamma.TabF.csv")
|
|
184
|
-
table.to_excel("A001_Delta_Gamma.TabF.xlsx")
|
|
185
|
-
table.to_json("A001_Delta_Gamma.TabF.json")
|
|
186
|
-
```
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
micpy/__init__.py,sha256=7wQUaseppjQYZW1iAVNm2WSDjvBLlqtY8tiHsfDaW5Q,148
|
|
2
|
-
micpy/bin.py,sha256=1eO8nv3j3CNFFx35W2I-MdOTgelxVwOf3AzIv5-cnXY,26586
|
|
3
|
-
micpy/geo.py,sha256=dcXcxvAxPpe4Rrs1ImYs8H67c2228brabdefJMoLn0g,7354
|
|
4
|
-
micpy/matplotlib.py,sha256=toxFTtTaA-usuWUltMp0XufQee4-n68XH7SN2In2NZY,1845
|
|
5
|
-
micpy/tab.py,sha256=ZXhL6bg17W3jqFFX28htCOAV9W_W3op_-GD7iU5a_wY,3547
|
|
6
|
-
micpy/utils.py,sha256=-JS5SRqH4QMD6_pXBKPVw5zPNTbaqkcOUu9ej5Gi0QU,1282
|
|
7
|
-
micpy/version.py,sha256=MwwJ3Tq2WyMrlg5ARuI934Sn37GJtLQJ8y2GpYXfdw4,26
|
|
8
|
-
micress_micpy-0.2.16b0.dist-info/LICENSE,sha256=seHdCiArizUoWZ6bEFg6N3K2ZtfPK35wvOwg0kH-f6o,1488
|
|
9
|
-
micress_micpy-0.2.16b0.dist-info/METADATA,sha256=ZtkZWKBm6rCf4Bgwq8hKzO-sEdNkSpCBe7XDC5sF6EY,3824
|
|
10
|
-
micress_micpy-0.2.16b0.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
11
|
-
micress_micpy-0.2.16b0.dist-info/top_level.txt,sha256=RiopkpW0AGNYdtOW2eQUWgm3yHGC13q9pWlHb2alhiE,6
|
|
12
|
-
micress_micpy-0.2.16b0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|