micress-micpy 0.2.13b4__py3-none-any.whl → 0.2.15b0__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 CHANGED
@@ -5,6 +5,7 @@ from typing import Callable, IO, List, Tuple, Generator
5
5
 
6
6
  import gzip
7
7
  import os
8
+ import sys
8
9
  import warnings
9
10
  import zlib
10
11
 
@@ -230,7 +231,7 @@ class Index(List[Position]):
230
231
  @staticmethod
231
232
  def from_file(
232
233
  file: IO[bytes],
233
- show_progress: bool = True,
234
+ verbose: bool = True,
234
235
  chunk_size: int = Chunk.DEFAULT_SIZE,
235
236
  compressed: bool = True,
236
237
  position: Position = None,
@@ -240,7 +241,7 @@ class Index(List[Position]):
240
241
  file, chunk_size=chunk_size, compressed=compressed, position=position
241
242
  )
242
243
 
243
- if show_progress:
244
+ if verbose:
244
245
  iterator = utils.progress_indicator(
245
246
  iterator, description="Indexing", unit="Field"
246
247
  )
@@ -250,13 +251,13 @@ class Index(List[Position]):
250
251
  @staticmethod
251
252
  def from_filename(
252
253
  filename: str,
253
- show_progress: bool = True,
254
+ verbose: bool = True,
254
255
  chunk_size: int = Chunk.DEFAULT_SIZE,
255
256
  compressed: bool = True,
256
257
  ):
257
258
  """Build an index from a binary file."""
258
259
  file = open(filename, "rb")
259
- return Index.from_file(file, show_progress, chunk_size, compressed)
260
+ return Index.from_file(file, verbose, chunk_size, compressed)
260
261
 
261
262
 
262
263
  class Field(np.ndarray):
@@ -535,7 +536,7 @@ class FieldList(List[Field]):
535
536
  raise ImportError("matplotlib is not installed")
536
537
 
537
538
  if cols is None:
538
- cols = int(np.sqrt(len(self)))
539
+ cols = int(np.ceil(np.sqrt(len(self))))
539
540
 
540
541
  rows = (len(self) + cols - 1) // cols
541
542
 
@@ -576,12 +577,14 @@ class File:
576
577
  self,
577
578
  filename: str,
578
579
  chunk_size: int = Chunk.DEFAULT_SIZE,
580
+ verbose: bool = True,
579
581
  ):
580
582
  """Initialize a binary file.
581
583
 
582
584
  Args:
583
585
  filename (str): File name.
584
586
  chunk_size (int, optional): Chunk size in bytes. Defaults to 8388608 (8 MiB).
587
+ verbose (bool, optional): Verbose output. Defaults to True.
585
588
 
586
589
  Raises:
587
590
  FileNotFoundError: If file is not found.
@@ -589,8 +592,9 @@ class File:
589
592
  if not os.path.isfile(filename):
590
593
  raise FileNotFoundError(f"File not found: {filename}")
591
594
 
592
- self._filename = filename
595
+ self._filename: str = filename
593
596
  self._chunk_size: int = chunk_size
597
+ self._verbose: bool = verbose
594
598
 
595
599
  self._file: IO[bytes] = None
596
600
  self._compressed: bool = None
@@ -604,11 +608,8 @@ class File:
604
608
  try:
605
609
  self.find_geo()
606
610
  except (geo.GeometryFileNotFoundError, geo.MultipleGeometryFilesError):
607
- print(
608
- "Caution: A geometry file was not found. "
609
- "To read a geometry from a designated location, use the read_geo() method. "
610
- "Alternatively, you can manually set the geometry by executing set_geo()."
611
- )
611
+ if self._verbose:
612
+ self._warn("Caution: A geometry file was not found.")
612
613
 
613
614
  def __getitem__(self, key: int or slice or list or Callable[[Field], bool]):
614
615
  return self.read(key)
@@ -622,73 +623,75 @@ class File:
622
623
  def __iter__(self):
623
624
  return self.iterate()
624
625
 
625
- def open(self):
626
- """Open the file."""
627
- if not self._file:
628
- self._file = open(self._filename, "rb")
629
- self._compressed = utils.is_compressed(self._filename)
626
+ def _info(self, *args):
627
+ if self._verbose:
628
+ print(*args)
630
629
 
631
- return self
630
+ def _warn(self, *args):
631
+ if self._verbose:
632
+ print(*args, file=sys.stderr)
632
633
 
633
- def close(self):
634
- """Close the file."""
634
+ def _open_file(self):
635
+ self._file = open(self._filename, "rb")
636
+ self._compressed = utils.is_compressed(self._filename)
637
+
638
+ def _close_file(self):
635
639
  if self._file:
636
640
  self._file.close()
641
+ self._reset()
637
642
 
643
+ def _reset(self):
638
644
  self._file = None
639
645
  self._compressed = None
640
646
  self._created = None
641
647
  self._modified = None
642
648
  self._index = None
643
649
 
644
- def index(
645
- self,
646
- show_progress: bool = True,
647
- create: bool = None,
648
- update: bool = None,
649
- ) -> Index:
650
- """Build an index of the file.
651
-
652
- Args:
653
- show_progress (bool, optional): Show progress bar. Defaults to True.
654
- create (bool, optional): Create the index. Defaults to None (auto).
655
- update (bool, optional): Update the index. Defaults to None (auto).
650
+ def _update_timestamps(self):
651
+ self._created = os.path.getctime(self._filename)
652
+ self._modified = os.path.getmtime(self._filename)
656
653
 
657
- Returns:
658
- Index: Index of the file.
659
- """
660
-
661
- def file_created():
662
- return self._created != os.path.getctime(self._filename)
663
-
664
- def file_modified():
665
- return self._modified != os.path.getmtime(self._filename)
666
-
667
- create = create if create is not None else file_created()
668
- update = update if update is not None else file_modified()
669
-
670
- if create:
671
- self.close()
672
- self.open()
654
+ def open(self):
655
+ """Open the file."""
656
+ if not self._file:
657
+ self.create_index()
658
+ return self
673
659
 
674
- if create or update:
675
- self._created = os.path.getctime(self._filename)
676
- self._modified = os.path.getmtime(self._filename)
660
+ def close(self):
661
+ """Close the file."""
662
+ self._close_file()
663
+
664
+ def index(self):
665
+ """Get the index of the file."""
666
+ if self._created != os.path.getctime(self._filename):
667
+ self.create_index()
668
+ elif self._modified != os.path.getmtime(self._filename):
669
+ self.update_index()
670
+ return self._index
677
671
 
678
- index_params = dict(
679
- file=self._file,
680
- compressed=self._compressed,
672
+ def create_index(self):
673
+ """Create an index of the file."""
674
+ self._close_file()
675
+ self._open_file()
676
+ self._update_timestamps()
677
+ self._index = Index.from_file(
678
+ self._file,
679
+ verbose=self._verbose,
681
680
  chunk_size=self._chunk_size,
682
- show_progress=show_progress,
681
+ compressed=self._compressed,
683
682
  )
684
683
 
685
- if create:
686
- self._index = Index.from_file(**index_params)
687
- elif update:
688
- index = Index.from_file(**index_params, position=self._index[-1])
689
- self._index.extend(index)
690
-
691
- return self._index
684
+ def update_index(self):
685
+ """Update the index of the file."""
686
+ self._update_timestamps()
687
+ index = Index.from_file(
688
+ self._file,
689
+ verbose=self._verbose,
690
+ chunk_size=self._chunk_size,
691
+ compressed=self._compressed,
692
+ position=self._index[-1],
693
+ )
694
+ self._index.extend(index)
692
695
 
693
696
  def times(self) -> List[float]:
694
697
  """Get the times of the fields in the file.
@@ -748,7 +751,7 @@ class File:
748
751
  """Get a string representation of the geometry."""
749
752
 
750
753
  if self.shape is None or self.spacing is None:
751
- print("Geometry: None")
754
+ self._info("Geometry: None")
752
755
  return
753
756
 
754
757
  dimensions = Field.dimensions(self.shape)
@@ -756,58 +759,57 @@ class File:
756
759
  spacing = np.round(self.spacing, 7)
757
760
  size = cells * spacing
758
761
 
759
- print(
760
- f"Geometry: {dimensions}-Dimensional Grid\n"
761
- f"Grid Size: {tuple(size)}μm³\n"
762
- f"Grid Shape (Cell Count): {tuple(cells)}\n"
763
- f"Grid Spacing (Cell Size): {tuple(spacing)}μm³"
764
- )
762
+ self._info(f"Geometry: {dimensions}-Dimensional Grid")
763
+ self._info(f"Grid Size: {tuple(size)}μm³")
764
+ self._info(f"Grid Shape (Cell Count): {tuple(cells)}")
765
+ self._info(f"Grid Spacing (Cell Size): {tuple(spacing)}μm³")
765
766
 
766
- def iterate(self, show_progress: bool = True):
767
+ def iterate(self):
767
768
  """Iterate over fields in the file.
768
769
 
769
- Args:
770
- show_progress (bool, optional): Show progress bar. Defaults to True.
771
-
772
770
  Returns:
773
771
  Field: Field data.
774
772
  """
775
- for position in self.index(show_progress=show_progress):
773
+ for position in self.index():
776
774
  yield Field.read(position, shape=self.shape, spacing=self.spacing)
777
775
 
778
- def read(
779
- self,
780
- key: int or slice or list or Callable[[Field], bool] = None,
781
- show_progress: bool = True,
782
- ):
776
+ def read(self, key: int or slice or list or Callable[[Field], bool] = None):
783
777
  """Read a field from the file.
784
778
 
785
779
  Args:
786
780
  key (int or list or slice or Callable[[Field], bool], optional): Field ID,
787
781
  list of field IDs, a slice object, or a condition function.
788
782
  Defaults to None.
789
- show_progress (bool, optional): Show progress bar. Defaults to True.
790
783
 
791
784
  Returns:
792
- Field: Field data.
785
+ FieldList: List of fields.
793
786
  """
794
787
 
795
788
  def read_field(self, field_id: int or slice or list):
796
789
  position = self._index[field_id]
797
790
  return Field.read(position, shape=self.shape, spacing=self.spacing)
798
791
 
799
- self.index(show_progress=show_progress)
792
+ def iterable(iterable):
793
+ if self._verbose:
794
+ return utils.progress_indicator(
795
+ iterable, description="Reading", unit="Field"
796
+ )
797
+ return iterable
798
+
799
+ self.index()
800
800
 
801
801
  if key is None:
802
- return FieldList(self.iterate())
803
- if isinstance(key, int):
804
- return read_field(self, key)
805
- if isinstance(key, slice):
806
- start, stop, step = key.start, key.stop, key.step
807
- key = list(range(len(self._index))[start:stop:step])
808
- if isinstance(key, list):
809
- return FieldList([read_field(self, i) for i in key])
810
- if isinstance(key, Callable):
811
- return FieldList([field for field in self.iterate() if key(field)])
812
-
813
- raise TypeError("Invalid argument type")
802
+ fields = list(field for field in iterable(self.iterate()))
803
+ elif isinstance(key, int):
804
+ fields = [read_field(self, key)]
805
+ elif isinstance(key, slice):
806
+ indices = range(*key.indices(len(self._index)))
807
+ fields = [read_field(self, i) for i in iterable(indices)]
808
+ elif isinstance(key, list):
809
+ fields = [read_field(self, i) for i in iterable(key)]
810
+ elif isinstance(key, Callable):
811
+ fields = [field for field in iterable(self.iterate()) if key(field)]
812
+ else:
813
+ raise TypeError("Invalid argument type")
814
+
815
+ return FieldList(fields)
micpy/utils.py CHANGED
@@ -8,19 +8,22 @@ def progress_indicator(iterable, description="Progress", unit="Iteration", start
8
8
  """Progress indicator for iterable."""
9
9
 
10
10
  start_time = time.time()
11
+
11
12
  for i, item in enumerate(iterable, start=start):
12
13
  yield item
14
+
13
15
  elapsed_time = time.time() - start_time
14
16
  average_time = elapsed_time / i
15
17
 
16
- print(
17
- f"\r{description}: {unit} {i}. Elapsed Time: {elapsed_time:.2f}s. Average Time/{unit}: {average_time:.2f}s",
18
- end="",
19
- )
20
- # The print method's flush is not guaranteed to work in IPython environments. A
21
- # workaround is to use sys.stdout.flush() instead.
18
+ message = f"\r{description}: {unit} {i}. Elapsed Time: {elapsed_time:.2f}s. Average Time/{unit}: {average_time:.2f}s"
19
+
20
+ sys.stdout.write("\r\x1b[0K") # Clear line
21
+ print(message, end="")
22
22
  sys.stdout.flush()
23
23
 
24
+ print("")
25
+ sys.stdout.flush()
26
+
24
27
 
25
28
  def is_compressed(filename):
26
29
  """Check if a file is compressed."""
micpy/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.2.13b4"
1
+ __version__ = "0.2.15b0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: micress-micpy
3
- Version: 0.2.13b4
3
+ Version: 0.2.15b0
4
4
  Summary: MicPy is a Python package to facilitate MICRESS workflows.
5
5
  Author: Lukas Koschmieder
6
6
  Author-email: l.koschmieder@access-technology.de
@@ -59,6 +59,7 @@ for field in bin.File("A001_Delta_Gamma.conc1"):
59
59
  #### Read all fields
60
60
 
61
61
  ```python
62
+
62
63
  from micpy import bin
63
64
 
64
65
  with bin.File("A001_Delta_Gamma.conc1") as file:
@@ -0,0 +1,12 @@
1
+ micpy/__init__.py,sha256=7wQUaseppjQYZW1iAVNm2WSDjvBLlqtY8tiHsfDaW5Q,148
2
+ micpy/bin.py,sha256=0RB4FTad00sriZvQdHuTvkzT9D4_pLS_eFwpYS7EOhA,26492
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=Kt1AvhMvWer9uftbb88X7N27aXtQdJl26grHmmm2vOQ,859
7
+ micpy/version.py,sha256=tyiEmp3lrfZHINaXvAGtz6wbg_fRgizg1D1jsMt3PXo,26
8
+ micress_micpy-0.2.15b0.dist-info/LICENSE,sha256=seHdCiArizUoWZ6bEFg6N3K2ZtfPK35wvOwg0kH-f6o,1488
9
+ micress_micpy-0.2.15b0.dist-info/METADATA,sha256=Po-1cfNOIsV2m9wU_oj8kKzf2LllWQf-50PQD5O_g3c,3824
10
+ micress_micpy-0.2.15b0.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
11
+ micress_micpy-0.2.15b0.dist-info/top_level.txt,sha256=RiopkpW0AGNYdtOW2eQUWgm3yHGC13q9pWlHb2alhiE,6
12
+ micress_micpy-0.2.15b0.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- micpy/__init__.py,sha256=7wQUaseppjQYZW1iAVNm2WSDjvBLlqtY8tiHsfDaW5Q,148
2
- micpy/bin.py,sha256=k75S6izFjBmNohjjHm-DEOSYp5eCl_iWi_bs-4OFjlc,26530
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=fN2FFRlhOnAe00fdrdGBJvhlPrfqIyIiWK9PY7HQaHQ,919
7
- micpy/version.py,sha256=4G2XnZ6DntBZ0cJueBhEVZgO2A-1Auou_W5b-24qWKk,26
8
- micress_micpy-0.2.13b4.dist-info/LICENSE,sha256=seHdCiArizUoWZ6bEFg6N3K2ZtfPK35wvOwg0kH-f6o,1488
9
- micress_micpy-0.2.13b4.dist-info/METADATA,sha256=7-5BHF15NtEdkxp8pO5Wj6JtAcj3P0TRR_-DfOQB_Q8,3822
10
- micress_micpy-0.2.13b4.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
11
- micress_micpy-0.2.13b4.dist-info/top_level.txt,sha256=RiopkpW0AGNYdtOW2eQUWgm3yHGC13q9pWlHb2alhiE,6
12
- micress_micpy-0.2.13b4.dist-info/RECORD,,