I am drawing a polygon in matplotlib. I put in all the coordinates of points. Between some points I'd like to have 'round' or 'radial' edges instead of straight lines (say points 1 and 2 on the drawing. Is this possible? If not what's the most efficient way to draw it?
EDIT: Rutger's solution works good.
You can use arcs by making the polygons from paths.
A normal square:
import matplotlib.path as mpath
import matplotlib.patches as patches
verts = [(0,0),
(1,0),
(1,1),
(0,1),
(0,0)]
codes = [mpath.Path.MOVETO] + (len(verts)-1)*[mpath.Path.LINETO]
square_verts = mpath.Path(verts, codes)
fig, ax = plt.subplots(subplot_kw={'aspect': 1.0, 'xlim': [-0.2,1.2], 'ylim': [-0.2,1.2]})
square = patches.PathPatch(square_verts, facecolor='orange', lw=2)
ax.add_patch(square)
A rounded square can be made with:
verts = [(0.2, 0.0),
(0.8, 0.0), # start of the lower right corner
(1.0, 0.0), # intermediate point (as if it wasn't rounded)
(1.0, 0.2), # end point of the lower right corner
(1.0, 0.8), # move to the next point etc.
(1.0, 1.0),
(0.8, 1.0),
(0.2, 1.0),
(0.0, 1.0),
(0.0, 0.8),
(0.0, 0.2),
(0.0, 0.0),
(0.2, 0.0)]
codes = [mpath.Path.MOVETO,
mpath.Path.LINETO,
mpath.Path.CURVE3,
mpath.Path.CURVE3,
mpath.Path.LINETO,
mpath.Path.CURVE3,
mpath.Path.CURVE3,
mpath.Path.LINETO,
mpath.Path.CURVE3,
mpath.Path.CURVE3,
mpath.Path.LINETO,
mpath.Path.CURVE3,
mpath.Path.CURVE3]
rounded_verts = mpath.Path(verts, codes)
fig, ax = plt.subplots(subplot_kw={'aspect': 1.0, 'xlim': [-0.2,1.2], 'ylim': [-0.2,1.2]})
rounded_verts = patches.PathPatch(rounded_verts, facecolor='orange', lw=2)
ax.add_patch(rounded_verts)
For your example, you would need to specify an intermediate point which uses the x-coordinate
from Point1 and the y-coordinate
from Point2.
The matplotlib path tutorial provides a detailed description of how paths can be made: http://matplotlib.org/users/path_tutorial.html
This class works for general polygons. Just specify the vertices and the padding/radius of the corners.
import numpy as np
from matplotlib import patches, path, pyplot as plt
class RoundedPolygon(patches.PathPatch):
def __init__(self, xy, pad, **kwargs):
p = path.Path(*self.__round(xy=xy, pad=pad))
super().__init__(path=p, **kwargs)
def __round(self, xy, pad):
n = len(xy)
for i in range(0, n):
x0, x1, x2 = np.atleast_1d(xy[i - 1], xy[i], xy[(i + 1) % n])
d01, d12 = x1 - x0, x2 - x1
d01, d12 = d01 / np.linalg.norm(d01), d12 / np.linalg.norm(d12)
x00 = x0 + pad * d01
x01 = x1 - pad * d01
x10 = x1 + pad * d12
x11 = x2 - pad * d12
if i == 0:
verts = [x00, x01, x1, x10]
else:
verts += [x01, x1, x10]
codes = [path.Path.MOVETO] + n*[path.Path.LINETO, path.Path.CURVE3, path.Path.CURVE3]
return np.atleast_1d(verts, codes)
# Test
xy = np.array([(0, 0), (0.25, 0), (0.5, -0.25), (0.75, 0),
(1, 0), (1, 0.25), (1.25, 0.5), (1, 0.75),
(1, 1), (0.75, 1), (0.5, 1.25), (0.25, 1),
(0, 1), (0, 0.75), (-0.25, 0.5), (0, 0.25)])
rp = RoundedPolygon(xy=xy, pad=0.1, facecolor='red', edgecolor='magenta', lw=3)
fig, ax = plt.subplots()
ax.add_patch(rp)
ax.set_aspect(1)
ax.axis('off')
ax.set_xlim(-1, 2)
ax.set_ylim(-1, 2)
plt.savefig('star.png')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With