pramodit adhikari
pramodit adhikari

Reputation: 15

Fill between the areas of polygons

I want to fill the area between two rectangles. Is there a way to do it with only one of fill_between or fill_betweenx?

I was able to produce the desired result by combining both the functions as seen in the code below. But I don't if this is the best way to do it. Below is the only a small demonstration. There are many concentric polygons whose whose inbetween areas I want to fill with different colors.

import matplotlib.pyplot as plt
x1 = [3, 6, 6, 3, 3]
y1 = [2, 2, 4, 4, 2]
x2 = [0, 9, 9, 0, 0]
y2 = [0, 0, 6, 6, 0]


plt.plot(x1, y1)
plt.plot(x2, y2)
plt.fill_betweenx(y1, x1, x2, color='blue')
plt.fill_between(x2, y1, y2, color='blue')

https://i.sstatic.net/h19uH.png

Upvotes: 1

Views: 1866

Answers (2)

Bruno Vermeulen
Bruno Vermeulen

Reputation: 3455

As you notice using difference of a bigger polygon with one smaller polygon that is totally embedded in the bigger polygon brings the issue on how to plot this polygon object. Shapely defines the difference polygon correctly but only plotting the exterior this will just plot the bigger polygon.

I have not found a straightforward solution to plot this with matplotlib. The solution I found was taken from this site Painting punctured polygons with matplotlib. It converts the Polygon object to a mpl pathpatch object by drawing the exterior xy points and the interior xy points with the mpl path module. (see for path workings for example in Path Tutorial - Matplotlib)

'''
see: https://sgillies.net/2010/04/06/painting-punctured-polygons-with-matplotlib.html
'''
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.path import Path
from matplotlib.patches import PathPatch
from shapely.geometry import Polygon

def ring_coding(ob):
    # The codes will be all "LINETO" commands, except for "MOVETO"s at the
    # beginning of each subpath
    n = len(ob.coords)
    codes = np.ones(n, dtype=Path.code_type) * Path.LINETO
    codes[0] = Path.MOVETO
    return codes

def pathify(polygon):
    # Convert coordinates to path vertices. Objects produced by Shapely's
    # analytic methods have the proper coordinate order, no need to sort.
    vertices = np.concatenate(
        [np.asarray(polygon.exterior)]
        + [np.asarray(r) for r in polygon.interiors])
    codes = np.concatenate(
        [ring_coding(polygon.exterior)]
        + [ring_coding(r) for r in polygon.interiors])
    return Path(vertices, codes)

x1 = [3, 6, 6, 3, 3]
y1 = [2, 2, 4, 4, 2]
x2 = [0, 9, 9, 0, 0]
y2 = [0, 0, 6, 6, 0]

fig, ax1 = plt.subplots(figsize=(6, 4))

ax1.set_xlim(-1, 10)
ax1.set_ylim(-1, 10)

rectangle_1 = Polygon([*zip(x1, y1)])
rectangle_2 = Polygon([*zip(x2, y2)])

difference_2_1 = rectangle_2.difference(rectangle_1)
difference_2_1 = pathify(difference_2_1)
patch = PathPatch(difference_2_1, facecolor='blue', edgecolor='red')
ax1.add_patch(patch)

plt.show()

enter image description here

Now I can hardly believe this is the simplest solution, so if anyone has a better way of doing this, please let me know!

Upvotes: 1

Bruno Vermeulen
Bruno Vermeulen

Reputation: 3455

If dealing with geometric objects concerning intersections, unions or differences I would have a look at the shapely module Shapely - PyPI.

Below some examples what you can do with two rectangles

import matplotlib.pyplot as plt
from shapely.geometry import Polygon

x1 = [3, 3, 6, 6, 3]
y1 = [4, 8, 8, 4, 4]
x2 = [1, 8, 8, 1, 1]
y2 = [1, 1, 6, 6, 1]

fig, ax1 = plt.subplots(figsize=(6, 4))

ax1.set_xlim(0, 10)
ax1.set_ylim(0, 10)

rectangle_1 = Polygon([*zip(x1, y1)])
rectangle_2 = Polygon([*zip(x2, y2)])

intersection = rectangle_1.intersection(rectangle_2)
union = rectangle_1.union(rectangle_2)
difference_1_2 = rectangle_1.difference(rectangle_2)
difference_2_1 = rectangle_2.difference(rectangle_1)

# ax1.plot(*rectangle_1.exterior.xy)
# ax1.plot(*rectangle_2.exterior.xy)
# ax1.plot(*intersection.exterior.xy)
# ax1.plot(*union.exterior.xy)
# ax1.plot(*difference_1_2.exterior.xy)
ax1.plot(*difference_2_1.exterior.xy)

plt.show()

In the above I have plotted the difference of the large rectangle and the small rectangle, which 'cuts out' the overlapping part of the small rectangle from the large rectangle. Un-commenting the plot lines show the results of the other options. enter image description here

Upvotes: 1

Related Questions