Skip to content

Commit

Permalink
Add AnnotatedPolygon annotation to items
Browse files Browse the repository at this point in the history
  • Loading branch information
PierreRaybaut committed Sep 3, 2024
1 parent eb8789e commit 04651a7
Show file tree
Hide file tree
Showing 13 changed files with 222 additions and 39 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog #

## Version 2.6.3 ##

💥 New features / Enhancements:

* Added `AnnotatedPolygon` annotation to items
* Added `make.annotated_polygon` function to `plotpy.builder` module

## Version 2.6.2 ##

💥 New features / Enhancements:
Expand Down
2 changes: 1 addition & 1 deletion doc/features/items/builder.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ used to simplify the creation of plot items.
:members:

.. autoclass:: plotpy.builder.PlotBuilder
: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
: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
1 change: 1 addition & 0 deletions doc/features/items/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ The following annotation items are available:
* :py:class:`.AnnotatedObliqueRectangle`
* :py:class:`.AnnotatedEllipse`
* :py:class:`.AnnotatedCircle`
* :py:class:`.AnnotatedPolygon`

Labels
^^^^^^
Expand Down
2 changes: 2 additions & 0 deletions doc/features/items/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ Annotations
:members:
.. autoclass:: plotpy.items.AnnotatedCircle
:members:
.. autoclass:: plotpy.items.AnnotatedPolygon
:members:

Labels
^^^^^^
Expand Down
82 changes: 61 additions & 21 deletions plotpy/builder/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
AnnotatedCircle,
AnnotatedEllipse,
AnnotatedPoint,
AnnotatedPolygon,
AnnotatedRectangle,
AnnotatedSegment,
)
Expand Down Expand Up @@ -126,10 +127,7 @@ def annotated_point(
def __annotated_shape(
self,
shapeclass,
x0,
y0,
x1,
y1,
points,
title,
subtitle,
show_label,
Expand All @@ -153,7 +151,10 @@ def __annotated_shape(
readonly=readonly,
private=private,
)
shape = shapeclass(x0, y0, x1, y1, param)
if isinstance(points, np.ndarray):
shape = shapeclass(points, annotationparam=param)
else:
shape = shapeclass(*points, annotationparam=param)
shape.set_style("plot", "shape/drag")
return shape

Expand Down Expand Up @@ -195,12 +196,10 @@ def annotated_rectangle(
Returns:
:py:class:`.AnnotatedRectangle` object
"""
points = x0, y0, x1, y1
return self.__annotated_shape(
AnnotatedRectangle,
x0,
y0,
x1,
y1,
points,
title,
subtitle,
show_label,
Expand Down Expand Up @@ -259,12 +258,10 @@ def annotated_ellipse(
Returns:
:py:class:`.AnnotatedEllipse` object
"""
points = x0, y0, x1, y1
item = self.__annotated_shape(
AnnotatedEllipse,
x0,
y0,
x1,
y1,
points,
title,
subtitle,
show_label,
Expand Down Expand Up @@ -318,12 +315,10 @@ def annotated_circle(
Returns:
:py:class:`.AnnotatedCircle` object
"""
points = x0, y0, x1, y1
return self.__annotated_shape(
AnnotatedCircle,
x0,
y0,
x1,
y1,
points,
title,
subtitle,
show_label,
Expand Down Expand Up @@ -374,12 +369,57 @@ def annotated_segment(
Returns:
:py:class:`.AnnotatedSegment` object
"""
points = x0, y0, x1, y1
return self.__annotated_shape(
AnnotatedSegment,
x0,
y0,
x1,
y1,
points,
title,
subtitle,
show_label,
show_computations,
show_subtitle,
format,
uncertainty,
transform_matrix,
readonly,
private,
)

def annotated_polygon(
self,
points: np.ndarray,
title: str | None = None,
subtitle: str | None = None,
show_label: bool | None = None,
show_computations: bool | None = None,
show_subtitle: bool | None = None,
format: str | None = None,
uncertainty: float | None = None,
transform_matrix: np.ndarray | None = None,
readonly: bool | None = None,
private: bool | None = None,
) -> AnnotatedPolygon:
"""Make an annotated polygon `plot item`
Args:
points: polygon points
title: label name. Default is None
subtitle: label subtitle. Default is None
show_label: show label. Default is None
show_computations: show computations. Default is None
show_subtitle: show subtitle. Default is None
format: string formatting. Default is None
uncertainty: measurement relative uncertainty. Default is None
transform_matrix: transform matrix. Default is None
readonly: readonly. Default is None
private: private. Default is None
Returns:
:py:class:`.AnnotatedPolygon` object
"""
return self.__annotated_shape(
AnnotatedPolygon,
points,
title,
subtitle,
show_label,
Expand Down
1 change: 1 addition & 0 deletions plotpy/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,7 @@ def register_serializable_items(modname, classnames):
"AnnotatedObliqueRectangle",
"AnnotatedEllipse",
"AnnotatedCircle",
"AnnotatedPolygon",
"LabelItem",
"LegendBoxItem",
"SelectedLegendBoxItem",
Expand Down
1 change: 1 addition & 0 deletions plotpy/items/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
AnnotatedObliqueRectangle,
AnnotatedPoint,
AnnotatedRectangle,
AnnotatedPolygon,
AnnotatedSegment,
AnnotatedShape,
)
Expand Down
92 changes: 89 additions & 3 deletions plotpy/items/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from plotpy.items.shape.base import AbstractShape
from plotpy.items.shape.ellipse import EllipseShape
from plotpy.items.shape.point import PointShape
from plotpy.items.shape.polygon import PolygonShape
from plotpy.items.shape.rectangle import ObliqueRectangleShape, RectangleShape
from plotpy.items.shape.segment import SegmentShape
from plotpy.mathutils.geometry import (
Expand Down Expand Up @@ -461,9 +462,8 @@ def boundingRect(self) -> QRectF:

class AnnotatedPoint(AnnotatedShape):
"""
Construct an annotated point at coordinates (x, y)
with properties set with *annotationparam*
(see :py:class:`.styles.AnnotationParam`)
Construct an annotated point at coordinates (x, y) with properties set with
*annotationparam* (see :py:class:`.styles.AnnotationParam`)
"""

SHAPE_CLASS = PointShape
Expand Down Expand Up @@ -575,6 +575,92 @@ def get_infos(self) -> str:
)


class AnnotatedPolygon(AnnotatedShape):
"""
Construct an annotated polygon with properties set with *annotationparam*
(see :py:class:`.styles.AnnotationParam`)
Args:
points: List of points
closed: True if polygon is closed
annotationparam: Annotation parameters
"""

SHAPE_CLASS = PolygonShape
LABEL_ANCHOR = "C"

def __init__(
self,
points: list[tuple[float, float]] | None = None,
closed: bool | None = None,
annotationparam: AnnotationParam | None = None,
) -> None:
super().__init__(annotationparam)
self.shape: PolygonShape
if points is not None:
self.set_points(points)
if closed is not None:
self.set_closed(closed)
self.setIcon(get_icon("polygon.png"))

# ----Public API-------------------------------------------------------------
def set_points(self, points: list[tuple[float, float]] | None) -> None:
"""Set the polygon points
Args:
points: List of point coordinates
"""
self.shape.set_points(points)
self.set_label_position()

def get_points(self) -> list[tuple[float, float]]:
"""Return the polygon points"""
return self.shape.get_points()

def set_closed(self, state: bool) -> None:
"""Set the polygon closed state
Args:
state: True if polygon is closed
"""
self.shape.set_closed(state)

def is_closed(self) -> bool:
"""Return True if polygon is closed
Returns:
True if polygon is closed
"""
return self.shape.is_closed()

# ----AnnotatedShape API-----------------------------------------------------
def create_shape(self):
"""Return the shape object associated to this annotated shape object"""
shape = self.SHAPE_CLASS() # pylint: disable=not-callable
return shape

def set_label_position(self) -> None:
"""Set label position, for instance based on shape position"""
x, y = self.shape.get_center()
self.label.set_pos(x, y)

def get_tr_center(self) -> tuple[float, float]:
"""Return shape center coordinates after applying transform matrix"""
return self.shape.get_center()

def get_infos(self) -> str:
"""Get informations on current shape
Returns:
str: Formatted string with informations on current shape
"""
return "<br>".join(
[
_("Center:") + " " + self.get_tr_center_str(),
]
)


class AnnotatedRectangle(AnnotatedShape):
"""
Construct an annotated rectangle between coordinates (x1, y1) and
Expand Down
26 changes: 26 additions & 0 deletions plotpy/items/shape/polygon.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,32 @@ def get_points(self) -> np.ndarray:
"""
return self.points

def set_closed(self, state: bool) -> None:
"""Set closed state
Args:
state: True if the polygon is closed, False otherwise
"""
self.closed = state

def is_closed(self) -> bool:
"""Return True if the polygon is closed, False otherwise
Returns:
True if the polygon is closed, False otherwise
"""
return self.closed

def get_center(self) -> tuple[float, float]:
"""Return the center of the polygon
Returns:
Center of the polygon
"""
if self.points is not None and self.points.size > 0:
return self.points.mean(axis=0)
return 0.0, 0.0

def boundingRect(self) -> QC.QRectF:
"""Return the bounding rectangle of the data
Expand Down
2 changes: 2 additions & 0 deletions plotpy/plot/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
AnnotatedEllipse,
AnnotatedObliqueRectangle,
AnnotatedPoint,
AnnotatedPolygon,
AnnotatedRectangle,
AnnotatedSegment,
BaseImageItem,
Expand Down Expand Up @@ -2369,3 +2370,4 @@ def register_autoscale_type(cls, type_):
BasePlot.register_autoscale_type(AnnotatedObliqueRectangle)
BasePlot.register_autoscale_type(AnnotatedSegment)
BasePlot.register_autoscale_type(AnnotatedPoint)
BasePlot.register_autoscale_type(AnnotatedPolygon)
26 changes: 14 additions & 12 deletions plotpy/tests/features/test_loadsaveitems_pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ def build_items() -> list:
delta = delta + 0.01
y.append(y[-1] + delta)

polypoints1 = np.array(
[
[150.0, 330.0],
[270.0, 520.0],
[470.0, 480.0],
[520.0, 360.0],
[460.0, 200.0],
[250.0, 240.0],
]
)
polypoints2 = polypoints1 * 0.5

items = [
make.curve(x, y, color="b"),
make.image(filename=filename),
Expand All @@ -71,19 +83,9 @@ def build_items() -> list:
make.ellipse(-10, 0.0, 0, 0, "el1"),
make.annotated_rectangle(0.5, 0.8, 3, 1.0, "rc1", "tutu"),
make.annotated_segment(-1, -1, 1, 1.0, "rc1", "tutu"),
make.annotated_polygon(polypoints2, "rc1", "tutu"),
Axes((0, 0), (1, 0), (0, 1)),
PolygonShape(
np.array(
[
[150.0, 330.0],
[270.0, 520.0],
[470.0, 480.0],
[520.0, 360.0],
[460.0, 200.0],
[250.0, 240.0],
]
)
),
PolygonShape(polypoints1),
]
return items

Expand Down
Loading

0 comments on commit 04651a7

Please sign in to comment.