Orthographic projection Python - python

I use orthographic projection to plot maps.
I use this programm:
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
import os, sys
from sys import argv
import pylab
from mpl_toolkits.basemap import Basemap, shiftgrid
from matplotlib import mpl
from matplotlib import rcParams
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import matplotlib.patches as patches
import matplotlib.path as path
import matplotlib.dates as dt
from numpy import linalg
import netCDF4
import time
import datetime as d
import sys
import math
from mpl_toolkits.axes_grid1 import make_axes_locatable
from pylab import *
nc = netCDF4.Dataset ('tt.nc')
latvar = nc.variables['lat']
lat = latvar[:]
lon = nc.variables['lon'][:]
lat_0=30;lon_0=-25
m1 = Basemap(projection='ortho',lon_0=-25,lat_0=30,resolution='l')
m = Basemap(projection='ortho',lon_0=lon_0,lat_0=lat_0,resolution='l',\
llcrnrx=0.,llcrnry=0.,urcrnrx=m1.urcrnrx/2.,urcrnry=m1.urcrnry/2.)
X, Y = m(lon, lat)
O_x_1=nc.variables['O3']
h=9
lev=0
minOzone=0
maxOzone=40
plotOzone = m.pcolor(X,Y,O_x_1[h,lev,:,:],vmin=minOzone,vmax=maxOzone)
ax=colorbar(plotOzone, shrink=0.8,norm=(0,40))
m.drawcoastlines()
m.drawparallels(np.arange(-90.,120.,30.))
m.drawmeridians(np.arange(0.,420.,60.))
plt.show()
What do I have to do to center my map
on Europe ?
I have already played with lat_0 and lon_0 but that doesn't
give what I want...
I can't add figures to show what I obtained and
what I would like...
Thank you!

The lat_0 and lon_0 are for setting the origin of the projection, not the extent of the map. Usually the place with the least distortions so you dont want the origin to deviate too much from the center of your area of interest. Basemap will automatically center the map around the origin if you dont specify an extent.
Centering the map (different from its origin) can be done if you know what extent (or boundingbox) you want to use. If you know the corner coordinates in your 'ortho' projection you could use the keywords from your example (llcrnrx etc.). I have had no luck with the 'llcrnrlon' keywords in Basemap 1.0.6, they seem to suggest that you can input the coordinates of your extent in geographic (lat/lon).
An alternative is to grab the axes and manually set an x- and y limit. A benefit is that you can do it after declaring the Basemap object which you can then use for coordinate transformation. An example:
from mpl_toolkits.basemap import Basemap
fig = plt.figure(figsize=(5,5))
m = Basemap(projection='ortho',lon_0=5,lat_0=35,resolution='l')
m.drawcoastlines()
m.drawparallels(np.arange(-90.,120.,15.))
m.drawmeridians(np.arange(0.,420.,30.))
# your extent in lat/lon (dec degrees)
ulx = -10
uly = 65
lrx = 65
lry = 35
# transform coordinates to map projection
xmin, ymin = m(ulx, lry)
xmax, ymax = m(lrx, uly)
# set the axes limits
ax = plt.gca()
ax.set_xlim(xmin, xmax)
ax.set_ylim(ymin, ymax)
Make sure the projection in the map declaration suites your needs, i have just picked an origin which falls within Europe.

Related

Plotting equal area map around a given Lat-Long using Cartopy

I want to have a square map around a user input latitude and longitude.
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.feature
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
x=float(input('Enter latitude:'))
y=float(input('Enter longitude:'))
ax = plt.axes(projection=ccrs.PlateCarree())
ax.set_extent([y-10,y+10,x-10,x+10],ccrs.PlateCarree())
ax.coastlines()
ax.gridlines(draw_labels=True)
plt.show()
It's a good plot
This works if I don't go towards the poles-
The sphericity of the earth is not taken count here and it stops at 90 degree -
If I change the projection to orthographic, the pole problem may be resolved.
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.feature
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
x=float(input('Enter latitude:'))
y=float(input('Enter longitude:'))
ax = plt.axes(projection=ccrs.Orthographic(y,x))
ax.set_extent([y-10,y+10,x-10,x+10],ccrs.PlateCarree())
ax.coastlines()
ax.gridlines(draw_labels=True)
plt.show()
I think the sphericity is taken into account, and I may get a good square plot, when I am near the equator. But, as I approach the poles, the square will start shrinking, and eventually I will not get a good area, as I have to take latitudes and longitudes from that square area, and calculate some value with them.
For instance, here are two plots below
plot at lat=80 long = 60
This picture clarifies the question. I need the diametrically opposite side also, so the latitude should again start to decrease from 90 towards 0, but then the longitudes will change again. In this way, I am going nowhere and stuck.
Plot at lat = 22 and long = 78
The 1st one becomes rectangular, and the 2nd one a square. How can I make them equal area with any given lat-long?
Even if I change the projection for the set_extent to LCC or any other, there is no way I can get to set the extent in terms of the center.
The solution is rather simple, I was completely misinterpreting how the Orthographic projection works. Projecting and setting the extent both in Orthographic projection will work fine. Here is the solution -
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import numpy as np
x=float(input('Enter latitude:'))
y=float(input('Enter longitude:'))
ax = plt.axes(projection=ccrs.Orthographic(y,x))
ax.set_extent((-1000000,1000000,-1000000,1000000),ccrs.Orthographic(y,x))
ax.coastlines('50m')
ax.gridlines(draw_labels=True)
plt.show()
plot at lat = 90 and long = 180
plot at lat=22 and long = 88
Both the maps clearly covers same area around the given latitude, longitude values.
Thanks!!!

Basemap great circle longitudinal wrapping and missing data issue

I am attempting to plot multiple great circles using a for loop in conjunction with a set of lat/lon points. I am using the animation function with matplotlib to make the plots update when the data source is updated. This is all working well.
I noticed that plotting greatcircles where the shortest distance is wrapping the image, the plot will use that and appear on the other side of the map. Is there an argument that prevents this?
Also, depending on where the plot is I notice the "middle" of the plot arc is missing. What could be causing this? Map and code below:
The CSV uses the following points:(Moscow and Tokyo)
sourcelon sourcelat destlon destlat
55.44 37.51 -80.84 35.22
139 35.6 -80.84 35.22
Minimal code:
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import matplotlib.animation
# setup mercator map projection.
fig = plt.figure(figsize=(27, 20))
m = Basemap(projection='mill', lon_0=0)
m.drawcoastlines(color='r', linewidth=1.0)
def animate(i):
df = pd.read_csv('c:/python/scripts/test2.csv', sep='\s*,\s*',header=0, encoding='ascii', engine='python'); df
for x,y,z,w in zip(df['sourcelon'], df['sourcelat'], df['destlon'], df['destlat']):
line, = m.drawgreatcircle(x,y,z,w,color='r')
ani = matplotlib.animation.FuncAnimation(fig, animate, interval=1000)
plt.tight_layout()
plt.show()
As wikipedia tells us
The great-circle distance or orthodromic distance is the shortest distance between two points on the surface of a sphere, measured along the surface of the sphere.
So the path shown goes the shortest distance, which might wrap from one side of the image to the other.
The missing points in the line are a bit of a mystery, but it might be that there is some problem with the projection in use. Using a different projection, this works fine, e.g. projection='robin':
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8,6))
m = Basemap(projection='robin',lon_0=0,resolution='c')
m.drawcoastlines(color='grey', linewidth=1.0)
a = [[55.44, 37.51, -80.84, 35.22],[139, 35.6, -80.84, 35.22]]
x,y,z,w = a[0]
line, = m.drawgreatcircle(x,y,z,w,color='r')
plt.show()
The problem can be circumvented if the distance between points in enlarged, e.g.
line, = m.drawgreatcircle(x,y,z,w,del_s=1000,color='r')
would give
Another workaround would be to get the data from the line and plot it manually,
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8,6))
m = Basemap(projection='mill', lon_0=0)
m.drawcoastlines(color='grey', linewidth=1.0)
a = [[55.44, 37.51, -80.84, 35.22],[139, 35.6, -80.84, 35.22]]
x,y,z,w = a[0]
line, = m.drawgreatcircle(x,y,z,w,color='r')
line.remove()
mx,my = line.get_data()
m.plot(mx,my, color="limegreen")
plt.show()

How to display stock_img() using Basemap?

According to Cartopy docs, stock_img() has only one (and default) option - a down sampled version of the Natural Earth shaded relief raster.
How do I display this image using Basemap?
Here is an example:
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
ax = plt.gca()
bmap = Basemap( projection='ortho', lat_0=45, lon_0=-100, resolution='l', ax=ax )
bmap.shadedrelief(scale=0.25)
plt.show()

Using Python to plot Natural Earth shapes as polygons in Matplotlib Basemap

I'm close to getting the map that I want. Matplotlib's Basemap is great, but the coastlines are too coarse when I zoom in. I can read the Natural Earth shapefiles and plot them, which are much better... but when I try and fill the polygons, I think it's treating all of the points as belonging to a single polygon. How can I iterate through the polygons and display the map correctly?
Thanks in advance!
Here's the code:
import numpy as np
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
%matplotlib inline
landColor, coastColor, oceanColor, popColor, countyColor = '#eedd99','#93ccfa','#93ccfa','#ffee99','#aa9955'
fig = plt.figure()
ax = fig.add_subplot(111)
s = 1900000
m = Basemap(projection='ortho',lon_0=-86.5,lat_0=30.3,resolution='l',llcrnrx=-s,llcrnry=-s,urcrnrx=s,urcrnry=s)
m.drawmapboundary(fill_color=oceanColor) # fill in the ocean
# generic function for reading polygons from file and plotting them on the map. This works with Natural Earth shapes.
def drawShapesFromFile(filename,facecolor,edgecolor,m):
m.readshapefile(filename, 'temp', drawbounds = False)
patches = []
for info, shape in zip(m.temp_info, m.temp): patches.append( Polygon(np.array(shape), True) )
ax.add_collection(PatchCollection(patches, facecolor=facecolor, edgecolor=edgecolor, linewidths=1))
# read the higher resolution Natural Earth coastline (land polygons) shapefile and display it as a series of polygons
drawShapesFromFile('\\Conda\\notebooks\\shapes\\ne_10m_coastline',landColor,coastColor,m)
drawShapesFromFile('\\Conda\\notebooks\\shapes\\ne_10m_urban_areas',popColor,'none',m)
m.drawcounties(color=countyColor)
plt.gcf().set_size_inches(10,10)
As requested, here's the updated code and resulting map. All I had to do was change ne_10m_coastline to ne_10m_land like this:
import numpy as np
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
%matplotlib inline
landColor, coastColor, oceanColor, popColor, countyColor = '#eedd99','#93ccfa','#93ccfa','#ffee99','#aa9955'
fig = plt.figure()
ax = fig.add_subplot(111)
s = 1900000
m = Basemap(projection='ortho',lon_0=-86.5,lat_0=30.3,resolution='l',llcrnrx=-s,llcrnry=-s,urcrnrx=s,urcrnry=s)
m.drawmapboundary(fill_color=oceanColor) # fill in the ocean
# generic function for reading polygons from file and plotting them on the map. This works with Natural Earth shapes.
def drawShapesFromFile(filename,facecolor,edgecolor,m):
m.readshapefile(filename, 'temp', drawbounds = False)
patches = []
for info, shape in zip(m.temp_info, m.temp): patches.append( Polygon(np.array(shape), True) )
ax.add_collection(PatchCollection(patches, facecolor=facecolor, edgecolor=edgecolor, linewidths=1))
# read the higher resolution Natural Earth coastline (land polygons) shapefile and display it as a series of polygons
drawShapesFromFile('\\Conda\\notebooks\\shapes\\ne_10m_land',landColor,coastColor,m)
drawShapesFromFile('\\Conda\\notebooks\\shapes\\ne_10m_urban_areas',popColor,'none',m)
m.drawcounties(color=countyColor)
plt.gcf().set_size_inches(10,10)

How to plot data only within Basemap country region

For the code below, besides having the relevant modules installed, you will need to download and unpack the file "nationp010g.shp.tar.gz" that can be found here. This file is a shape file of the United States. If anyone has a better way of displaying these boundaries, by all means suggest it!
For my test case below, I have succeeded in colouring in the united states blue. What I want to do is to plot contour plots as if only the land portions of the USA are allowed. Im not sure how this can be accomplished without using a tedious for loop which loops through all the coordinates and checks whether the coordinate in question is inside the polygon given by the shape file. What is the best way to accomplish what I want? Here is the result:
from __future__ import print_function
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap as Basemap
from matplotlib.colors import rgb2hex
from matplotlib.patches import Polygon
m = Basemap(llcrnrlon=-119,llcrnrlat=22,urcrnrlon=-64,urcrnrlat=49,
projection='lcc',lat_1=33,lat_2=45,lon_0=-95)
shp_info = m.readshapefile('nationp010g/nationp010g', 'borders', drawbounds=True)
print(dir(m)) #List all attributes of an object
ax = plt.gca()
color = 'blue'
for nshape,seg in enumerate(m.borders):
poly = Polygon(seg,facecolor=color,edgecolor=color)
ax.add_patch(poly)
xmax, ymax = m(m.lonmax, m.latmax )
xmin, ymin = m(m.lonmin, m.latmin)
y = np.linspace(ymin,ymax,100)
x = np.linspace(xmin, xmax, 100)
X, Y = np.meshgrid(x, y)
Z = (X-(xmax-xmin)/2)**2+(Y-(ymax-ymin)/2)**2
ax.contour(X,Y, Z, cmap=plt.get_cmap('coolwarm'))
plt.show()

Categories

Resources