Skip to content

Commit c4686dc

Browse files
committed
Merged codmore-dev
2 parents c1c4971 + e3a2145 commit c4686dc

19 files changed

Lines changed: 549 additions & 97 deletions

File tree

mapmanagercore/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@
1212
__version_tuple__: VERSION_TUPLE
1313
version_tuple: VERSION_TUPLE
1414

15-
__version__ = version = '0.0.post73'
15+
__version__ = version = '0.0.post104'
1616
__version_tuple__ = version_tuple = (0, 0)

mapmanagercore/annotations/base.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
from mapmanagercore.analysis_params import AnalysisParams
2121

22+
from mapmanagercore.analysis_params import AnalysisParams
23+
from mapmanagercore.logger import logger
2224

2325
class AnnotationsBase(LazyImagesGeoPandas):
2426
_images: ImageLoader
@@ -46,18 +48,32 @@ def __init__(self,
4648
Segment, data=lineSegments, store=self)
4749
self._points = LazyGeoFrame(Spine, data=points, store=self)
4850

51+
self.loader = loader
52+
53+
# abb
54+
def __str__(self):
55+
"""Print info about the map.
56+
57+
See: _SingleTimePointAnnotationsBase()
58+
"""
59+
numTimepoints = len(self._images.timePoints())
60+
numPnts = len(self.points._rootDf)
61+
numSegments = len(self.segments._rootDf)
62+
63+
return f't:{numTimepoints}, points:{numPnts} segments:{numSegments} loader:{self.laoder}'
64+
4965
@property
5066
def segments(self) -> LazyGeoFrame:
5167
return self._segments
5268

5369
@property
5470
def points(self) -> LazyGeoFrame:
5571
return self._points
56-
72+
5773
@property
5874
def analysisParams(self) -> AnalysisParams:
5975
return self._analysisParams
60-
76+
6177
def filterPoints(self, filter: Any):
6278
"""
6379
Filters the points.
@@ -130,6 +146,7 @@ def save(self, path: str, compression=zipfile.ZIP_STORED):
130146
with warnings.catch_warnings():
131147
warnings.simplefilter("ignore")
132148

149+
logger.info(f'saving to {path}')
133150
fs = zarr.ZipStore(path, mode="w", compression=compression)
134151
with fs as store:
135152
group = zarr.group(store=store)

mapmanagercore/annotations/mutation.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from ..config import SegmentId, SpineId
44
from .base import AnnotationsBase
55

6+
from mapmanagercore.logger import logger
7+
68
Key = Union[SpineId, Tuple[SpineId, int]]
79
Keys = Union[Key, list[Key]]
810

@@ -20,22 +22,29 @@ def deleteSegment(self, segmentId: Keys, skipLog=False):
2022
"""
2123
try:
2224
if not self.points[["segmentID"]].reset_index().set_index(["segmentID", "t"]).loc[segmentId].empty:
23-
raise ValueError(
24-
f"Cannot delete segment(s) {segmentId} as it has an attached spine(s)")
25+
# abb
26+
logger.info(f'Cannot delete segment(s) {segmentId} as it has an attached spine(s)')
27+
return False
28+
# raise ValueError(
29+
# f"Cannot delete segment(s) {segmentId} as it has an attached spine(s)")
2530
except KeyError:
2631
pass
2732

2833
self._drop("Segment", segmentId, skipLog=skipLog)
29-
34+
return True
35+
3036
def updateSpine(self, spineId: Keys, value: Spine, replaceLog=False, skipLog=False):
3137
"""
3238
Set the spine with the given ID to the specified value.
3339
"""
3440
return self._update("Spine", spineId, value, replaceLog, skipLog)
3541

3642
def updateSegment(self, segmentId: Keys, value: Segment, replaceLog=False, skipLog=False):
37-
"""
38-
Set the segment with the given ID to the specified value.
43+
"""Set the segment with the given ID to the specified value.
44+
45+
Args:
46+
segmentId (str): The ID of the spine.
47+
value (Union[dict, gp.Series, pd.Series]): The value to set for the spine.
3948
"""
4049
return self._update("Segment", segmentId, value, replaceLog, skipLog)
4150

@@ -56,9 +65,14 @@ def newUnassignedSegmentId(self) -> SegmentId:
5665
return self.segments.index.get_level_values(0).max() + 1
5766

5867
def connect(self, spineKey: Tuple[SpineId, int], toSpineKey: Tuple[SpineId, int]):
59-
if self.points[toSpineKey, "segmentID"] != self.points[spineKey, "segmentID"]:
68+
69+
# ValueError: Can only compare identically-labeled Series objects
70+
# if self.points[toSpineKey, "segmentID"] != self.points[spineKey, "segmentID"]:
71+
_segmentID = self.points[spineKey, "segmentID"].values[0]
72+
_toSegmentID = self.points[toSpineKey, "segmentID"].values[0]
73+
if _toSegmentID != _segmentID:
6074
raise ValueError("Cannot connect spines from different segments.")
61-
75+
6276
# check if the key already exists in the time point
6377
existingKey = (toSpineKey[0], spineKey[1])
6478
if existingKey in self.points.index:

mapmanagercore/annotations/single_time_point/base.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
# abb analysisparams
2424
from mapmanagercore.analysis_params import AnalysisParams
2525

26+
from mapmanagercore.logger import logger
2627

2728
class SingleTimePointFrame(LazyGeoFrame):
2829
def __init__(self, frame: LazyGeoFrame, t: int):
@@ -148,6 +149,20 @@ def __init__(self, annotations: Annotations, t: int):
148149

149150
self._t = t
150151

152+
def __str__(self):
153+
logger.info('')
154+
155+
# get the number of time points
156+
numTimepoints = 'abb ???'
157+
try:
158+
numTimepoints = len(self._images._imagesSrcs.keys())
159+
except (AttributeError) as e:
160+
logger.error(e)
161+
162+
numPnts = len(self._annotations._points._rootDf)
163+
numSegments = len(self._annotations._segments._rootDf)
164+
return f't:{numTimepoints}, points:{numPnts} segments:{numSegments}'
165+
151166
@property
152167
def points(self) -> LazyGeoFrame:
153168
return self._points

mapmanagercore/annotations/single_time_point/interactions.py

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,50 +11,56 @@
1111
from shapely.geometry import LineString
1212
import geopandas as gp
1313
from mapmanagercore.logger import logger
14+
from mapmanagercore.logger import logger
1415

1516
pendingBackgroundRoiTranslation = None
1617

1718

1819
class AnnotationsInteractions(AnnotationsSegments):
20+
21+
# abb
22+
def getSpineDistance(self, segmentID: SegmentId,
23+
point: Point):
24+
"""Add doc string
25+
"""
26+
segment: LineString = self.segments[segmentID, "segment"]
27+
# find the closest point on the segment to the `point`
28+
minProjection = segment.project(point)
29+
return minProjection
30+
31+
# abb added findBrightest=False, do not find brightest by default
1932
def nearestAnchor(self, segmentID: SegmentId,
2033
point: Point,
21-
useBrightestPath=False,
22-
brightestPathDistance: int = None,
23-
channel: int = None,
24-
zSpread: int = None):
25-
"""
26-
Finds the nearest anchor point on a given line segment to a given point.
34+
findBrightest : bool = False):
35+
"""Finds the nearest anchor point on a given line segment to a given point.
2736
2837
Args:
2938
segmentID (SegmentId): The ID of the line segment.
3039
point (Point): The point to find the nearest anchor to.
31-
brightestPathDistance (int): The distance to search for the brightest path. Defaults to None.
32-
channel (int): The channel. Defaults to 0.
33-
zSpread (int): The z spread. Defaults to 0.
40+
findBrightest (bool): Default False.
41+
If True then find the brightest anchor using image data.
3442
3543
Returns:
3644
Point: The nearest anchor point.
37-
"""
38-
45+
"""
3946
segment: LineString = self.segments[segmentID, "segment"]
4047
# find the closest point on the segment to the `point`
4148
minProjection = segment.project(point)
42-
43-
if not useBrightestPath:
44-
# Default to the closest path
49+
50+
if np.isnan(minProjection):
51+
logger.warning(f'minProjection:{minProjection}')
52+
logger.warning(f'segment:{segment}')
53+
logger.warning(f'point:{point}')
54+
55+
if not findBrightest:
56+
# Default to the closest point (not brightest)
4557
anchor = segment.interpolate(minProjection)
4658
anchor = roundPoint(anchor, 1)
4759
return anchor
4860

49-
# abb analysisparams
50-
# if not specified, get defaults from AnalysisParams()
51-
if brightestPathDistance is None:
52-
brightestPathDistance = self.analysisParams.getValue(
53-
'brightestPathDistance')
54-
if channel is None:
55-
channel = self.analysisParams.getValue('channel')
56-
if zSpread is None:
57-
zSpread = self.analysisParams.getValue('zSpread')
61+
brightestPathDistance = self.analysisParams.getValue('brightestPathDistance')
62+
channel = self.analysisParams.getValue('channel')
63+
zSpread = self.analysisParams.getValue('zSpread')
5864

5965
segmentLength = int(segment.length)
6066
minProjection = int(minProjection)
@@ -121,7 +127,10 @@ def addSpine(self, segmentId: SpineId, x: int, y: int, z: int) -> Union[SpineId,
121127
z (int): The z coordinate of the spine.
122128
"""
123129
point = Point(x, y, z)
124-
anchor = self.nearestAnchor(segmentId, point)
130+
131+
logger.error(f'1 FutureWarning: The `drop` keyword ...')
132+
anchor = self.nearestAnchor(segmentId, point, findBrightest=True)
133+
125134
spineId = self.newUnassignedSpineId()
126135

127136
self.updateSpine(spineId, Spine.withDefaults(
@@ -134,6 +143,7 @@ def addSpine(self, segmentId: SpineId, x: int, y: int, z: int) -> Union[SpineId,
134143
yBackgroundOffset=0.0,
135144
))
136145

146+
logger.error(f'4 FutureWarning: The `drop` keyword ...')
137147
self.snapBackgroundOffset(spineId)
138148

139149
return spineId
@@ -169,7 +179,9 @@ def moveSpine(self, spineId: SpineId, x: int, y: int, z: int, state: DragState =
169179

170180
return True
171181

172-
def moveAnchor(self, spineId: SpineId, x: int, y: int, z: int, state: DragState = DragState.MANUAL) -> bool:
182+
def moveAnchor(self, spineId: SpineId,
183+
x: int, y: int, z: int,
184+
state: DragState = DragState.MANUAL) -> bool:
173185
"""
174186
Moves the anchor point of a spine to the given x and y coordinates.
175187
@@ -183,6 +195,9 @@ def moveAnchor(self, spineId: SpineId, x: int, y: int, z: int, state: DragState
183195
bool: True if the anchor point was successfully translated, False otherwise.
184196
"""
185197
segmentId = self.points[spineId, "segmentID"]
198+
199+
# abb
200+
# when moving, do not find brightest
186201
anchor = self.nearestAnchor(segmentId, Point(x, y, z))
187202

188203
logger.info(f'segmentId:{segmentId} anchor:{anchor}')
@@ -310,9 +325,9 @@ def newSegment(self) -> Union[SegmentId, None]:
310325
311326
Returns:
312327
int: The ID of the new segment.
313-
"""
328+
"""
314329
segmentId = self.newUnassignedSegmentId()
315-
330+
316331
self.updateSegment(segmentId, Segment.withDefaults(
317332
segment=LineString([]),
318333
roughTracing=LineString([])
@@ -346,8 +361,7 @@ def injectSegmentPoint(self, segmentId: SegmentId, x: int, y: int, z: int):
346361
return idx
347362

348363
def appendSegmentPoint(self, segmentId: SegmentId, x: int, y: int, z: int, speculate: bool = False) -> LineString:
349-
"""
350-
Adds a point to a segment.
364+
"""Adds a point to a segment.
351365
352366
Args:
353367
segmentId (str): The ID of the segment.

mapmanagercore/layers/line.py

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
import shapely
99
import geopandas as gp
1010
from ..benchmark import timer
11-
11+
import math
12+
from math import pi as PI
1213

1314
class MultiLineLayer(Layer):
1415
@Layer.setProperty
@@ -105,6 +106,77 @@ def head(self):
105106
def getTail(d):
106107
return Point(d.coords[1][0], d.coords[1][1])
107108

109+
# abj
110+
def getSide(a: Point, b: Point, c: Point):
111+
""" Calculate which side a point (c) is relative to a segment (AB)
112+
Args:
113+
a: Beginning point of line segment
114+
b: End point of line segment
115+
c: Point relative to line segment
116+
"""
117+
crossProduct = (b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x)
118+
if crossProduct > 0:
119+
return "Right"
120+
elif crossProduct < 0:
121+
return "Left"
122+
else:
123+
return "On the Line"
124+
125+
# abj
126+
@ timer
127+
def getSpineSide(line: LineString, spine: Point):
128+
""" Return a string representing the side at which the spine point is relative to its segment
129+
130+
Args:
131+
Line: segment in the for of a LineString
132+
Spine: point
133+
"""
134+
first = Point(line.coords[0])
135+
last = Point(line.coords[-1])
136+
val = getSide(first, last, spine)
137+
return val
138+
139+
# abj
140+
@ timer
141+
def getSpineAngle(segmentLine: LineString, spineLine: LineString):
142+
""" Return the angle between the two Lines
143+
Line 1: The line formed between the spine head and the anchor point
144+
Line 2: The line formed by two points on the segment tracing.
145+
Grab two points, one “up” and the other “down” the segment from the spine anchor point.
146+
I think the anchor point on the segment tracing is our new “position”.
147+
148+
Args:
149+
segmentLine: segment in the for of a LineString
150+
spineLine: Linestring of spine head to anchor point
151+
"""
152+
spineLineCoord0 = Point(spineLine.coords[0])
153+
spineLineCoord1 = Point(spineLine.coords[1])
154+
sl0x = spineLineCoord0.x
155+
sl0y = spineLineCoord0.y
156+
sl1x = spineLineCoord1.x
157+
sl1y = spineLineCoord1.y
158+
159+
segmentLineCoord0 = Point(segmentLine.coords[0])
160+
segmentLineCoord1 = Point(segmentLine.coords[-1])
161+
sgl0x = segmentLineCoord0.x
162+
sgl0y = segmentLineCoord0.y
163+
sgl1x = segmentLineCoord1.x
164+
sgl1y = segmentLineCoord1.y
165+
166+
m1 = (sl1y-sl0y)/(sl1x-sl0x)
167+
m2 = (sgl1y-sgl0y)/(sgl1x-sgl0x)
168+
169+
angle_rad = math.atan(m1) - math.atan(m2)
170+
angle_deg = angle_rad*180/PI
171+
172+
# Range: 0 - 360
173+
# Check for Negative angle and add 360 degrees to determine counter clockwise value
174+
if angle_deg < 0:
175+
angle_deg = angle_deg + 360
176+
177+
# print("m1", m1, "m2", m2, "degree:", angle_deg)
178+
179+
return angle_deg
108180

109181
@timer
110182
def calcSubLine(line: LineLayer, origin: Point, distance: int):

mapmanagercore/layers/polygon.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import geopandas as gp
66
from shapely.geometry import Polygon, Point
77

8+
from mapmanagercore.logger import logger
89

910
class PolygonLayer(Layer):
1011
def box(minx, miny, maxx, maxy):

mapmanagercore/lazy_geo_pandas/lazy.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import geopandas as gp
1414
from collections.abc import Sequence
1515

16+
from mapmanagercore.logger import logger
1617

1718
class LazyGeoPandas:
1819
"""

0 commit comments

Comments
 (0)