11from copy import copy
2- from typing import Any , Tuple
2+ from io import BytesIO
3+ from typing import Any , Tuple , Union
34import zipfile
45import numpy as np
56import pandas as pd
67
78from mapmanagercore .benchmark import timer
8- from mapmanagercore .config import COLORS , scaleColors , symbols
9+ from mapmanagercore .config import Colors , scaleColors , symbols
10+ from mapmanagercore .lazy_geo_pd_images .loader .zarr import ZarrLoader
911from ..lazy_geo_pandas import LazyGeoFrame
1012from ..schemas import Segment , Spine
11- from ..lazy_geo_pd_image import LazyImagesGeoPandas
12- from ..image_slices import ImageSlice
13- from ..loader .base import ImageLoader , Loader
13+ from ..lazy_geo_pd_images import LazyImagesGeoPandas , ImageLoader
14+ from ..lazy_geo_pd_images .image_slices import ImageSlice
1415import zarr
1516import warnings
1617from plotly .express .colors import sample_colorscale
18+ import geopandas as gp
1719
1820from mapmanagercore .analysis_params import AnalysisParams
19- from mapmanagercore .logger import logger
2021
2122
2223class AnnotationsBase (LazyImagesGeoPandas ):
2324 _images : ImageLoader
2425
25- def __init__ (self , loader : Loader ):
26- super ().__init__ (loader .images ())
26+ def __init__ (self ,
27+ loader : ImageLoader ,
28+ lineSegments : Union [str , pd .DataFrame ] = pd .DataFrame (),
29+ points : Union [str , pd .DataFrame ] = pd .DataFrame (),
30+ analysisParams : AnalysisParams = AnalysisParams ()):
2731
28- self ._segments = LazyGeoFrame (
29- Segment , data = loader .segments (), store = self )
30- self ._points = LazyGeoFrame (Spine , data = loader .points (), store = self )
32+ super ().__init__ (loader )
33+
34+ if not isinstance (lineSegments , gp .GeoDataFrame ):
35+ if not isinstance (lineSegments , pd .DataFrame ):
36+ lineSegments = pd .read_csv (lineSegments , index_col = False )
37+
38+ if not isinstance (points , gp .GeoDataFrame ):
39+ if not isinstance (points , pd .DataFrame ):
40+ points = pd .read_csv (points , index_col = False )
3141
3242 # abb analysisparams
33- self ._analysisParams : AnalysisParams = loader .analysisParams ()
43+ self ._analysisParams : AnalysisParams = analysisParams
44+
45+ self ._segments = LazyGeoFrame (
46+ Segment , data = lineSegments , store = self )
47+ self ._points = LazyGeoFrame (Spine , data = points , store = self )
3448
3549 @property
3650 def segments (self ) -> LazyGeoFrame :
@@ -45,16 +59,25 @@ def analysisParams(self) -> AnalysisParams:
4559 return self ._analysisParams
4660
4761 def filterPoints (self , filter : Any ):
62+ """
63+ Filters the points.
64+ """
4865 c = copy (self )
4966 c ._points = c ._points [filter ]
5067 return c
5168
5269 def filterSegments (self , filter : Any ):
70+ """
71+ Filters the segments.
72+ """
5373 c = copy (self )
5474 c ._segments = c ._segments [filter ]
5575 return c
5676
5777 def getTimePoint (self , time : int ):
78+ """
79+ Returns the annotations for a single time point.
80+ """
5881 from .single_time_point import SingleTimePointAnnotations
5982 return SingleTimePointAnnotations (self , time )
6083
@@ -83,10 +106,26 @@ def getPixels(self, time: int, channel: int, zRange: Tuple[int, int] = None, z:
83106
84107 return super ().getPixels (time , channel , zRange )
85108
109+ # Serialization
110+
111+ @classmethod
112+ def load (cls , path : str , lazy = False ):
113+ loader = ZarrLoader (path , lazy = lazy )
114+ points = pd .read_pickle (BytesIO (loader .group ["points" ][:].tobytes ()))
115+ points = gp .GeoDataFrame (points , geometry = "point" )
116+ lineSegments = pd .read_pickle (
117+ BytesIO (loader .group ["lineSegments" ][:].tobytes ()))
118+ lineSegments = gp .GeoDataFrame (lineSegments , geometry = "segment" )
119+
120+ # abb analysisparams
121+ _analysisParams_json = loader .group .attrs ['analysisParams' ] # json str
122+ analysisParams = AnalysisParams (loadJson = _analysisParams_json )
123+
124+ return cls (loader , lineSegments , points , analysisParams )
125+
86126 def save (self , path : str , compression = zipfile .ZIP_STORED ):
87127 if not path .endswith (".mmap" ):
88- raise ValueError (
89- "Invalid file format. Please provide a path ending with '.mmap'." )
128+ path += ".mmap"
90129
91130 with warnings .catch_warnings ():
92131 warnings .simplefilter ("ignore" )
@@ -104,6 +143,8 @@ def save(self, path: str, compression=zipfile.ZIP_STORED):
104143 # abb analysisparams
105144 group .attrs ['analysisParams' ] = self ._analysisParams .getJson ()
106145
146+ # Context manager
147+
107148 def __enter__ (self ):
108149 self ._images = self ._images .__enter__ ()
109150 return self
@@ -115,12 +156,17 @@ def close(self):
115156 self ._images .close ()
116157 return
117158
159+ # Utility functions
160+
118161 @timer
119162 def getColors (self , colorOn : str = None , function = False ) -> pd .Series :
163+ """
164+ Returns the colors of the points.
165+ """
120166 if colorOn is None :
121167 if function :
122- return lambda _ : COLORS [ " spine" ]
123- return pd .Series ([COLORS [ " spine" ] ] * len (self .points ), index = self .points .index )
168+ return lambda _ : Colors . spine
169+ return pd .Series ([Colors . spine ] * len (self .points ), index = self .points .index )
124170
125171 categorical = False
126172 if colorOn not in self .points .columnsAttributes :
@@ -130,12 +176,12 @@ def getColors(self, colorOn: str = None, function=False) -> pd.Series:
130176 if "colors" in attr :
131177 colors = attr ["colors" ]
132178 elif "categorical" in attr and attr ["categorical" ]:
133- colors = COLORS [ " categorical" ]
179+ colors = Colors . categorical
134180 categorical = True
135181 elif "divergent" in attr and attr ["divergent" ]:
136- colors = COLORS [ " divergent" ]
182+ colors = Colors . divergent
137183 else :
138- colors = COLORS [ " scalar" ]
184+ colors = Colors . scalar
139185
140186 if colorOn in self .points .index .names :
141187 values = pd .Series (self .points .index .get_level_values (
@@ -176,6 +222,9 @@ def extractColor(x):
176222
177223 @timer
178224 def getSymbols (self , shapeOn : str = None , function = False ) -> pd .Series :
225+ """
226+ Returns the symbols of the points.
227+ """
179228 if shapeOn is None :
180229 if function :
181230 return lambda _ : "circle"
0 commit comments