Skip to content

Commit 04651a7

Browse files
committed
Add AnnotatedPolygon annotation to items
1 parent eb8789e commit 04651a7

13 files changed

Lines changed: 222 additions & 39 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog #
22

3+
## Version 2.6.3 ##
4+
5+
💥 New features / Enhancements:
6+
7+
* Added `AnnotatedPolygon` annotation to items
8+
* Added `make.annotated_polygon` function to `plotpy.builder` module
9+
310
## Version 2.6.2 ##
411

512
💥 New features / Enhancements:

doc/features/items/builder.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ used to simplify the creation of plot items.
1212
:members:
1313

1414
.. autoclass:: plotpy.builder.PlotBuilder
15-
:members: widget,dialog,window,gridparam,grid,mcurve,pcurve,curve,merror,perror,error,histogram,phistogram,range,vcursor,hcursor,xcursor,marker,image,maskedimage,maskedxyimage,rgbimage,quadgrid,pcolor,trimage,xyimage,imagefilter,contours,histogram2D,rectangle,ellipse,polygon,circle,segment,svg,annotated_point,annotated_rectangle,annotated_ellipse,annotated_circle,annotated_segment,label,legend,info_label,range_info_label,computation,computations,computation2d,computations2d
15+
:members: widget,dialog,window,gridparam,grid,mcurve,pcurve,curve,merror,perror,error,histogram,phistogram,range,vcursor,hcursor,xcursor,marker,image,maskedimage,maskedxyimage,rgbimage,quadgrid,pcolor,trimage,xyimage,imagefilter,contours,histogram2D,rectangle,ellipse,polygon,circle,segment,svg,annotated_point,annotated_rectangle,annotated_ellipse,annotated_circle,annotated_segment,annotated_polygon,label,legend,info_label,range_info_label,computation,computations,computation2d,computations2d

doc/features/items/overview.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ The following annotation items are available:
7575
* :py:class:`.AnnotatedObliqueRectangle`
7676
* :py:class:`.AnnotatedEllipse`
7777
* :py:class:`.AnnotatedCircle`
78+
* :py:class:`.AnnotatedPolygon`
7879

7980
Labels
8081
^^^^^^

doc/features/items/reference.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ Annotations
124124
:members:
125125
.. autoclass:: plotpy.items.AnnotatedCircle
126126
:members:
127+
.. autoclass:: plotpy.items.AnnotatedPolygon
128+
:members:
127129

128130
Labels
129131
^^^^^^

plotpy/builder/annotation.py

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
AnnotatedCircle,
2828
AnnotatedEllipse,
2929
AnnotatedPoint,
30+
AnnotatedPolygon,
3031
AnnotatedRectangle,
3132
AnnotatedSegment,
3233
)
@@ -126,10 +127,7 @@ def annotated_point(
126127
def __annotated_shape(
127128
self,
128129
shapeclass,
129-
x0,
130-
y0,
131-
x1,
132-
y1,
130+
points,
133131
title,
134132
subtitle,
135133
show_label,
@@ -153,7 +151,10 @@ def __annotated_shape(
153151
readonly=readonly,
154152
private=private,
155153
)
156-
shape = shapeclass(x0, y0, x1, y1, param)
154+
if isinstance(points, np.ndarray):
155+
shape = shapeclass(points, annotationparam=param)
156+
else:
157+
shape = shapeclass(*points, annotationparam=param)
157158
shape.set_style("plot", "shape/drag")
158159
return shape
159160

@@ -195,12 +196,10 @@ def annotated_rectangle(
195196
Returns:
196197
:py:class:`.AnnotatedRectangle` object
197198
"""
199+
points = x0, y0, x1, y1
198200
return self.__annotated_shape(
199201
AnnotatedRectangle,
200-
x0,
201-
y0,
202-
x1,
203-
y1,
202+
points,
204203
title,
205204
subtitle,
206205
show_label,
@@ -259,12 +258,10 @@ def annotated_ellipse(
259258
Returns:
260259
:py:class:`.AnnotatedEllipse` object
261260
"""
261+
points = x0, y0, x1, y1
262262
item = self.__annotated_shape(
263263
AnnotatedEllipse,
264-
x0,
265-
y0,
266-
x1,
267-
y1,
264+
points,
268265
title,
269266
subtitle,
270267
show_label,
@@ -318,12 +315,10 @@ def annotated_circle(
318315
Returns:
319316
:py:class:`.AnnotatedCircle` object
320317
"""
318+
points = x0, y0, x1, y1
321319
return self.__annotated_shape(
322320
AnnotatedCircle,
323-
x0,
324-
y0,
325-
x1,
326-
y1,
321+
points,
327322
title,
328323
subtitle,
329324
show_label,
@@ -374,12 +369,57 @@ def annotated_segment(
374369
Returns:
375370
:py:class:`.AnnotatedSegment` object
376371
"""
372+
points = x0, y0, x1, y1
377373
return self.__annotated_shape(
378374
AnnotatedSegment,
379-
x0,
380-
y0,
381-
x1,
382-
y1,
375+
points,
376+
title,
377+
subtitle,
378+
show_label,
379+
show_computations,
380+
show_subtitle,
381+
format,
382+
uncertainty,
383+
transform_matrix,
384+
readonly,
385+
private,
386+
)
387+
388+
def annotated_polygon(
389+
self,
390+
points: np.ndarray,
391+
title: str | None = None,
392+
subtitle: str | None = None,
393+
show_label: bool | None = None,
394+
show_computations: bool | None = None,
395+
show_subtitle: bool | None = None,
396+
format: str | None = None,
397+
uncertainty: float | None = None,
398+
transform_matrix: np.ndarray | None = None,
399+
readonly: bool | None = None,
400+
private: bool | None = None,
401+
) -> AnnotatedPolygon:
402+
"""Make an annotated polygon `plot item`
403+
404+
Args:
405+
points: polygon points
406+
title: label name. Default is None
407+
subtitle: label subtitle. Default is None
408+
show_label: show label. Default is None
409+
show_computations: show computations. Default is None
410+
show_subtitle: show subtitle. Default is None
411+
format: string formatting. Default is None
412+
uncertainty: measurement relative uncertainty. Default is None
413+
transform_matrix: transform matrix. Default is None
414+
readonly: readonly. Default is None
415+
private: private. Default is None
416+
417+
Returns:
418+
:py:class:`.AnnotatedPolygon` object
419+
"""
420+
return self.__annotated_shape(
421+
AnnotatedPolygon,
422+
points,
383423
title,
384424
subtitle,
385425
show_label,

plotpy/io.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ def register_serializable_items(modname, classnames):
620620
"AnnotatedObliqueRectangle",
621621
"AnnotatedEllipse",
622622
"AnnotatedCircle",
623+
"AnnotatedPolygon",
623624
"LabelItem",
624625
"LegendBoxItem",
625626
"SelectedLegendBoxItem",

plotpy/items/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
AnnotatedObliqueRectangle,
1010
AnnotatedPoint,
1111
AnnotatedRectangle,
12+
AnnotatedPolygon,
1213
AnnotatedSegment,
1314
AnnotatedShape,
1415
)

plotpy/items/annotation.py

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from plotpy.items.shape.base import AbstractShape
2929
from plotpy.items.shape.ellipse import EllipseShape
3030
from plotpy.items.shape.point import PointShape
31+
from plotpy.items.shape.polygon import PolygonShape
3132
from plotpy.items.shape.rectangle import ObliqueRectangleShape, RectangleShape
3233
from plotpy.items.shape.segment import SegmentShape
3334
from plotpy.mathutils.geometry import (
@@ -461,9 +462,8 @@ def boundingRect(self) -> QRectF:
461462

462463
class AnnotatedPoint(AnnotatedShape):
463464
"""
464-
Construct an annotated point at coordinates (x, y)
465-
with properties set with *annotationparam*
466-
(see :py:class:`.styles.AnnotationParam`)
465+
Construct an annotated point at coordinates (x, y) with properties set with
466+
*annotationparam* (see :py:class:`.styles.AnnotationParam`)
467467
"""
468468

469469
SHAPE_CLASS = PointShape
@@ -575,6 +575,92 @@ def get_infos(self) -> str:
575575
)
576576

577577

578+
class AnnotatedPolygon(AnnotatedShape):
579+
"""
580+
Construct an annotated polygon with properties set with *annotationparam*
581+
(see :py:class:`.styles.AnnotationParam`)
582+
583+
Args:
584+
points: List of points
585+
closed: True if polygon is closed
586+
annotationparam: Annotation parameters
587+
"""
588+
589+
SHAPE_CLASS = PolygonShape
590+
LABEL_ANCHOR = "C"
591+
592+
def __init__(
593+
self,
594+
points: list[tuple[float, float]] | None = None,
595+
closed: bool | None = None,
596+
annotationparam: AnnotationParam | None = None,
597+
) -> None:
598+
super().__init__(annotationparam)
599+
self.shape: PolygonShape
600+
if points is not None:
601+
self.set_points(points)
602+
if closed is not None:
603+
self.set_closed(closed)
604+
self.setIcon(get_icon("polygon.png"))
605+
606+
# ----Public API-------------------------------------------------------------
607+
def set_points(self, points: list[tuple[float, float]] | None) -> None:
608+
"""Set the polygon points
609+
610+
Args:
611+
points: List of point coordinates
612+
"""
613+
self.shape.set_points(points)
614+
self.set_label_position()
615+
616+
def get_points(self) -> list[tuple[float, float]]:
617+
"""Return the polygon points"""
618+
return self.shape.get_points()
619+
620+
def set_closed(self, state: bool) -> None:
621+
"""Set the polygon closed state
622+
623+
Args:
624+
state: True if polygon is closed
625+
"""
626+
self.shape.set_closed(state)
627+
628+
def is_closed(self) -> bool:
629+
"""Return True if polygon is closed
630+
631+
Returns:
632+
True if polygon is closed
633+
"""
634+
return self.shape.is_closed()
635+
636+
# ----AnnotatedShape API-----------------------------------------------------
637+
def create_shape(self):
638+
"""Return the shape object associated to this annotated shape object"""
639+
shape = self.SHAPE_CLASS() # pylint: disable=not-callable
640+
return shape
641+
642+
def set_label_position(self) -> None:
643+
"""Set label position, for instance based on shape position"""
644+
x, y = self.shape.get_center()
645+
self.label.set_pos(x, y)
646+
647+
def get_tr_center(self) -> tuple[float, float]:
648+
"""Return shape center coordinates after applying transform matrix"""
649+
return self.shape.get_center()
650+
651+
def get_infos(self) -> str:
652+
"""Get informations on current shape
653+
654+
Returns:
655+
str: Formatted string with informations on current shape
656+
"""
657+
return "<br>".join(
658+
[
659+
_("Center:") + " " + self.get_tr_center_str(),
660+
]
661+
)
662+
663+
578664
class AnnotatedRectangle(AnnotatedShape):
579665
"""
580666
Construct an annotated rectangle between coordinates (x1, y1) and

plotpy/items/shape/polygon.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,32 @@ def get_points(self) -> np.ndarray:
154154
"""
155155
return self.points
156156

157+
def set_closed(self, state: bool) -> None:
158+
"""Set closed state
159+
160+
Args:
161+
state: True if the polygon is closed, False otherwise
162+
"""
163+
self.closed = state
164+
165+
def is_closed(self) -> bool:
166+
"""Return True if the polygon is closed, False otherwise
167+
168+
Returns:
169+
True if the polygon is closed, False otherwise
170+
"""
171+
return self.closed
172+
173+
def get_center(self) -> tuple[float, float]:
174+
"""Return the center of the polygon
175+
176+
Returns:
177+
Center of the polygon
178+
"""
179+
if self.points is not None and self.points.size > 0:
180+
return self.points.mean(axis=0)
181+
return 0.0, 0.0
182+
157183
def boundingRect(self) -> QC.QRectF:
158184
"""Return the bounding rectangle of the data
159185

plotpy/plot/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
AnnotatedEllipse,
4343
AnnotatedObliqueRectangle,
4444
AnnotatedPoint,
45+
AnnotatedPolygon,
4546
AnnotatedRectangle,
4647
AnnotatedSegment,
4748
BaseImageItem,
@@ -2369,3 +2370,4 @@ def register_autoscale_type(cls, type_):
23692370
BasePlot.register_autoscale_type(AnnotatedObliqueRectangle)
23702371
BasePlot.register_autoscale_type(AnnotatedSegment)
23712372
BasePlot.register_autoscale_type(AnnotatedPoint)
2373+
BasePlot.register_autoscale_type(AnnotatedPolygon)

0 commit comments

Comments
 (0)