2012-01-24 6 views
6

मुझे मानचित्र निर्देशांक को पिक्सेल में परिवर्तित करने की आवश्यकता है (HTML में क्लिक करने योग्य मानचित्र बनाने के लिए)।अक्षांश/देशांतर निर्देशांक (matplotlib Basemap का उपयोग करके) से पिक्सेल मानों की गणना करें

यहां एक नमूना मानचित्र है (matplotlib से बेसमैप पैकेज का उपयोग करके बनाया गया है)। मैं इस पर कुछ लेबल डाल दिया है और पिक्सेल में लेबल के मध्य बिन्दुओं की गणना करने का प्रयास किया:

#!/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

क्या आप लाल बिंदुओं को आकर्षित करने के लिए बेसमैप का उपयोग कर सकते हैं? Http://matplotlib.org/basemap/api/basemap_api.html#mpl_toolkits.basemap.Basemap.plot –

उत्तर

4

आपकी पिक्सेल स्थिति बंद होने के कारण दो चीजें हो रही हैं।

  1. डीपीआई टेक्स्ट स्थिति की गणना करने के लिए उपयोग किया जाता है जो आंकड़ा को बचाने के लिए उपयोग किया जाता है।

  2. जब आप कॉल में bbox_inches विकल्प का उपयोग करते हैं, तो यह बहुत सी सफेद जगह को समाप्त करता है। जब आप PIL के साथ अपनी मंडलियों को चित्रित कर रहे हैं (या यह जांच कर रहे हैं कि किसी ने क्लिक किया है तो आप इसे ध्यान में रखते हैं। इसके अलावा आप इस savefig कॉल में एक पैडिंग जोड़ते हैं, जिसे कॉल करने के लिए आपको खाते की आवश्यकता हो सकती है (जैसा कि मैंने अपने उदाहरण में दिखाया है नीचे)। शायद इससे कोई फर्क नहीं करता है, तो आप अभी भी 0.01 का उपयोग करें।

यह पहली समस्या को हल करने के लिए, बस एक ही डीपीआई उपयोग करने के लिए आंकड़ा और 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

यह अद्भुत है! पूर्ण, स्पष्ट, और परीक्षण किए गए उत्तर के लिए बहुत बहुत धन्यवाद। –

संबंधित मुद्दे