how to make map lines visible over data in cartopy? - python

I am trying to make map lines always on top of data, but cannot find the right command/options to do so in cartopy. In the plot below, I want the thick blue line "under" the black state lines but on top of the beige states.
Code:
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import os,sys
conus_proj = ccrs.LambertConformal(central_longitude=-96,central_latitude=39.0)
fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(1,1,1,projection=conus_proj)
ax.set_extent([-120,-70,22,50])
#ax.add_feature(cfeature.BORDERS)
ax.add_feature(cfeature.COASTLINE)
ax.add_feature(cfeature.OCEAN, facecolor='#CCFEFF')
ax.add_feature(cfeature.LAKES, facecolor='#CCFEFF')
ax.add_feature(cfeature.RIVERS, facecolor='#CCFEFF')
ax.add_feature(cfeature.LAND, facecolor='#FFE9B5')
state_borders = cfeature.NaturalEarthFeature(category='cultural', name='admin_1_states_provinces_lakes', scale='50m', facecolor='#FFE9B5')
ax.add_feature(state_borders, edgecolor='black')
plt.plot([-120,-70],[35,45],linewidth=8, transform=ccrs.PlateCarree())
plt.show()
I have tried changing the zorder of ax.add_feature(state_borders...) and plt.plot(...) but have received weird results. The state borders are on top by default with pcolormesh, but don't appear to be so with plt.plot
Here is the output of the above code:

The reason things turn out differently for pcolormesh vs. plot is that those have different default zorders. If I set the zorder for the state borders (note below that I use Cartopy's built-in support for states) to 10, I get them to appear on top of the plot:
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import os,sys
conus_proj = ccrs.LambertConformal(central_longitude=-96,central_latitude=39.0)
fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(1,1,1,projection=conus_proj)
ax.set_extent([-120,-70,22,50])
ax.add_feature(cfeature.COASTLINE)
ax.add_feature(cfeature.OCEAN, facecolor='#CCFEFF')
ax.add_feature(cfeature.LAKES, facecolor='#CCFEFF')
ax.add_feature(cfeature.RIVERS, edgecolor='#CCFEFF')
ax.add_feature(cfeature.LAND, facecolor='#FFE9B5')
ax.add_feature(cfeature.STATES, edgecolor='black', zorder=10)
plt.plot([-120,-70],[35,45],linewidth=8, transform=ccrs.PlateCarree())
plt.show()
I also had to remove the face colors on some of the features.

Related

Crossing Dateline with cartopy.io.img_tiles

I'm trying to figure out how to generate a map that crosses the dateline with Cartopy and a terrain from img_tiles. Here is what I have so far:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.feature as cfeature
import cartopy.io.img_tiles as cimgt
import shapely.geometry as sgeom
my_dpi = 96
plt.figure(figsize=(1530/my_dpi, 900/my_dpi), dpi=my_dpi, frameon=False)
plt.subplots_adjust(left=0.0, right=1.0, top=1.0, bottom=0)
ax = plt.axes(projection=ccrs.Mercator(central_longitude=180))
terrain = cimgt.Stamen('terrain-background')
ax.add_image(terrain, 4)
states = cfeature.NaturalEarthFeature('cultural', 'admin_1_states_provinces', '10m', edgecolor='darkblue',facecolor='none')
ax.add_feature(states, linewidth = 0.1, linestyle='-')
# draw box
box = sgeom.box(minx=69, maxx=210, miny=-57, maxy=13.5)
ax.add_geometries([box], ccrs.PlateCarree(), facecolor='coral',
edgecolor='black', alpha=0.5)
# Set extent
ax.set_extent(oceania_coords, crs=ccrs.PlateCarree())
plt.show()
When I draw a box around the region I want to zoom in on, it looks correct.
When I try to ax.set_extent on this range, it seems to set all of the cfeatures correctly but screws up with the img_tiles features.
Is there any way to work around this? Thanks for the help!
I have a solution that is good enough for me, by abutting two subplots with the appropriate ratios and borders turned off. There is a tiny artifact on the seam, but I'm mostly slicing ocean in this frame so I'm ok with it. When I have Russia in the frame, it's more obvious.
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.feature as cfeature
import cartopy.io.img_tiles as cimgt
import shapely.geometry as sgeom
import matplotlib.gridspec as gridspec
my_dpi=96
f = plt.figure(figsize=(1530/my_dpi, 900/my_dpi), dpi=my_dpi, frameon=False)
spec = gridspec.GridSpec(ncols=2, nrows=1,width_ratios=[111,30])
plt.subplots_adjust(left=0.0, right=1.0, top=1.0, bottom=0)
ax1 = f.add_subplot(spec[0],projection=ccrs.Mercator(central_longitude=180))
terrain = cimgt.Stamen('terrain-background')
ax1.add_image(terrain, 3)
states = cfeature.NaturalEarthFeature('cultural', 'admin_1_states_provinces', '10m', edgecolor='darkblue',facecolor='none')
ax1.add_feature(states, linewidth = 0.1, linestyle='-')
ax1.set_extent([69, 180, -57, 13.5], crs=ccrs.PlateCarree())
plt.gca().outline_patch.set_visible(False)
ax2 = f.add_subplot(spec[1],projection=ccrs.Mercator(central_longitude=180))
ax2.add_image(terrain, 3)
ax2.add_feature(states, linewidth = 0.1, linestyle='-')
ax2.set_extent([-180,-150, -57, 13.5], crs=ccrs.PlateCarree())
plt.gca().outline_patch.set_visible(False)
plt.subplots_adjust(wspace=0)

Set width of plot area, matplotlib

The texts on the right on this pyplot graph are clipped, how can I expand the plot area without changing the x-axis?
Minimal example code (similar to but not identical to example image)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mp
n40=146-1.07*40
n90=146-1.07*90
ageAxis =np.array([10, 40, 90])
Normal=np.array([n40, n40, n90])
plt.plot(ageAxis,Normal)
plt.text(90.2,50,'long text here that will be clipped')
ax = plt.gca()
ax.set_ylim([0,165])
ax.set_xlim([0,90])
fig= plt.gcf()
# set size fig.set_size_inches(20, 10.5)
plt.show()
It seems that it can be done with a combination of set_size_inches and subplots_adjust
Not elegant, I think, but it works:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mp
n40=146-1.07*40
n90=146-1.07*90
ageAxis =np.array([10, 40, 90])
Normal=np.array([n40, n40, n90])
plt.plot(ageAxis,Normal)
plt.text(90.2,50,'long text here that will be clipped')
ax = plt.gca()
ax.set_ylim([0,165])
ax.set_xlim([0,90])
fig= plt.gcf()
fig.set_size_inches(10, 5.5) # set a suitable size
plt.subplots_adjust(right=0.75) # adjust plot area
plt.show()

How to zoom in cartopy

I am attempting to edit the boundaries of a map using the EuroPP() projection in cartopy. I have written the following code, but hope to zoom in on the Scandinavia region. Any suggestions? Thanks!
import matplotlib.pyplot as plt
%matplotlib inline
import cartopy
import cartopy.crs as ccrs
import cartopy.io.img_tiles as cimgt
plt.figure(figsize=(5, 6))
ax = plt.axes(projection=ccrs.EuroPP())
ax.coastlines(resolution='50m', linewidth = 0.5)
ax.gridlines()
ax.add_feature(cartopy.feature.BORDERS, linestyle='-', alpha=.5)
ax.add_feature(cartopy.feature.OCEAN)
tile = cimgt.StamenTerrain()
ax.add_image(tile,5)
plt.show()
The code produces the following image:
You can use set_extent to "zoom" into the desired region, in your case, just create a bounding box around Scandinavia. Add the following code right before plt.show():
ax.set_extent([0, 43, 54, 75])
Output:

Using xkcd to plot a hr diagram but all the labels are so big

So I'm trying to plot a hr diagram in python using matplotlib and I want to make it look a little more appealing to children by making it look like a drawing with xkcd. I'm not getting any errors with my code but the axes labels and title on the resulting graph are so big you can't even read what they're saying. Does anyone know how I could fix this?
import glob
import pylab as plt
import numpy as np
import sys
import os
from sys import exit
import random
from numpy import exp
import math
from matplotlib import colors as mcolors
import csv
from matplotlib.ticker import ScalarFormatter
plt.xkcd()
plt.style.use('dark_background')
fig = plt.figure()
ax = fig.add_subplot(111)
with open("gaia_stars - Sheet1 (1).tsv") as tsvfile:
tsvreader = csv.reader(tsvfile, delimiter="\t")
tsvfile.next()
for line in tsvreader:
temperature.append(line[5])
magnitude.append(line[21])
plt.figure(figsize=(22,22))
plt.scatter(temperature, magnitude, c=temperature, cmap=plt.get_cmap('RdYlBu'), marker='*')
plt.ylabel('Magnitude',fontsize=17)
plt.xlabel('Temperature /K',fontsize=17)
plt.title('Hertzsprung-Russell Diagram',fontsize=20)
plt.gca().invert_xaxis()
plt.xscale('log')
plt.gca().invert_yaxis()
for line in ax.get_xticklines() + ax.get_yticklines():
line.set_markersize(10)
plt.tick_params(axis='x', which='major', labelsize=12)
plt.tick_params(axis='y', which='major', labelsize=12)
plt.tight_layout()
plt.show()

The plot3d figure in matplotlib is somewhat canted

I am using matplotlib to get a water fall figure, but the results look very strange. Anyone have any idea what could be wrong with it?
Here I attached the figures. The second one is the same data but in an ordinary plot. In the waterfall figure, why the color is not fully filled?
Here is the code:
def water_fall_1(x,y,Z):
#x=[...]
#y=[...]
#Z=[[z1],[z2],...z[ny]]
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
from matplotlib.colors import colorConverter
from mpl_toolkits.mplot3d import Axes3D
figs=[]
for jc in range(len(y)):
figs.append(list(zip(x,Z[jc])))
x=np.array(x)
y=np.array(y)
Z=np.array(Z)
xmin=np.floor(np.min((x.astype(np.float))))
xmax=np.ceil(np.max((x.astype(np.float))))
ymin=np.min((y.astype(np.float)))
ymax=np.max((y.astype(np.float)))
zmin=(np.min((Z.astype(np.float))))
zmax=np.max((Z.astype(np.float)))
fig=plt.figure()
ax = Axes3D(fig)
poly = PolyCollection(figs, facecolors=colorConverter.to_rgba("r", alpha=0.5))
ax.add_collection3d(poly, zs=y.astype(np.float), zdir='y')
ax.set_xlim(xmin,xmax)
ax.set_ylim(ymin,ymax)
ax.set_zlim(zmin,zmax)
ax.set_xlabel('$\omega$')
ax.set_ylabel('$T$')
#ax.set_zlabel('$\\frac{1}{2}$')
plt.show()
The curve is fully filled. I.e. the surface in between the points of the curve is red.
Consider the following example:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
from mpl_toolkits.mplot3d import Axes3D
bottom=-0.3
x = np.linspace(0,6, num=50)
z = np.sinc(x-4)
verts = zip(x,z)
#verts=verts + [(x.max(),bottom),(x.min(),bottom)]
fig=plt.figure()
ax = Axes3D(fig)
poly = PolyCollection([verts], facecolors="r", alpha=0.5)
ax.add_collection3d(poly, zs=1, zdir='y')
ax.set_xlim(x.min(),x.max())
ax.set_ylim(0,2)
ax.set_zlim(bottom,z.max())
plt.show()
which produces the following plot, where everything between the points of the curve is filled as expected.
If we now want to have the area between the curve and some bottom line filled, we would need to add some points,
verts=verts + [(x.max(),bottom),(x.min(),bottom)]
such that the bottom line is part of the curve and can thus be filled as well.

Categories