How to draw a hole on shape with matplolib

Viewed 219

I draw a filled circle with imshow and plt.circle :

sun_back = ax.imshow(np.linspace(0, 1, 100).reshape(-1, 1), cmap='plasma', vmin=0, vmax=100, 
                     extent=[..., ..., ..., ...])

sun_back.set_clip_path(plt.Circle((0, 10), 20, transform=ax.transData))

And then i know how to plot a line on it, but i don't want filled line, i want a hole on this circle but i don't know how to "drill" two zorder with a shape.

circle with line

unlike the picture, I want the black bars to be the same color as the background, but this one is dynamic so i can't change the color with the code. It need to be transparent.

Thanks

1 Answers

In matplotlib, you can only create the union of several paths but here you need the difference between the cirle and the rectangles. So unless you want to do the maths yourself I recommend using shapely to get this difference between the clip objects. difference gives you a multipolygon:

cp_shape = circle.difference(rect1).difference(rect2).difference(rect3) 

enter image description here

You can then convert the exterior of all polygons of that multipolygon into paths and use make_compound_path to combine them into one clip path:

clip_path = mp.Path.make_compound_path(*[mp.Path(np.array(p.exterior.xy).T) for p in cp_shape])

Example:

import matplotlib.pyplot as plt
import matplotlib.path as mp
import numpy as np
import shapely.geometry as sg

fig,ax = plt.subplots()
ax.xaxis.set_major_locator(plt.NullLocator())
ax.yaxis.set_major_locator(plt.NullLocator())
ax.patch.set_color('r')
sun_back = ax.imshow(np.broadcast_to(np.linspace(100, 0, 100), (100, 100)).T, 
                     cmap='plasma',
                     extent=[0,200,0,200]
                     )

circle = sg.Point(100,100).buffer(70)
rect1 = sg.box(30,50,170,58)
rect2 = sg.box(30,65,170,70)
rect3 = sg.box(30,75,170,78)
cp_shape = circle.difference(rect1).difference(rect2).difference(rect3)
clip_path = mp.Path.make_compound_path(*[mp.Path(np.array(p.exterior.xy).T) for p in cp_shape])

sun_back.set_clip_path(clip_path, transform=ax.transData)

enter image description here

Related