cartopy country map with html area links - python

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

Related

Controlling resolution of full domain pcolormesh cells

I'm not sure whether this is a Cartopy or Matplotlib question, so I apologize if this would have been better suited for Matplotlib.
I am transitioning from NCL (NCAR Command Language https://www.ncl.ucar.edu/) to Python. Previously, I was using NCL to contour with a method of "CellFill" (https://www.ncl.ucar.edu/Document/Graphics/Resources/cn.shtml#cnFillMode). In Python, I am using pcolormesh to render a gridded dataset with a horizontal grid spacing of 3-km. In NCL, regardless of whether I am plotting the full domain or an area zoom, the resolution of the resulting image appears to be consistent using a PNG output. In Python however, if I use pcolormesh with an area zoom it looks identical to my NCL plot but if I try and plot the full domain, it looks different.
I've traced this down to the figure resolution. At the full domain view in Python, however I have my figure settings configured causes the 3-km cells in certain areas to become "blurred together" making it appear as if the entire region is a certain contour value when in actuality there are areas with no values in between.
Here is a CONUS example of pcolormesh:
And here is a full CONUS version from NCL:
There are several areas of note, but one obvious area is the NM/AZ region. If I zoom in very closely in both Python and NCL in this region, the resulting images look identical. But at the CONUS view it looks like there's much more shading in this area than there actually should be in the Python version.
crs = ccrs.PlateCarree() # Lat/Lon
fig = plt.figure(1, figsize=(15, 15))
ax.add_feature(cfeature.COASTLINE.with_scale('50m'), linewidth=BORDERWIDTH,edgecolor=BORDERCOLOR)
ax.add_feature(cfeature.STATES, linewidth=BORDERWIDTH,edgecolor=BORDERCOLOR)
ax.add_feature(cfeature.BORDERS, linewidth=BORDERWIDTH,edgecolor=BORDERCOLOR)
ax1 = plt.subplot(111,projection=crs)
norm = BoundaryNorm(LEVELS,ncolors=plt.get_cmap('plasma').N,clip=False)
cf1 = ax1.pcolormesh(diffsum.lon0,diffsum.lat0,diffsum,cmap='plasma',transform=ccrs.PlateCarree(),norm=norm)
plt.savefig('testing%s.png' % (DSTRING))
Note that if I manually increase the DPI used in the resulting image to something rediculous like 1000, or increase the figure size to 100x100 inches, it also looks OK but the resulting image is so gigantic it makes it cumbersome to view on the screen.
Is there something I am missing about pcolormesh that I should be doing to help better adapt the resolution of the cells being shaded with respect to the resolution of the actual figure itself?

Coordinates in Basemap don't match the real ones

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:

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.

Basemap horizontal lines with Natural Earth shape files

I am trying to use the coastline data provided by Natural Earth (in the form of shape files) within basemap. I am getting weird horizontal lines as shown in the figures below. When the plot is centered on 180 degree longitude, the number of such lines increases.
Looking at the location of these lines (which is where continents wrap around), I reckon the source of the problem must be related to how the polygons are defined in the shape file and the wrapping of the polygon around a longitude, but I don't see how I can go about fixing it. I would expect a mapping library like basemap to be able to handle this transparently. Any solution would very be helpful.
I am using the "ne_110m_coastline" data from Natural Earth and I have not modified it in any way. Here's a sample code that replicates the problem:
Map = Basemap(projection='eck4',lon_0=0, resolution='c')
a = Map.readshapefile("ne_110m_coastline", "coast")

Categories

Resources