Coordinates in Basemap don't match the real ones - python

For my team project I'm trying to obtain a map of my city using Python and plot a heatmap on it. I'm using Basemap and matplotlib.
I found that selecting epsg=3003 gives sufficient graphic results, but the problem is that if I want to visualize a precise coordinate on the map, for example lat=45.0306 and long=7.42, it shows a different point with respect to the one I get with Google Earth.
Since I need to plot data with very precise and near coordinates, getting an accurate map is essential.
Can anyone help me with my code?
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
map = Basemap(llcrnrlat=45,urcrnrlat=45.4,
llcrnrlon=7.41,urcrnrlon=7.8,resolution='h', epsg=3003)
map.arcgisimage(service='ESRI_StreetMap_World_2D', xpixels = 3000, verbose= True)
plt.show()

The problem is that you are using two different projection systems. Google Earth uses WGS84, whose epsg code is: 3857 but you set up your map using EPSG:3003. The best would simply be to change the projection of your map when you define your basemap. Alternatively, if you really want to use EPSG:3003 then you have to reproject the coordinate you get from Google Earth (you may want to have a look at this answer)
Here a small example to show that by using the proper projection you can nicely match google map results:
map = Basemap(llcrnrlat=45.245,urcrnrlat=45.255,
llcrnrlon=7.54,urcrnrlon=7.55,resolution='h', epsg=4326)
map.arcgisimage(service='ESRI_StreetMap_World_2D', xpixels = 3000, verbose= True)
plt.plot(7.544335,45.250423,marker='+',markersize=15,color='Red')
Here the map from basemap with a google map screenshot:

Related

Issue with plotting shapefiles on an orthographic projection in Basemap

I have been trying to plot Exclusive Economic Zone (EEZ) shapefiles on an orthographic projection from the basemap package. However, the shapefile file has EEZs from around the world, and so when I try to plot the shapefiles there are always some that are not visible in the projection at that particular angle. This results in the shapes being smeared out, which is not quite the effect that I am going for. Ultimately I wish to only plot select shapefiles, but then this same issue will likely pop up so for now I'd be happy to solve this more basic case where I try to plot all of them.
Here in the code I try a simple case where I plot the shapefiles with the readshapefile command from basemap. I have also tried plotting the various shapes as polygons (figured that would give me more flexibility in changing the appearances of the individual shapefiles) but then I could not get the polygons to appear on the map in the right spot and I would see similar smearing behavior (so likely the issue has the same or a similar root cause).
I have attached the code from the simple case below. If I run this, I get the projection to appear as a I want, but with the smearing of the shapefiles. The shapefiles can be found at http://www.marineregions.org/downloads.php#unioneezcountry where I use version 2 of Marine and land zones: the union of world country boundaries and EEZ's.
#Here is the figure
fig=plt.figure(figsize=(20,12))
ax=fig.add_subplot(111)
#create the map projection
Map=Basemap(projection='ortho',lon_0=0,lat_0=0,resolution='l')
Map.drawcoastlines(zorder=10)
Map.drawcountries(zorder=10)
Map.drawmapboundary()
#Reading in the shapefile and plotting it
Map.readshapefile('~/EEZ_Boundaries/EEZ_land_v2_201410','countries')
Here is a link to the image I get when I run the code
Ok, so after more time of trying to get this to work, I have pretty much given up with Basemap and made a (long overdue) switch to cartopy. In that case, the problem does solved by Cartopy already, so the code that creates the figure I was trying to get is:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cpf
from cartopy.io.shapereader import Reader
#Set the projection
projection=ccrs.Orthographic(central_longitude=0,central_latitude=0)
fig=plt.figure(figsize=(20,12))
axMap=fig.add_subplot(1,1,1,projection=projection)
#resolution of the coastlines
resolution='10m'
axMap.coastlines(resolution=resolution,edgecolor='black',zorder=10)
#Add the shapefiles
shape_feature = cpf.ShapelyFeature(Reader(direc_shp+file_shp).geometries(),
ccrs.PlateCarree(), edgecolor='black')
axMap.add_feature(shape_feature,zorder=1)

Rendering 2D images from STL file in Python

I would like to load an STL file and produce a set of 2D images in different rotations.
I got the basics working with numpy-stl based on this example, ended up with this code -
from stl import mesh
from mpl_toolkits import mplot3d
from matplotlib import pyplot
filename = '3001.stl'
# Create a new plot
figure = pyplot.figure()
axes = figure.gca(projection='3d')
# Load the STL files and add the vectors to the plot
mesh = mesh.Mesh.from_file(filename)
axes.add_collection3d(mplot3d.art3d.Poly3DCollection(mesh.vectors, color='lightgrey'))
#axes.plot_surface(mesh.x,mesh.y,mesh.z)
# Auto scale to the mesh size
scale = mesh.points.flatten()
axes.auto_scale_xyz(scale, scale, scale)
#turn off grid and axis from display
pyplot.axis('off')
#set viewing angle
axes.view_init(azim=120)
# Show the plot to the screen
pyplot.show()
This works well only that I end up with a silhouette of the component, lacking a lot of the detail. the picture below is a lego brick...
I tried to highlight the edges. but that is sensitive to how the model was created, which is not great for me.
I was hoping that by adding lighting, the shadows could help add the missing detail but I can't find a way to do that.
Any idea how to add lightsource to the code below to create shadows ?
After getting tired with Mayavi's install disasters I ended up writing my own library for this.
https://github.com/bwoodsend/vtkplotlib
Your code would be something like
import vtkplotlib as vpl
from stl.mesh import Mesh
path = "your path here.stl"
# Read the STL using numpy-stl
mesh = Mesh.from_file(path)
# Plot the mesh
vpl.mesh_plot(mesh)
# Show the figure
vpl.show()
If you want the brick to be blue you can replace the mesh_plot with
vpl.mesh_plot(mesh, color="blue")
If you don't find Mayavi helpful, you could try Panda3D which is intended for graphics/3D rendering applications. I find it quite straightforward for doing simple stuff like this.

Cartopy behavior when plotting projected data

I am using cartopy to draw my maps. Its a great tool!
For some of my data I have the problem that the data is not properly mapped around 0deg or the dateline. See the example below.
I know the same feature from matplotlib.basemap, where it can be solved by using the add_cyclic routine. I wondered if somebody can recommend how to best fix this problem in cartopy.
Thanks!
Alex
When plotting global data like this you will always need to add a cyclic point to your input data and coordinate. I don't believe Cartopy currently includes a function to do this for you, but you can do it yourself quite simply for the time being. Assuming you have a 1d array of longitudes and a 2d array of data where the first dimension is latitude and the second is longitude:
import numpy as np
dlon = lons[1] - lons[0]
new_lons = np.concatenate((lons, lons[-1:] + dlon))
new_data = np.concatenate((data, data[:, 0:1]), axis=1)
If you have different shaped data or coordinates then you will need to adjust this to your needs.
The cartopy development team has included the required feature in the developoment branch. For details see here

'Crop' basemap (Python) projection to cover only 1 hemisphere

I'm working with the Hammer projection defined in basemap (I use basemap's version instead on the one defined directly in maptplotlib due to the ability to change the lon_0 parameter).
But my goal is to represent sky maps generated from ground, so it doesn't make sense to plot the southern hemisphere of the map (ground).
https://dl.dropboxusercontent.com/u/66372761/skymap.png
What I would like (more or less)
https://dl.dropboxusercontent.com/u/66372761/skymap_crop.png
Is there any way to achieve this with this basemap module?. One option would be of course to save the image and then crop it with p.e. imagemagick, but this seems a bit ugly workaround, and the results would be far from perfect due to the axis labels and so.
I see that someone managed to get something similar with the custom projection of matplotlib, matplotlib: custom projection for hemisphere/wedge, but it's with the standard matplotlib, not with the basemap module.
PS. I'm using Python 2.7, matplotlib 1.3.1 and basemap 1.0.7.
Thanks in advance,
Miguel
Ordinarily, the way to show only part of the map is using the height, width, lat_0, and lon_0 parameters in the Basemap() constructor. However, the hammer projection ignores all but the lon_0 parameter, meaning the only way to crop the image in the way you want is to crop the image after it's created by basemap or use a different type of projection.

cartopy country map with html area links

I have been following instructions from user pelson to create a map with filled country shapes. (Fill countries in python basemap)
Now I was curious on putting this one step further and creating a html site like this:
http://www.ethnologue.com/region/NEU
I don't need those fancy popups but those links (http://www.w3schools.com/tags/att_area_href.asp) for every country would be real nice.
Is it possible to create those lists of coordinates with cartopy?
I'm looking for a fully automatic script generating a static html file.
Yes, this is definitely possible, but if you're producing web based maps, it might be worth you looking at D3.js (specifically, for maps see this excellent tutorial http://bost.ocks.org/mike/map/).
For cartopy however I'll take this through step-by-step, as it is a good walkthrough of the transformation system in matplotlib and cartopy.
First, we can get the pixel coordinate of any point in a figure:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
ax = plt.axes(projection=ccrs.PlateCarree())
ax.set_global()
ax.coastlines()
# Define a transformation which takes latitude and longitude values,
# and returns pixel coordinates.
ll_to_pixel = ccrs.Geodetic()._as_mpl_transform(ax)
# We need to call draw to ensure that the axes location has been defined
# fully.
plt.draw()
# Now lets figure out the pixel coordinate of Sydney.
x_pix, y_pix = ll_to_pixel.transform_point([151.2111, -33.8600])
# We can even plot these pixel coordinates directly with matplotlib.
plt.plot(x_pix, y_pix, 'ob', markersize=25, transform=None)
plt.savefig('figure_1.png', dpi=plt.gcf().get_dpi())
plt.show()
Now we have the information necessary to write the code to produce the area map, which I've gone ahead and written with full comments (<80 lines). I've posted this as a gist (https://gist.github.com/pelson/6308997) so that you can check it out and give it a go, if you like. For a live demo of the result: https://rawgithub.com/pelson/6308997/raw/map.html

Categories

Resources