Matplotlib Mollweide/Hammer projection: region of interest only - python

I was wondering if there's a way to only show the region of interest from a plot based on Mollweide/Hammer projection in basemap (matplotlib).
I am trying to set the plot-bounds roughly to the Pacific plate, as in the link below. However, the set_xlim and set_ylim functions do not seem to have any effect. Thanks in advance for any guidance.
http://geology.gsapubs.org/content/29/8/695/F1.large.jpg

From the documentation, both Hammer and Mollweide projections don't allow this as they print out entire world maps. Here's some code using Polyconic projection, but it is bounded by straight lines. The trick here is to define the corner longitude and latitudes on creation.
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
my_map = Basemap(projection='poly', lat_0=0, lon_0=-160,
resolution = 'h', area_thresh = 0.1,
llcrnrlon=140, llcrnrlat=-60,
urcrnrlon=-100, urcrnrlat=60)
plt.figure(figsize=(16,12))
my_map.drawcoastlines()
my_map.drawcountries()
my_map.fillcontinents(color='coral', lake_color='aqua')
my_map.drawmapboundary(fill_color='aqua')
my_map.drawmeridians(np.arange(0, 360, 20))
my_map.drawparallels(np.arange(-90, 90, 10))
plt.show()
Result:
Note that this effectively shows less area than the one in the picture you provided.

Related

Astropy matplotlib and plot galactic coordinates

I am trying to make a plot of galactic coordinates using python. Let's say that I have this data:
data = [(0.261, -7.123, 13.03, 'Unidentified'), (-0.326, 77, 13.03, 'Galaxies')]
Where each tuple is of the form (ra, dec, flux, type).
I am asked to use astropy + matplotlib, so:
c = SkyCoord(ra = ra*u.degree, dec = dec*u.degree)
galactic = c.galactic
Here is where my problem arises, I am using this code:
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
# lon_0 is central longitude of projection.
# resolution = 'c' means use crude resolution coastlines.
m = Basemap(projection='hammer',lon_0=0,resolution='c')
m.drawcoastlines()
m.fillcontinents(color='coral',lake_color='aqua')
# draw parallels and meridians.
m.drawparallels(np.arange(-90.,120.,30.))
m.drawmeridians(np.arange(0.,420.,60.))
m.drawmapboundary(fill_color='aqua')
plt.title("Hammer Projection")
plt.show()
However I can't plot the data in galactic coordinates and I don't know why. Also I need that every point is of a different color depending on the type, and of different size depending on the value of flux. I need to achieve something like this (I am kind of new to python and I have never used astropy, I have not found good examples):
Hope someone could help.
Look at the examples at the bottom of http://www.astropy.org/astropy-tutorials/plot-catalog.html. A common problem I run into when plotting Galactic coordinates is that you want to plot from -180 to +180, but the default is to give coordinates from 0 to 360. You can change this with wrap_at, e.g.:
plot(galactic.l.wrap_at(180*u.deg), galactic.b.wrap_at(180*u.deg))

Overlay coastlines on a matplotlib plot

I'm looking to overlay some coastlines on graph representing an area. The area is defined by the box:
Top: 3900000
Bottom: 3450000
Left: 300000
Right: 800000
with the coordinate system WGS_1984_UTM_Zone_36N.
I've tried using mpl_toolkits.basemap however I can't work out how to specify that area as the ESPG code (32636) is not accepted by Basemap, and when I attempt to manually insert the projection parameters (m = Basemap(projection='tmerc', k_0=0.9996, lat_0=0, lon_0=33, llcrnrx=300000, llcrnry=3450000, urcrnrx=800000, urcrnry=3900000) it still requires a lat long boundary box.
Is there a another way to define that area in Basemap?
Thanks!
Edit: I'm trying to return an area of coastline defined by a box that is in the utm system, using lat/long values for the extremities of the box would result in over/underlap of the area covered by the coastlines when converted back into the utm system (I think, please correct me if I'm wrong).
Try cartopy and its new epsg feature:
projection = ccrs.epsg(32636)
fig, ax = plt.subplots(figsize=(5, 5),
subplot_kw=dict(projection=projection))
ax.coastlines(resolution='10m')
Here is a notebook with an example:
http://nbviewer.ipython.org/gist/ocefpaf/832cf7917c21da229564
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
# make sure the value of resolution is a lowercase L,
# for 'low', not a numeral 1
map = Basemap(projection='merc', lat_0=57, lon_0=-135,
resolution = 'h', area_thresh = 0.1,
llcrnrlon=-136.25, llcrnrlat=56,
urcrnrlon=-134.25, urcrnrlat=57.75)
map.drawcoastlines()
map.drawcountries()
map.fillcontinents(color='coral')
map.drawmapboundary()
map.drawmeridians(np.arange(0, 360, 30))
map.drawparallels(np.arange(-90, 90, 30))
plt.show()
All at this link https://peak5390.wordpress.com/2012/12/08/matplotlib-basemap-tutorial-making-a-simple-map/

how to plot a text on basemap, python

I was thinking to put a text on my map, like the satellite imagery.
import numpy as np, matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
m = Basemap(resolution='l',projection='geos',lon_0=-75.)
fig = plt.figure(figsize=(10,8))
m.drawcoastlines(linewidth=1.25)
x,y = m(-150,80)
plt.text(x,y,'Jul-24-2012')
However, the text "Jul-24-2012" doesn't show up on my figure.
I guess the reason of this is because the map is not in Cartesian coordinates.
So, could anyone help me to figure out how to do this, please?
The reason that your text didn't show up is that you're trying to plot a point that's invalid for the map projection that you're using.
If you're just wanting to place text at a point in axes coordinates (e.g. the upper left hand corner of the plot) use annotate, not text.
In fact, it's fairly rare that you'll actually want to use text. annotate is much more flexible, and is actually geared towards annotating a plot, rather than just placing text at an x,y position in data coordinates. (For example, even if you want to annotate an x,y position in data coords, you often want the text offset from it by a distance in points instead of data units.)
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
m = Basemap(resolution='l',projection='geos',lon_0=-75.)
fig = plt.figure(figsize=(10,8))
m.drawcoastlines(linewidth=1.25)
#-- Place the text in the upper left hand corner of the axes
# The basemap instance doesn't have an annotate method, so we'll use the pyplot
# interface instead. (This is one of the many reasons to use cartopy instead.)
plt.annotate('Jul-24-2012', xy=(0, 1), xycoords='axes fraction')
plt.show()

Plotting at boundaries using matplotlib-basemap

I have difficulties in plotting e.g. polygons across the boundaries of a map generated using matplotlib-basemap. In the example below, the map boundary is specified by the dateline. I try to plot a triangle across the dateline by specifying the coordinates of vertices of a triangle. This works fine when all coordinates are within the map, but if they go across the map boundary, basemap performs strange extrapolation, as it seems not to know how to draw the rectangles in the right way.
Right way would mean in my sense that the triangle is drawn until the map boundary and would then continue at the other side of the map.
Below is a minimum code example and a figure illustrating the general problem.
Any ideas how to solve this problem in a general way are highly welcome.
from mpl_toolkits.basemap import Basemap
import matplotlib.pylab as plt
import numpy as np
import matplotlib.path as mpath
import matplotlib.patches as mpatches
import matplotlib as mpl
from matplotlib.collections import PatchCollection
![plt.close('all')
Path = mpath.Path
fig=plt.figure(); ax=fig.add_subplot(121); ax1=fig.add_subplot(122)
def do_plot(ax,lons,lats,title):
patches=\[\]
m = Basemap(projection='robin', resolution='c',lon_0=0.,ax=ax) #todo: how to make it properly work for other projections ???
m.drawmapboundary(fill_color='grey')
m.drawcoastlines()
#--- generate first sample with no problem
x,y=m(lons,lats)
verts = np.asarray(\[x,y\]).T
codes = \[Path.MOVETO,Path.LINETO,Path.LINETO\]
patches.append(mpatches.PathPatch(mpath.Path(verts, codes,closed=True)))
#--- generate collection
cmap = plt.cm.get_cmap('jet', 50); norm = mpl.colors.Normalize(vmin=None, vmax=None) #colorbar mapping
collection = PatchCollection(patches, cmap=cmap,norm=norm, alpha=1.,match_original=False) #construct library of all objects
colors = np.asarray(np.random.random(len(patches)))
collection.set_array(np.array(colors)) #assign data values here
#--- do actual plotting
im=m.ax.add_collection(collection)
ax.set_title(title)
do_plot(ax,\[-10.,0.,20.\],\[30.,50.,20.\],'This works')
do_plot(ax1,\[170,180,-175\],\[30.,50.,20.\],'... and here is the boundary problem')
plt.show()][1]
You cannot get around this problem with Basemap in a simple way. In your line x,y=m(lons,lats) you have transformed the points to map coordinates, and drawing the polygon just draws between those projected points.
You might try using Cartopy, which can do this. This example may help.

Stereographic Sun Diagram matplotlib polar plot python

I am trying to create a simple stereographic sun path diagram similar to these:
http://wiki.naturalfrequency.com/wiki/Sun-Path_Diagram
I am able to rotate a polar plot and set the scale to 90. How do I go about reversing the y-axis?
Currently the axis goes from 0>90, how do I reverse the axis to 90>0 to represent the azimuth?
I have tried:
ax.invert_yaxis()
ax.yaxis_inverted()
Further, how would I go about creating a stereographic projection as opposed to a equidistant?
My code:
import matplotlib.pylab as plt
testFig = plt.figure(1, figsize=(8,8))
rect = [0.1,0.1,0.8,0.8]
testAx = testFig.add_axes(rect,polar=True)
testAx.invert_yaxis()
testAx.set_theta_zero_location('N')
testAx.set_theta_direction(-1)
Azi = [90,180,270]
Alt= [0,42,0]
testAx.plot(Azi,Alt)
plt.show()
Currently my code doesn't seem to even plot the lines correctly, do I need need to convert the angle or degrees into something else?
Any help is greatly appreciated.
I finally had time to play around with matplotlib. After much searching, the correct way as Joe Kington points out is to subclass the Axes. I found a much quicker way utilising the excellent basemap module.
Below is some code I have adapted for stackoverflow. The sun altitude and azimuth were calculated with Pysolar with a set of timeseries stamps created in pandas.
import matplotlib.pylab as plt
from mpl_toolkits.basemap import Basemap
import numpy as np
winterAzi = datafomPySolarAzi
winterAlt = datafromPySolarAlt
# create instance of basemap, note we want a south polar projection to 90 = E
myMap = Basemap(projection='spstere',boundinglat=0,lon_0=180,resolution='l',round=True,suppress_ticks=True)
# set the grid up
gridX,gridY = 10.0,15.0
parallelGrid = np.arange(-90.0,90.0,gridX)
meridianGrid = np.arange(-180.0,180.0,gridY)
# draw parallel and meridian grid, not labels are off. We have to manually create these.
myMap.drawparallels(parallelGrid,labels=[False,False,False,False])
myMap.drawmeridians(meridianGrid,labels=[False,False,False,False],labelstyle='+/-',fmt='%i')
# we have to send our values through basemap to convert coordinates, note -winterAlt
winterX,winterY = myMap(winterAzi,-winterAlt)
# plot azimuth labels, with a North label.
ax = plt.gca()
ax.text(0.5,1.025,'N',transform=ax.transAxes,horizontalalignment='center',verticalalignment='bottom',size=25)
for para in np.arange(gridY,360,gridY):
x= (1.1*0.5*np.sin(np.deg2rad(para)))+0.5
y= (1.1*0.5*np.cos(np.deg2rad(para)))+0.5
ax.text(x,y,u'%i\N{DEGREE SIGN}'%para,transform=ax.transAxes,horizontalalignment='center',verticalalignment='center')
# plot the winter values
myMap.plot(winterX,winterY ,'bo')
Note that currently I am only plotting points, you will have to make sure that line points have a point at alt 0 at sunrise/sunset.

Categories

Resources