Python에서 선택한 그리드 영역의 바깥 쪽 가장자리를 윤곽을 그리는 방법
다음 코드가 있습니다.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-np.pi/2, np.pi/2, 30)
y = np.linspace(-np.pi/2, np.pi/2, 30)
x,y = np.meshgrid(x,y)
z = np.sin(x**2+y**2)[:-1,:-1]
fig,ax = plt.subplots()
ax.pcolormesh(x,y,z)
이 이미지를 제공합니다.

이제 특정 그리드 상자의 가장자리를 강조 표시하고 싶다고 가정하겠습니다.
highlight = (z > 0.9)
윤곽 기능을 사용할 수 있지만 이렇게하면 "부드러운"윤곽이 생성됩니다. 그리드 상자의 가장자리를 따라 영역의 가장자리를 강조 표시하고 싶습니다.
내가 온 가장 가까운 것은 다음과 같은 것을 추가하는 것입니다.
highlight = np.ma.masked_less(highlight, 1)
ax.pcolormesh(x, y, highlight, facecolor = 'None', edgecolors = 'w')
이 플롯을 제공합니다.

거의 비슷하지만 내가 정말로 원하는 것은 "도넛"의 바깥 쪽과 안쪽 가장자리 만 강조 표시하는 것입니다.
그래서 본질적으로 저는 contour와 pcolormesh 함수의 하이브리드를 찾고 있습니다.-어떤 값의 윤곽을 따르지만 점대 점을 연결하는 것이 아니라 "단계"에서 그리드 빈을 따르는 것입니다. 말이 돼?
참고 : pcolormesh 인수에는 edgecolors = 'w'
이 있지만 가장자리는 여전히 파란색으로 나옵니다. 거기 무슨 일 이죠?
편집 : add_iso_line ()을 사용하는 JohanC의 초기 답변은 제시된 질문에 대해 작동합니다. 그러나 내가 사용하는 실제 데이터는 매우 불규칙한 x, y 그리드이므로 1D로 변환 할 수 없습니다 ( add_iso_line()
.
극좌표 (rho, phi)에서 데카르트 (x, y)로 변환 된 데이터를 사용하고 있습니다. JohanC가 제시 한 2D 솔루션은 다음과 같은 경우에는 작동하지 않는 것 같습니다.
import numpy as np
import matplotlib.pyplot as plt
from scipy import ndimage
def pol2cart(rho, phi):
x = rho * np.cos(phi)
y = rho * np.sin(phi)
return(x, y)
phi = np.linspace(0,2*np.pi,30)
rho = np.linspace(0,2,30)
pp, rr = np.meshgrid(phi,rho)
xx,yy = pol2cart(rr, pp)
z = np.sin(xx**2 + yy**2)
scale = 5
zz = ndimage.zoom(z, scale, order=0)
fig,ax = plt.subplots()
ax.pcolormesh(xx,yy,z[:-1, :-1])
xlim = ax.get_xlim()
ylim = ax.get_ylim()
xmin, xmax = xx.min(), xx.max()
ymin, ymax = yy.min(), yy.max()
ax.contour(np.linspace(xmin,xmax, zz.shape[1]) + (xmax-xmin)/z.shape[1]/2,
np.linspace(ymin,ymax, zz.shape[0]) + (ymax-ymin)/z.shape[0]/2,
np.where(zz < 0.9, 0, 1), levels=[0.5], colors='red')
ax.set_xlim(*xlim)
ax.set_ylim(*ylim)

답변
이 포스트 는 그러한 선을 그리는 방법을 보여줍니다. current에 적응하는 것이 간단하지 않으므로 pcolormesh
다음 코드는 가능한 적응을 보여줍니다. 선 세그먼트에 1d 버전이 필요하므로 x 및 y의 2d 버전의 이름이 변경되었습니다.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
x = np.linspace(-np.pi / 2, np.pi / 2, 30)
y = np.linspace(-np.pi / 2, np.pi / 2, 30)
xx, yy = np.meshgrid(x, y)
z = np.sin(xx ** 2 + yy ** 2)[:-1, :-1]
fig, ax = plt.subplots()
ax.pcolormesh(x, y, z)
def add_iso_line(ax, value, color):
v = np.diff(z > value, axis=1)
h = np.diff(z > value, axis=0)
l = np.argwhere(v.T)
vlines = np.array(list(zip(np.stack((x[l[:, 0] + 1], y[l[:, 1]])).T,
np.stack((x[l[:, 0] + 1], y[l[:, 1] + 1])).T)))
l = np.argwhere(h.T)
hlines = np.array(list(zip(np.stack((x[l[:, 0]], y[l[:, 1] + 1])).T,
np.stack((x[l[:, 0] + 1], y[l[:, 1] + 1])).T)))
lines = np.vstack((vlines, hlines))
ax.add_collection(LineCollection(lines, lw=1, colors=color))
add_iso_line(ax, 0.9, 'r')
plt.show()

다음은 2d 배열에서만 작동하는 두 번째 답변의 수정입니다.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from scipy import ndimage
x = np.linspace(-np.pi / 2, np.pi / 2, 30)
y = np.linspace(-np.pi / 2, np.pi / 2, 30)
x, y = np.meshgrid(x, y)
z = np.sin(x ** 2 + y ** 2)
scale = 5
zz = ndimage.zoom(z, scale, order=0)
fig, ax = plt.subplots()
ax.pcolormesh(x, y, z[:-1, :-1] )
xlim = ax.get_xlim()
ylim = ax.get_ylim()
xmin, xmax = x.min(), x.max()
ymin, ymax = y.min(), y.max()
ax.contour(np.linspace(xmin,xmax, zz.shape[1]) + (xmax-xmin)/z.shape[1]/2,
np.linspace(ymin,ymax, zz.shape[0]) + (ymax-ymin)/z.shape[0]/2,
np.where(zz < 0.9, 0, 1), levels=[0.5], colors='red')
ax.set_xlim(*xlim)
ax.set_ylim(*ylim)
plt.show()

add_iso_line
최적화를위한 개방성을보다 명확하게하기 위해 메서드 를 리팩터링하려고합니다 . 따라서 처음에는 반드시해야 할 부분이 있습니다.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
x = np.linspace(-np.pi/2, np.pi/2, 30)
y = np.linspace(-np.pi/2, np.pi/2, 30)
x, y = np.meshgrid(x,y)
z = np.sin(x**2+y**2)[:-1,:-1]
fig, ax = plt.subplots()
ax.pcolormesh(x,y,z)
xlim, ylim = ax.get_xlim(), ax.get_ylim()
highlight = (z > 0.9)
이제 highlight
다음과 같은 이진 배열이 있습니다.

add_iso_line
메서드 에서와 같이)으로 수행하는 것이 편안하지 않으므로 간단한 루프를 사용합니다.
lines = []
cells = zip(*np.where(highlight))
for x, y in cells:
if x == 0 or highlight[x - 1, y] == 0: lines.append(([x, y], [x, y + 1]))
if x == highlight.shape[0] or highlight[x + 1, y] == 0: lines.append(([x + 1, y], [x + 1, y + 1]))
if y == 0 or highlight[x, y - 1] == 0: lines.append(([x, y], [x + 1, y]))
if y == highlight.shape[1] or highlight[x, y + 1] == 0: lines.append(([x, y + 1], [x + 1, y + 1]))
그리고 마지막으로 pcolormesh에 맞추기 위해 선의 크기를 조정하고 중심 좌표를 조정합니다.
lines = (np.array(lines) / highlight.shape - [0.5, 0.5]) * [xlim[1] - xlim[0], ylim[1] - ylim[0]]
ax.add_collection(LineCollection(lines, colors='r'))
plt.show()
결론적으로 이것은 JohanC 솔루션과 매우 유사하며 일반적으로 느립니다. 다행히도 패키지를 cells
사용하여 윤곽선을 추출하여 양을 크게 줄일 수 있습니다 python-opencv
.
import cv2
highlight = highlight.astype(np.uint8)
contours, hierarchy = cv2.findContours(highlight, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cells = np.vstack(contours).squeeze()
다음은 검사중인 셀의 그림입니다.
