add patches package in plotlib

This commit is contained in:
wyq 2021-08-27 00:24:55 +08:00
parent 6ac0f2dbf7
commit a4a8ba82e8
17 changed files with 570 additions and 89 deletions

View File

@ -1493,6 +1493,67 @@ public class GraphicFactory {
return new GraphicCollection[]{stemlines, graphics};
}
/**
* Create a polygon
*
* @param xa X coordinate array
* @param ya Y coordinate array
* @param pgb PolygonBreak
* @return Graphic
*/
public static Graphic createPolygon(Array xa, Array ya, PolygonBreak pgb) {
double x, y;
int n = (int) xa.getSize();
PolygonShape pgs;
PointD p;
List<PointD> points = new ArrayList<>();
IndexIterator xIter = xa.getIndexIterator();
IndexIterator yIter = ya.getIndexIterator();
while (xIter.hasNext()){
x = xIter.getDoubleNext();
y = yIter.getDoubleNext();
p = new PointD(x, y);
points.add(p);
}
if (points.size() > 2) {
pgs = new PolygonShape();
pgs.setPoints(points);
Graphic graphic = new Graphic(pgs, pgb);
return graphic;
}
return null;
}
/**
* Create a polygon
*
* @param xa X coordinate array
* @param ya Y coordinate array
* @param pgb PolygonBreak
* @return Graphic
*/
public static Graphic createPolygon(Array xy, PolygonBreak pgb) {
double x, y;
int n = xy.getShape()[0];
PolygonShape pgs;
PointD p;
List<PointD> points = new ArrayList<>();
IndexIterator iter = xy.getIndexIterator();
while (iter.hasNext()){
x = iter.getDoubleNext();
y = iter.getDoubleNext();
p = new PointD(x, y);
points.add(p);
}
if (points.size() > 2) {
pgs = new PolygonShape();
pgs.setPoints(points);
Graphic graphic = new Graphic(pgs, pgb);
return graphic;
}
return null;
}
/**
* Add polygons
*

View File

@ -323,6 +323,12 @@ public class Plot2D extends AbstractPlot2D {
case RECTANGLE:
this.drawRectangle(g, (RectangleShape) shape, (PolygonBreak) cb, false, area);
break;
case CIRCLE:
this.drawCircle(g, (CircleShape) shape, (PolygonBreak) cb, false, area);
break;
case ELLIPSE:
this.drawEllipse(g, (EllipseShape) shape, (PolygonBreak) cb, false, area);
break;
case ARC:
this.drawArc(g, (ArcShape) shape, (PolygonBreak) cb, area);
break;
@ -874,6 +880,96 @@ public class Plot2D extends AbstractPlot2D {
g.draw(rshape);
}
}
private void drawCircle(Graphics2D g, CircleShape rs, PolygonBreak aPGB,
boolean isSelected, Rectangle2D area) {
Extent extent = rs.getExtent();
double[] sXY;
sXY = projToScreen(extent.minX, extent.minY + extent.getHeight(), area);
double x = sXY[0];
double y = sXY[1];
double width = this.projXLength(extent.getWidth(), area);
java.awt.Shape shape = new Ellipse2D.Double(x, y, width, width);
if (aPGB.isDrawFill()) {
Color aColor = aPGB.getColor();
if (isSelected) {
aColor = this.getSelectedColor();
}
if (aPGB.isUsingHatchStyle()) {
int size = aPGB.getStyleSize();
BufferedImage bi = getHatchImage(aPGB.getStyle(), size, aPGB.getColor(), aPGB.getBackColor());
Rectangle2D rect = new Rectangle2D.Double(0, 0, size, size);
g.setPaint(new TexturePaint(bi, rect));
g.fill(shape);
} else {
g.setColor(aColor);
g.fill(shape);
}
} else if (isSelected) {
g.setColor(this.getSelectedColor());
g.fill(shape);
}
if (aPGB.isDrawOutline()) {
BasicStroke pen = new BasicStroke(aPGB.getOutlineSize());
g.setStroke(pen);
g.setColor(aPGB.getOutlineColor());
g.draw(shape);
}
}
private void drawEllipse(Graphics2D g, EllipseShape rs, PolygonBreak aPGB,
boolean isSelected, Rectangle2D area) {
Extent extent = rs.getExtent();
double[] sXY;
sXY = projToScreen(extent.minX, extent.minY + extent.getHeight(), area);
double x = sXY[0];
double y = sXY[1];
double width = this.projXLength(extent.getWidth(), area);
double height = this.projYLength(extent.getHeight(), area);
java.awt.Shape shape = new Ellipse2D.Double(x, y, width, height);
AffineTransform atf = g.getTransform();
if (rs.getAngle() != 0) {
AffineTransform newATF = (AffineTransform) atf.clone();
newATF.translate(x + width / 2, y + height / 2);
newATF.rotate(Math.toRadians(rs.getAngle()));
g.setTransform(newATF);
shape = new Ellipse2D.Double(-width * 0.5, -height * 0.5, width, height);
}
if (aPGB.isDrawFill()) {
Color aColor = aPGB.getColor();
if (isSelected) {
aColor = this.getSelectedColor();
}
if (aPGB.isUsingHatchStyle()) {
int size = aPGB.getStyleSize();
BufferedImage bi = getHatchImage(aPGB.getStyle(), size, aPGB.getColor(), aPGB.getBackColor());
Rectangle2D rect = new Rectangle2D.Double(0, 0, size, size);
g.setPaint(new TexturePaint(bi, rect));
g.fill(shape);
} else {
g.setColor(aColor);
g.fill(shape);
}
} else if (isSelected) {
g.setColor(this.getSelectedColor());
g.fill(shape);
}
if (aPGB.isDrawOutline()) {
BasicStroke pen = new BasicStroke(aPGB.getOutlineSize());
g.setStroke(pen);
g.setColor(aPGB.getOutlineColor());
g.draw(shape);
}
if (rs.getAngle() != 0) {
g.setTransform(atf);
}
}
private void drawArc(Graphics2D g, ArcShape aShape, PolygonBreak aPGB,
Rectangle2D area, float dist, float ex, Font labelFont, Color labelColor) {

View File

@ -14,6 +14,7 @@
package org.meteoinfo.geo.drawing;
import org.meteoinfo.common.*;
import org.meteoinfo.geometry.geoprocess.GeometryUtil;
import org.meteoinfo.geometry.legend.*;
import org.meteoinfo.geometry.geoprocess.Spline;
import org.meteoinfo.common.colors.ColorUtil;
@ -2459,7 +2460,11 @@ public class Draw {
drawPolygonShape(pgs, (PolygonBreak) aGraphic.getLegend(), g);
break;
case RECTANGLE:
drawPolygon(points, (PolygonBreak) aGraphic.getLegend(), g);
//drawPolygon(points, (PolygonBreak) aGraphic.getLegend(), g);
Extent extent = GeometryUtil.getExtent(points);
drawRectangle(new PointF((float)extent.minX, (float)extent.minY),
(float)extent.getWidth(), (float)extent.getHeight(),
(PolygonBreak) aGraphic.getLegend(), g);
break;
case CURVE_LINE:
drawCurveLine(points, (PolylineBreak) aGraphic.getLegend(), g);

View File

@ -13,6 +13,7 @@ import org.locationtech.jts.geom.GeometryFactory;
import org.meteoinfo.common.Extent;
import org.meteoinfo.common.Extent3D;
import org.meteoinfo.common.PointD;
import org.meteoinfo.common.PointF;
import org.meteoinfo.geometry.shape.*;
import org.meteoinfo.ndarray.*;
@ -142,11 +143,12 @@ public class GeometryUtil {
double minz = p.Z;
double maxz = p.Z;
for (int i = 1; i < points.length; i++) {
p = points[i];
if (minx > p.X) {
minx = p.M;
minx = p.X;
}
if (maxx < p.X) {
maxx = p.M;
maxx = p.X;
}
if (miny > p.Y) {
miny = p.Y;
@ -173,6 +175,43 @@ public class GeometryUtil {
return extent;
}
/**
* Get extent of the points
*
* @param points
* @return Extent
*/
public static Extent getExtent(PointF[] points) {
PointF p = points[0];
double minx = p.X;
double maxx = p.X;
double miny = p.Y;
double maxy = p.Y;
for (int i = 1; i < points.length; i++) {
p = points[i];
if (minx > p.X) {
minx = p.X;
}
if (maxx < p.X) {
maxx = p.X;
}
if (miny > p.Y) {
miny = p.Y;
}
if (maxy < p.Y) {
maxy = p.Y;
}
}
Extent extent = new Extent();
extent.minX = minx;
extent.maxX = maxx;
extent.minY = miny;
extent.maxY = maxy;
return extent;
}
/**
* Get ellipse coordinate
* @param x0 Center x

View File

@ -90,7 +90,6 @@ package org.meteoinfo.geometry.graphic;
public void setLegend(ColorBreak legend) {
_legend = legend;
updateResizeAbility();
updateResizeAbility();
}
/**

View File

@ -42,6 +42,7 @@ package org.meteoinfo.geometry.legend;
*/
public PolygonBreak() {
super();
this.color = Color.cyan;
this.breakType = BreakTypes.POLYGON_BREAK;
outlineColor = Color.black;
outlineSize = 1.0f;

View File

@ -1,73 +1,122 @@
/* Copyright 2012 Yaqiang Wang,
* yaqiang.wang@gmail.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*/
package org.meteoinfo.geometry.shape;
* yaqiang.wang@gmail.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*/
package org.meteoinfo.geometry.shape;
import org.meteoinfo.common.PointD;
import org.meteoinfo.geometry.geoprocess.GeometryUtil;
import java.util.ArrayList;
import java.util.List;
/**
* Ellipse shape class
*
* @author Yaqiang Wang
*/
public class EllipseShape extends PolygonShape {
// <editor-fold desc="Variables">
private float angle = 0.0f;
// </editor-fold>
// <editor-fold desc="Constructor">
* Ellipse shape class
*
* @author Yaqiang Wang
*/
public class EllipseShape extends PolygonShape {
// <editor-fold desc="Variables">
private float angle = 0.0f;
// </editor-fold>
// <editor-fold desc="Constructor">
/**
* Constructor
*/
public EllipseShape() {
}
// </editor-fold>
// <editor-fold desc="Get Set Methods">
@Override
public ShapeTypes getShapeType(){
return ShapeTypes.ELLIPSE;
}
/**
* Get angle
* @return Angle
*/
public float getAngle(){
return this.angle;
}
/**
* Set angle
* @param value Angle
*/
public void setAngle(float value){
this.angle = value;
}
// </editor-fold>
// <editor-fold desc="Methods">
/**
* Constructor
*/
public EllipseShape() {
}
/**
* Clone
*
* @return EllipseShape
*/
@Override
public Object clone() {
EllipseShape aPGS = new EllipseShape();
aPGS.setExtent(this.getExtent());
aPGS.setPoints(this.getPoints());
aPGS.setVisible(this.isVisible());
aPGS.setSelected(this.isSelected());
return aPGS;
}
// </editor-fold>
}
/**
* Constructor
* @param x Center x
* @param y Center y
* @param width Width
* @param height Height
*/
public EllipseShape(double x, double y, double width, double height) {
List<PointD> points = new ArrayList<>();
points.add(new PointD(x - width * 0.5, y));
points.add(new PointD(x, y - height * 0.5));
points.add(new PointD(x + width * 0.5, y));
points.add(new PointD(x, y + height * 0.5));
super.setPoints(points);
}
// </editor-fold>
// <editor-fold desc="Get Set Methods">
@Override
public ShapeTypes getShapeType() {
return ShapeTypes.ELLIPSE;
}
/**
* Get center point
* @return Center point
*/
public PointD getCenter() {
return this.getExtent().getCenterPoint();
}
/**
* Get width
* @return Width
*/
public double getWidth() {
return this.getExtent().getWidth();
}
/**
* Get height
* @return Height
*/
public double getHeight() {
return this.getExtent().getHeight();
}
/**
* Get angle
*
* @return Angle
*/
public float getAngle() {
return this.angle;
}
/**
* Set angle
*
* @param value Angle
*/
public void setAngle(float value) {
this.angle = value;
}
// </editor-fold>
// <editor-fold desc="Methods">
/**
* Clone
*
* @return EllipseShape
*/
@Override
public Object clone() {
EllipseShape aPGS = new EllipseShape();
aPGS.setExtent(this.getExtent());
aPGS.setPoints(this.getPoints());
aPGS.setVisible(this.isVisible());
aPGS.setSelected(this.isSelected());
return aPGS;
}
// </editor-fold>
}

View File

@ -27,6 +27,7 @@ public class RectangleShape extends PolygonShape {
private boolean round = false;
private double roundX = 0;
private double roundY = 0;
private double angle = 0;
// </editor-fold>
// <editor-fold desc="Constructor">
/**
@ -100,6 +101,22 @@ public class RectangleShape extends PolygonShape {
this.roundY = value;
this.round = true;
}
/**
* Get angle
* @return Angle
*/
public double getAngle() {
return this.angle;
}
/**
* Set angle
* @param value Angle
*/
public void setAngle(double value) {
this.angle = value;
}
// </editor-fold>
// <editor-fold desc="Methods">

View File

@ -9,7 +9,10 @@ import java.util.ArrayList;
import java.util.List;
import org.meteoinfo.common.PointD;
import org.meteoinfo.geometry.graphic.Graphic;
import org.meteoinfo.geometry.legend.PolygonBreak;
import org.meteoinfo.ndarray.Array;
import org.meteoinfo.ndarray.IndexIterator;
/**
*
@ -300,6 +303,63 @@ public class ShapeUtil {
return ps;
}
/**
* Create a polygon
*
* @param xa X coordinate array
* @param ya Y coordinate array
* @return PolygonShape
*/
public static PolygonShape createPolygon(Array xa, Array ya) {
double x, y;
int n = (int) xa.getSize();
PolygonShape pgs;
PointD p;
List<PointD> points = new ArrayList<>();
IndexIterator xIter = xa.getIndexIterator();
IndexIterator yIter = ya.getIndexIterator();
while (xIter.hasNext()){
x = xIter.getDoubleNext();
y = yIter.getDoubleNext();
p = new PointD(x, y);
points.add(p);
}
if (points.size() > 2) {
pgs = new PolygonShape();
pgs.setPoints(points);
return pgs;
}
return null;
}
/**
* Create a polygon
*
* @param xa X coordinate array
* @param ya Y coordinate array
* @return PolygonShape
*/
public static PolygonShape createPolygonShape(Array xy) {
double x, y;
int n = xy.getShape()[0];
PolygonShape pgs;
PointD p;
List<PointD> points = new ArrayList<>();
IndexIterator iter = xy.getIndexIterator();
while (iter.hasNext()){
x = iter.getDoubleNext();
y = iter.getDoubleNext();
p = new PointD(x, y);
points.add(p);
}
if (points.size() > 2) {
pgs = new PolygonShape();
pgs.setPoints(points);
return pgs;
}
return null;
}
/**
* Add a circle

View File

@ -1,32 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<MeteoInfo File="milconfig.xml" Type="configurefile">
<Path OpenPath="D:\Working\MIScript\Jython\mis\common_math\special">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\satellite"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\satellite\calipso"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\map"/>
<Path OpenPath="D:\Working\MIScript\Jython\mis\plot_types\patch">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\map\topology"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\test"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\common_math\stats"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\array"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\wind"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\chart"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\chart\subplot"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\common_math"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\common_math\special"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\common_math\stats"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\chart"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\map"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\map\maskout"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\patch"/>
</Path>
<File>
<OpenedFiles>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf_sombrero.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\common_math\stats\kendalltau_1.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\common_math\special\erfc.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\map\maskout\maskout_data_circle_rect.py"/>
</OpenedFiles>
<RecentFiles>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf_sombrero.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\common_math\stats\kendalltau_1.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\common_math\special\erfc.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\map\maskout\maskout_data_circle_rect.py"/>
</RecentFiles>
</File>
<Font>
@ -34,5 +32,5 @@
</Font>
<LookFeel DockWindowDecorated="true" LafDecorated="true" Name="FlatDarkLaf"/>
<Figure DoubleBuffering="true"/>
<Startup MainFormLocation="-7,0" MainFormSize="1364,813"/>
<Startup MainFormLocation="-7,-7" MainFormSize="1293,693"/>
</MeteoInfo>

View File

@ -10,6 +10,7 @@ import numbers
from org.meteoinfo.data.mapdata.geotiff import GeoTiff
from org.meteoinfo.geometry.shape import ShapeUtil, PolygonShape
from org.meteoinfo.geometry.graphic import Graphic
from org.meteoinfo.geometry.legend import BreakTypes
from org.meteoinfo.geometry.geoprocess import GeoComputation, GeometryUtil
from org.meteoinfo.ndarray.math import ArrayMath, ArrayUtil
@ -315,8 +316,8 @@ def maskout(data, mask, x=None, y=None):
:returns: (*array_like*) Maskouted data array.
"""
if mask is None:
return data
elif isinstance(mask, (NDArray, DimArray)):
return data
elif isinstance(mask, NDArray):
r = ArrayMath.maskout(data.asarray(), mask.asarray())
if isinstance(data, DimArray):
return DimArray(r, data.dims, data.fill_value, data.proj)
@ -330,8 +331,14 @@ def maskout(data, mask, x=None, y=None):
else:
return None
if not isinstance(mask, (list, ArrayList)):
if not isinstance(mask, (list, tuple, ArrayList)):
if isinstance(mask, Graphic):
mask = mask.getShape()
mask = [mask]
else:
for i in range(len(mask)):
if isinstance(mask[i], Graphic):
mask[i] = mask[i].getShape()
if data.ndim == 2 and x.ndim == 1 and y.ndim == 1:
x, y = np.meshgrid(x, y)

View File

@ -6,7 +6,9 @@ from ._axes3d import Axes3D
from ._axes3dgl import Axes3DGL
from ._figure import Figure
from ._glfigure import GLFigure
from .patches import *
__all__ = ['Figure','GLFigure','Axes','PolarAxes','MapAxes','Axes3D','Axes3DGL']
__all__ += miplot.__all__
__all__ += miplot.__all__
__all__ += patches.__all__

View File

@ -929,6 +929,15 @@ class Axes(object):
Reverse y axis.
'''
self.axes.getYAxis().setInverse(True)
def add_patch(self, patch):
"""
Add a patch.
:param patch: (*Graphic*) The patch to be added.
"""
self.axes.addGraphic(patch)
self.axes.setAutoExtent()
def add_graphic(self, graphic):
'''

View File

@ -0,0 +1,138 @@
from org.meteoinfo.geometry.graphic import Graphic
from org.meteoinfo.geometry.shape import ShapeUtil, CircleShape, EllipseShape, \
RectangleShape
from . import plotutil
import mipylib.numeric as np
__all__ = ['Circle','Ellipse','Rectangle','Polygon']
class Circle(Graphic):
"""
A circle patch.
"""
def __init__(self, xy, radius=5, **kwargs):
"""
Create a true circle at center *xy* = (*x*, *y*) with given *radius*.
:param xy: (float, float) xy coordinates of circle centre.
:param radius: (float) Circle radius.
"""
self._center = xy
self._radius = radius
shape = CircleShape(xy[0], xy[1], radius)
legend, isunique = plotutil.getlegendbreak('polygon', **kwargs)
super(Circle, self).__init__(shape, legend)
@property
def center(self):
return self._center
@property
def radius(self):
return self._radius
class Ellipse(Graphic):
"""
A ellipse patch.
"""
def __init__(self, xy, width, height, angle=0, **kwargs):
"""
Create a ellipse at center *xy* = (*x*, *y*) with given *width* and *height*.
:param xy: (float, float) xy coordinates of ellipse centre.
:param width: (float) Ellipse width.
:param height: (float) Ellipse height.
:param angle: (float) Ellipse angle. Default is 0.
"""
self._center = xy
self._width = width
self._height = height
self._angle = angle
shape = EllipseShape(xy[0], xy[1], width, height)
shape.setAngle(angle)
legend, isunique = plotutil.getlegendbreak('polygon', **kwargs)
super(Ellipse, self).__init__(shape, legend)
@property
def center(self):
return self._center
@property
def width(self):
return self._width
@property
def height(self):
return self._height
@property
def angle(self):
return self._angle
class Rectangle(Graphic):
"""
A rectangle patch.
"""
def __init__(self, xy, width, height, angle=0, **kwargs):
"""
Create a rectangle at anchor point *xy* = (*x*, *y*) with given *width* and *height*.
:param xy: (float, float) xy coordinates of anchor point.
:param width: (float) Rectangle width.
:param height: (float) Rectangle height.
:param angle: (float) Rectangle angle. Default is 0.
"""
self._center = xy
self._width = width
self._height = height
self._angle = angle
shape = RectangleShape(xy[0], xy[1], width, height)
shape.setAngle(angle)
legend, isunique = plotutil.getlegendbreak('polygon', **kwargs)
super(Rectangle, self).__init__(shape, legend)
@property
def center(self):
return self._center
@property
def width(self):
return self._width
@property
def height(self):
return self._height
@property
def angle(self):
return self._angle
class Polygon(Graphic):
"""
A general polygon patch.
"""
def __init__(self, xy, closed=True, **kwargs):
"""
Create a polygon with *xy* point array.
:param xy: (array_like) xy point array.
:param closed: (bool) If *closed* is *True*, the polygon will be closed so the
starting and ending points are the same.
"""
if isinstance(xy, (list, tuple)):
xy = np.array(xy)
self._xy = xy
self._closed = closed
shape = ShapeUtil.createPolygonShape(xy._array)
legend, isunique = plotutil.getlegendbreak('polygon', **kwargs)
super(Polygon, self).__init__(shape, legend)
@property
def xy(self):
return self._xy