Drawing on a figure on a figure

I am experimenting with matplotlib to draw numbers in numbers. Since squares are the most straightforward to draw, I started with them. In the end, I want to write a generator for polygons with a certain width. In this example, it will be a quadrangular polygon with right angles and a width of 1.

My current code shows the following, which is as expected, and almost at will.

square in square in square

Note that there is a line between 2,2 and 2,3 , which, I think, can be deleted if this is done using the correct algorithm instead of the current code.

The above summary is a square in a box in two boxes with an amplitude that increases with 1 , assuming that the big boxes are β€œbehind” the rest of the blocks.

The method by which I wrote the code producing the above is, well, not really a function. This is a damn ugly collection of dots that resemble hollow squares.

 import matplotlib.path as mpath import matplotlib.patches as mpatches import matplotlib.pyplot as plt fig, ax = plt.subplots() INNER_AMPLITUDE = 1.0 OUTER_AMPLITUDE = 3.0 Path_in = mpath.Path path_in_data = [ (Path_in.MOVETO, (INNER_AMPLITUDE, -INNER_AMPLITUDE)), (Path_in.LINETO, (-INNER_AMPLITUDE, -INNER_AMPLITUDE)), (Path_in.LINETO, (-INNER_AMPLITUDE, INNER_AMPLITUDE)), (Path_in.LINETO, (INNER_AMPLITUDE, INNER_AMPLITUDE)), (Path_in.CLOSEPOLY, (INNER_AMPLITUDE, -INNER_AMPLITUDE)), ] codes, verts = zip(*path_in_data) path_in = mpath.Path(verts, codes) patch_in = mpatches.PathPatch(path_in, facecolor='g', alpha=0.3) ax.add_patch(patch_in) x, y = zip(*path_in.vertices) line, = ax.plot(x, y, 'go-') Path_out = mpath.Path path_out_data = [ (Path_out.MOVETO, (OUTER_AMPLITUDE, -OUTER_AMPLITUDE)), (Path_out.LINETO, (-OUTER_AMPLITUDE, -OUTER_AMPLITUDE)), (Path_out.LINETO, (-OUTER_AMPLITUDE, OUTER_AMPLITUDE)), (Path_out.LINETO, (OUTER_AMPLITUDE, OUTER_AMPLITUDE)), (Path_out.LINETO, (OUTER_AMPLITUDE, OUTER_AMPLITUDE-INNER_AMPLITUDE)), (Path_out.LINETO, (-(OUTER_AMPLITUDE-INNER_AMPLITUDE), OUTER_AMPLITUDE-INNER_AMPLITUDE)), (Path_out.LINETO, (-(OUTER_AMPLITUDE-INNER_AMPLITUDE), -(OUTER_AMPLITUDE-INNER_AMPLITUDE))), (Path_out.LINETO, (OUTER_AMPLITUDE-INNER_AMPLITUDE, -(OUTER_AMPLITUDE-INNER_AMPLITUDE))), (Path_out.LINETO, (OUTER_AMPLITUDE-INNER_AMPLITUDE, OUTER_AMPLITUDE-INNER_AMPLITUDE)), (Path_out.LINETO, (OUTER_AMPLITUDE, OUTER_AMPLITUDE-INNER_AMPLITUDE)), (Path_out.CLOSEPOLY, (OUTER_AMPLITUDE, OUTER_AMPLITUDE-INNER_AMPLITUDE)), ] codes, verts = zip(*path_out_data) path_out = mpath.Path(verts, codes) patch_out = mpatches.PathPatch(path_out, facecolor='r', alpha=0.3) ax.add_patch(patch_out) plt.title('Square in a square in a square') ax.grid() ax.axis('equal') plt.show() 

Notice that I am considering this off-topic code review, as I am looking for an extension of my functionality, and not just rewriting that is in line with best practices. I feel like doing this completely wrong. First of all, first.

How to draw polygons with a specific width using matplotlib , assuming that the polygon will be surrounded on the outside by a strip of the same kind and at least the same width and completely filled inside?

+4
source share
1 answer

Handling polygons exclusively in matplotlib can be quite tedious. Fortunately, there is a very good library for such operations: shapely . For your purposes, the parallel_offset function is the way to go. The ratings of the polygons you are interested in are determined by ring1 , ring2 and ring3 :

 import numpy as np import matplotlib.pyplot as plt import shapely.geometry as sg from descartes.patch import PolygonPatch # if I understood correctly you mainly need the difference d here INNER_AMPLITUDE = 0.1 OUTER_AMPLITUDE = 0.2 d = OUTER_AMPLITUDE - INNER_AMPLITUDE # fix seed, for reproducability np.random.seed(11111) # a function to produce a "random" polygon def random_polygon(): nr_p = np.random.randint(7,15) angle = np.sort(np.random.rand(nr_p)*2*np.pi) dist = 0.3*np.random.rand(nr_p) + 0.5 return np.vstack((np.cos(angle)*dist, np.sin(angle)*dist)).T # your input polygon p = random_polygon() # create a shapely ring object ring1 = sg.LinearRing(p) ring2 = ring1.parallel_offset(d, 'right', join_style=2, mitre_limit=10.) ring3 = ring1.parallel_offset(2*d, 'right', join_style=2, mitre_limit=10.) # revert the third ring. This is necessary to use it to procude a hole ring3.coords = list(ring3.coords)[::-1] # inner and outer polygon inner_poly = sg.Polygon(ring1) outer_poly = sg.Polygon(ring2, [ring3]) # create the figure fig, ax = plt.subplots(1) # convert them to matplotlib patches and add them to the axes ax.add_patch(PolygonPatch(inner_poly, facecolor=(0,1,0,0.4), edgecolor=(0,1,0,1), linewidth=3)) ax.add_patch(PolygonPatch(outer_poly, facecolor=(1,0,0,0.4), edgecolor=(1,0,0,1), linewidth=3)) # cosmetics ax.set_aspect(1) plt.axis([-1.5, 1.5, -1.5, 1.5]) plt.grid() plt.show() 

Result:

enter image description here

+1
source

All Articles