2012-01-24 4 views
6

지도 좌표를 픽셀로 변환해야합니다 (HTML에서 클릭 가능한지도를 만들기 위해).위도/경도 좌표에서 픽셀 값을 계산하십시오 (matplotlib Basemap 사용)

다음은 샘플지도입니다 (matplotlib의 Basemap 패키지를 사용). 나는 거기에 약간의 라벨을 넣고 픽셀 레이블의 중간 점을 계산하려고했습니다 :

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 

## Step 0: some points to plot 
names = [u"Reykjavík", u"Höfn", u"Húsavík"] 
lats = [64.133333, 64.25, 66.05] 
lons = [-21.933333, -15.216667, -17.316667] 

## Step 1: draw a map using matplotlib/Basemap 
from mpl_toolkits.basemap import Basemap 
import matplotlib.pyplot as plt 

M = Basemap(projection='merc',resolution='c', 
      llcrnrlat=63,urcrnrlat=67, 
      llcrnrlon=-24,urcrnrlon=-13) 

x, y = M(lons, lats) # transform coordinates according to projection 
boxes = [] 
for xa, ya, name in zip(x, y, names): 
    box = plt.text(xa, ya, name, 
     bbox=dict(facecolor='white', alpha=0.5)) 
    boxes.append(box) 

M.bluemarble() # a bit fuzzy at this resolution... 
plt.savefig('test.png', bbox_inches="tight", pad_inches=0.01) 

# Step 2: get the coordinates of the textboxes in pixels and calculate the 
# midpoints 
F = plt.gcf() # get current figure 
R = F.canvas.get_renderer() 
midpoints = [] 
for box in boxes: 
    bb = box.get_window_extent(renderer=R) 
    midpoints.append((int((bb.p0[0] + bb.p1[0])/2), 
      int((bb.p0[1] + bb.p1[1])/2))) 

이 계산 된 포인트가 서로에 약 올바른 상대 관계에 있지만, 진정한 점과 일치하지 않습니다. 다음 코드는 각 레이블의 중간에 빨간 점을 넣어해야합니다

# Step 3: use PIL to draw dots on top of the labels 
from PIL import Image, ImageDraw 

im = Image.open("test.png") 
draw = ImageDraw.Draw(im) 
for x, y in midpoints: 
    y = im.size[1] - y # PIL counts rows from top not bottom 
    draw.ellipse((x-5, y-5, x+5, y+5), fill="#ff0000") 
im.save("test.png", "PNG") 

sample output

  • 레드 도트는 라벨의 중앙에 있어야합니다.

나는 (2 단계에서) 텍스트 상자의 좌표를 추출하는 곳에서 오류가 발생한다고 생각합니다. 어떤 도움을 많이 주셨습니다.

노트

  • 아마도 솔루션은 this answer의 라인을 따라 뭔가?
+0

대신 빨간색 점을 그리려면 Basemap을 사용할 수 있습니까? 놀라운 http://matplotlib.org/basemap/api/basemap_api.html#mpl_toolkits.basemap.Basemap.plot –

답변

4

픽셀 위치가 꺼지는 두 가지 일이 발생합니다.

  1. 텍스트 위치를 계산하는 데 사용 된 dpi가 그림을 저장하는 데 사용 된 것과 다릅니다.

  2. savefig 호출에서 bbox_inches 옵션을 사용하면 많은 공백이 제거됩니다. PIL을 사용하여 서클을 그릴 때 (또는 누군가가 클릭 한 위치를 확인하는 경우) 이것을 고려하지 말고이 savefig 호출에 패딩을 추가합니다.이 예에서는 매우 큰 경우 계정해야 할 수도 있습니다 당신은 아직도 0.01를 사용하는 경우 아래). 아마 그건 문제가되지 않습니다.

그냥 같은 DPI를 사용하는 그림과 savefig 전화를 강제로, 첫 번째 문제를 해결하려면.

를 두 번째 문제를 해결하려면 축의 (0,0) 위치 (축 단위)를 픽셀 단위로 문서화하고 이에 따라 텍스트 위치를 이동하십시오.

가 여기에 귀하의 코드를 약간 수정 된 버전입니다 :

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 

## Step 0: some points to plot 
names = [u"Reykjavík", u"Höfn", u"Húsavík"] 
lats = [64.133333, 64.25, 66.05] 
lons = [-21.933333, -15.216667, -17.316667] 

## Step 1: draw a map using matplotlib/Basemap 
from mpl_toolkits.basemap import Basemap 
import matplotlib.pyplot as plt 

# predefined dpi 
FIGDPI=80 

# set dpi of figure, so that all calculations use this value 
plt.gcf().set_dpi(FIGDPI) 

M = Basemap(projection='merc',resolution='c', 
      llcrnrlat=63,urcrnrlat=67, 
      llcrnrlon=-24,urcrnrlon=-13) 

x, y = M(lons, lats) # transform coordinates according to projection 
boxes = [] 
for xa, ya, name in zip(x, y, names): 
    box = plt.text(xa, ya, name, 
     bbox=dict(facecolor='white', alpha=0.5)) 
    boxes.append(box) 

M.bluemarble() # a bit fuzzy at this resolution... 

# predefine padding in inches 
PADDING = 2 
# force dpi to same value you used in your calculations 
plt.savefig('test.png', bbox_inches="tight", pad_inches=PADDING,dpi=FIGDPI) 

# document shift due to loss of white space and added padding 
origin = plt.gca().transAxes.transform((0,0)) 
padding = [FIGDPI*PADDING,FIGDPI*PADDING] 

단계 # 2 변경되지

3 단계는이 결과 기원

# Step 3: use PIL to draw dots on top of the labels 
from PIL import Image, ImageDraw 

im = Image.open("test.png") 
draw = ImageDraw.Draw(im) 
for x, y in midpoints: 
    # deal with shift 
    x = x-origin[0]+padding[0] 
    y = y-origin[1]+padding[1] 
    y = im.size[1] - y # PIL counts rows from top not bottom 
    draw.ellipse((x-5, y-5, x+5, y+5), fill="#ff0000") 
im.save("test.png", "PNG") 

을 고려 :

enter image description here

모든 것이 여전히 작동하는지 테스트하려면 과장된 PADDING 값을 사용하고 0.01 값은 원래 숫자를 나타냅니다.

+0

을 참조하십시오! 완전하고, 명확하고, 테스트를 거친 답변을 해주셔서 너무 고맙습니다. –

관련 문제