Python Matplotlib Basemap - how to set zoom level - python

I have a dataframe with locations given as longitude and latitude coordinates (in degrees). Those locations are around New York. Therefore I setup a Basemap in Python that nicely shows all those locations. Works fine!
But: the map is drawn inline and it's very tiny. How can I force that figure to be let's say 3 times larger (zoom=3).
Here's the code. The data is from the Kaggle Two Sigma Rental Listing challenge.
%matplotlib inline
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
# New York Central Park
# Longitude: -73.968285
# Latitude: 40.785091
m = Basemap(projection='merc',llcrnrlat=40,urcrnrlat=42,\
llcrnrlon=-75, urcrnrlon=-72, resolution='i', area_thresh=50, lat_0=40.78, lon_0=-73.96)
m.drawmapboundary()
m.drawcoastlines(color='black', linewidth=0.4)
m.drawrivers(color='blue')
m.fillcontinents(color='lightgray')
lons = df['longitude'].values
lats = df['latitude'].values
x,y = m(lons, lats)
# r = red; o = circle marker (see: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.plot)
m.plot(x, y, 'ro', markersize=4)
plt.show()

normally it would be as simple as:
plt.figure(figsize=(20,10))
How do you change the size of figures drawn with matplotlib?
but there are some other options too, see:
How to maximize a plt.show() window using Python
also to get the current size (for the purpose of "zoom")
How to get matplotlib figure size
regarding the specific issue:
the figure is inline inside a Jupyter notebook
before creating or plotting the map/figure:
import matplotlib
matplotlib.rcParams['figure.figsize'] = (30,30)

Related

3D elevation on geographical map with python

I am trying to display elevation/topography in 3D on a geographical map
I am currently displaying elevation with a colormap using the scatter function of matplolib over a geographical map created with the basemap package. I would like to visualize it in 3D with a shady effect or something similar.
Bellow is a simple example using data created randomly. The only constrain is to keep the 'ortho' look shown bellow. Any python package could be used.
Input data could either be a 1D arrays or 2D arrays.
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import numpy as np
size = 1000
# data to plot
data = np.arange(size)*0.5/size
# coordinates
lat = np.random.uniform(low=65, high=90, size=(size,))
lon = np.random.uniform(low=-180, high=180, size=(size,))
f1, ax = plt.subplots(1, 1,figsize=(9,8))
m = Basemap(projection='ortho',lat_0=70,lon_0=0,resolution='l',ax=ax)
m.drawcoastlines(linewidth=0.25, zorder=0)
m.drawparallels(np.arange(90,-90,-5), labels=[1,1,1,1],linewidth = 0.25, zorder=1)
m.drawmeridians(np.arange(-180.,180.,30.),labels=[1,1,1,1],latmax=85, linewidth = 0.25, zorder=1)
m.fillcontinents(color='dimgray',lake_color='grey', zorder=1)
x,y = m(lon,lat)
cmap='viridis'
m.scatter(x,y,c=data,s=10,cmap=cmap,vmin=0,vmax=0.5,zorder=3,alpha=1)
plt.show()
Thanks a lot,

Cartopy fails with small regional plots in polar regions

I want to make simple static maps for use in journal papers. I work in the Arctic and I make a lot of map images that show equipment layout, vessel tracks, and source and receiver locations. I can't do it in CARTOPY. For example, 1 deg of latitude (74 to 75N) and 2.5 degrees of longitude (-92.5 to -90.0) at a mid-latitude of say 74.5N. You can't get the coastline to work properly. The map is often empty, but it should show a portion of the coastline of Devon Island, NU. If I make the plot a bigger region (something like 30deg by 30deg), it works, but you will see that the coordinates displayed in the graph window don't line up properly. The X, Y values match the graph axes, but the lat, lon values are in parentheses are shifted. In the worst case, the lat, lons come out as 0.00n deg or even nearly half a world away.
I've tried multiple ways of invoking the extent. Different projections. Nothing seems to work.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
from cartopy.feature import NaturalEarthFeature
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
import numpy as np
import matplotlib.ticker as mticker
# the limits of the map
# extent = (-100., -50.0, 60.0, 80.0) # try this, you'll get a shifted plot on northern Alaska
extent = (-92.5, -90.0, 74.0, 75.0) # try this, you'll get a blank plot. axes shifted badly.
# set the projection type
c_lon, c_lat = (extent[0] + extent[1])/2., (extent[2] + extent[3])/2.
proj = ccrs.PlateCarree(central_longitude=c_lon)
# proj = ccrs.Mercator(c_lon) # I've tried these as well
# proj = ccrs.Orthographic(c_lon, c_lat)
gax = plt.axes(projection=proj)
gax.set_extent(extent)
gax.set_ylim((extent[2], extent[3]))
gax.set_xlim((extent[0], extent[1]))
# now add the coastline. This only works for big maps. Small regions fail.
coastline_10m = NaturalEarthFeature(category='physical', name='coastline', \
facecolor='none', scale='10m')
gax.add_feature(coastline_10m, edgecolor='gray')
# draw a grid with labelled lat and lon. Suppress ticklabels on the top and right.
gl = gax.gridlines(crs=proj, draw_labels=True) # only works with PlateCarree()
gl.xlabels_top = None
gl.ylabels_right = False
# now we put labels on the X and Y axes. You have to move these around manually.
gax.text(-0.2, 0.55, 'Latitude [Deg]', va='bottom', ha='center',
rotation='vertical', rotation_mode='anchor',
transform=gax.transAxes)
gax.text(0.5, -0.12, 'Longitude [Deg]', va='bottom', ha='center',
rotation='horizontal', rotation_mode='anchor',
transform=gax.transAxes)
# approximately correct for the aspect ratio
plt.gca().set_aspect(1.0/(np.cos(np.pi*(extent[2] + extent[3])/(2.*180.))))
plt.show()
macOS Catalina, Anaconda python3.8.3, IPython 7.19.0, cartopy 0.17 (the highest version supported. Anaconda says 0.18, but it installs 0.17).
Some obvious errors:
set_extent() needs option crs=ccrs.PlateCarree()
set_xlim() and set_ylim need data (map projection) coordinates.
And set_xlim() and set_ylim change what you have done with set_extent() in the previous line. They must be used correctly. Most of your cases, they should not be used.

Plotting data set with extra points using matplotlib

I have searched stackoverflow to find an answer to my issue, but to no avail. I wish to plot an earthquake data set with a yellow star to represent the center of my study area. However, I can only plot the earthquake data and cannot plot the star. I have tried two solutions: just plotting both data sets such as what I have in my code, or using a subplot.
In other words, what is the equivalent of MatLab's hold on command in Python/matplotlib?
#!/usr/bin/env python
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
# Read in latitudes and longitudes
eq_data = open('eq_data')
lats, lons = [], []
mag = []
for index, line in enumerate(eq_data.readlines()):
if index > 0:
lats.append(float(line.split(',')[0]))
lons.append(float(line.split(',')[1]))
mag.append(float(line.split(',')[2]))
#Build the basemap
antmap = Basemap(projection='spstere', boundinglat=10, lon_0=-60, resolution='f')
antmap.drawcoastlines(color='black', linewidth=0.15)
antmap.fillcontinents(color='0.95')
antmap.drawmapboundary(fill_color='aqua')
x,y = antmap(lons, lats)
x1,x2= (0,-90)
antmap.plot(x1,x2, 'r*', markersize=10)
antmap.plot(x,y,'ro', markersize=8)
plt.show()

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/

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