python - Calculate pixel values from latitude/longitude coordinates (using matplotlib Basemap) -



python - Calculate pixel values from latitude/longitude coordinates (using matplotlib Basemap) -

i need convert map coordinates pixels (in order create clickable map in html).

here sample map (made using basemap bundle matplotlib). have set labels on , attempted calculate midpoints of labels in pixels:

#!/usr/bin/env python # -*- coding: utf-8 -*- ## step 0: points 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 map using matplotlib/basemap mpl_toolkits.basemap import basemap import matplotlib.pyplot plt m = basemap(projection='merc',resolution='c', llcrnrlat=63,urcrnrlat=67, llcrnrlon=-24,urcrnrlon=-13) x, y = m(lons, lats) # transform coordinates according projection boxes = [] 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() # bit fuzzy @ resolution... plt.savefig('test.png', bbox_inches="tight", pad_inches=0.01) # step 2: coordinates of textboxes in pixels , calculate # midpoints f = plt.gcf() # current figure r = f.canvas.get_renderer() midpoints = [] 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)))

these calculated points in approximately right relative relation each other, not coincide true points. next code snippet should set reddish dot on midpoint of each label:

# step 3: utilize pil draw dots on top of labels pil import image, imagedraw im = image.open("test.png") draw = imagedraw.draw(im) x, y in midpoints: y = im.size[1] - y # pil counts rows top not bottom draw.ellipse((x-5, y-5, x+5, y+5), fill="#ff0000") im.save("test.png", "png")

red dots should in middle of labels.

i guess error comes in extract coordinates of text boxes (in step #2). help much appreciated.

notes

perhaps solution along lines of this answer?

two things happening cause pixel positions off.

the dpi used calculated text position different used save figure.

when utilize bbox_inches alternative in savefig call, eliminates lot of white space. don't take business relationship when drawing circles pil (or checking clicked. add together padding in savefig phone call may need business relationship if it's big (as show in illustration below). not matter if still utilize 0.01.

to prepare first issue, forcefulness figure , savefig phone call utilize same dpi.

to prepare sec issue, document (0,0) position (axes units) of axes in pixels, , shift text positions accordingly.

here's modified version of code:

#!/usr/bin/env python # -*- coding: utf-8 -*- ## step 0: points 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 map using matplotlib/basemap mpl_toolkits.basemap import basemap import matplotlib.pyplot plt # predefined dpi figdpi=80 # set dpi of figure, calculations utilize 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 projection boxes = [] 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() # bit fuzzy @ resolution... # predefine padding in inches padding = 2 # forcefulness dpi same value used in calculations plt.savefig('test.png', bbox_inches="tight", pad_inches=padding,dpi=figdpi) # document shift due loss of white space , added padding origin = plt.gca().transaxes.transform((0,0)) padding = [figdpi*padding,figdpi*padding]

step #2 unchanged

step #3 takes business relationship of origin

# step 3: utilize pil draw dots on top of labels pil import image, imagedraw im = image.open("test.png") draw = imagedraw.draw(im) x, y in midpoints: # deal shift x = x-origin[0]+padding[0] y = y-origin[1]+padding[1] y = im.size[1] - y # pil counts rows top not bottom draw.ellipse((x-5, y-5, x+5, y+5), fill="#ff0000") im.save("test.png", "png")

this results in:

notice used exaggerated padding value test still works, , value of 0.01 produce original figure.

python matplotlib geospatial

Comments

Popular posts from this blog

delphi - blogger via idHTTP : error 400 bad request -

c++ - compiler errors when initializing EXPECT_CALL with function which has program_options::variables_map as parameter -

How do I check if an insert was successful with MySQLdb in Python? -