Рисунок на фигуре на фигуре

Я экспериментирую с matplotlib чтобы нарисовать фигуры в цифрах. Поскольку квадраты – самые прямые, чтобы рисовать, я начал с них. В конце я хочу написать генератор для многоугольников с определенной шириной. В данном примере это будет четырехугольный многоугольник с прямыми углами и шириной 1.

Мой текущий код показывает следующее, которое как и ожидалось, так и почти по желанию.

квадратный квадрат в квадрате

Обратите внимание, что существует строка между 2,2 и 2,3 которая, как я думаю, может быть удалена, если это делается с использованием правильного алгоритма вместо текущего кода.

Краткое изложение вышесказанного – квадрат в коробке в двух коробках с амплитудой, увеличивающейся с 1 , предполагая, что большие коробки «отстают» от остальных коробок.

Метод, которым я написал код, производящий выше, является, ну, на самом деле, не функцией. Это чертовски уродливая коллекция очков, которые напоминают полые квадраты.

 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() 

Обратите внимание, что я рассматриваю эту не по теме для обзора кода, так как я ищу расширение моей функциональности, а не просто переписывание, которое соответствует лучшим практикам. Я чувствую, что делаю это совершенно неправильно. Прежде всего.

Как рисовать полигоны с определенной шириной с использованием matplotlib , предполагая, что полигон будет окружен снаружи полосой того же вида и, по крайней мере, такой же ширины и полностью заполнен внутри?

Обработка полигонов исключительно в matplotlib может быть довольно утомительной. К счастью, для таких операций есть очень хорошая библиотека: стройная . Для ваших целей функция parallel_offset – это путь. ring1 интересующих вас полигонов определяются ring1 , ring2 и 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() 

Результат:

введите описание изображения здесь