Place pie charts on a map using Basemap - python

I would like to plot pie charts on a map using Basemap and Matplotlib.
Do you know a way to do this?

You can add an axes to a basemap with inset_axes . I've modified the first example here to include a pie chart.
from mpl_toolkits.basemap import Basemap
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
import matplotlib.pyplot as plt
# setup Lambert Conformal basemap.
fig = plt.figure()
ax = fig.add_subplot(111)
m = Basemap(width=12000000,height=9000000,projection='lcc',
resolution='c',lat_1=45.,lat_2=55,lat_0=50,lon_0=-107.,ax=ax)
# draw coastlines.
m.drawcoastlines()
# draw a boundary around the map, fill the background.
# this background will end up being the ocean color, since
# the continents will be drawn on top.
m.drawmapboundary(fill_color='aqua')
# fill continents, set lake color same as ocean color.
m.fillcontinents(color='coral',lake_color='aqua')
axin = inset_axes(m.ax,width="30%",height="30%", loc=3)
axin.pie([100,200,3000])
plt.show()

Related

How do you clip gridlines so that they don't appear over continents with cartopy?

I'd like to create a map using cartopy that draws gridlines that are clipped by the continents so that they only appear over the ocean and not over land. Whether they're actually clipped or whether I just control the drawing order so that my data is drawn over them is not important to me; either way would work.
I'm in Python 3, using cartopy 0.17 and matplotlib 3.1.1.
from cartopy.crs import PlateCarree
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_axes((0, 0, 1, 1), projection=PlateCarree())
ax.gridlines()
ax.coastlines()
I've tried calling gridlines before and coastlines and vice versa but either way the gridlines end up being drawn over the continents, so clearly the order in which these things are drawn is determined in a different way.
I've also tried this plotting some data using ax.contourf and I get the same thing: the gridlines appear over the opaque colors created by the data. So it's not just the fact that coastlines only draws an outline.
Is this the result you want?
from cartopy.crs import PlateCarree
import cartopy
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_axes((0, 0, 1, 1), projection=PlateCarree())
ax.add_feature(cartopy.feature.LAND, facecolor='white', zorder=1)
ax.add_feature(cartopy.feature.COASTLINE)
ax.gridlines(zorder=0)

How do I draw a polygon with dark borders but transparent facecolors?

In matplotlib I have:
cmap = plt.cm.RdYlBu_r
colors = cmap(np.linspace(0,1, len(patches)))
collection = PatchCollection(patches, alpha=.3,
facecolor=colors, linestyle='solid')
and it gives me what I want except that the border inherits the "alpha" attribute. How do I draw a polygon with dark borders but transparent facecolors?
as a by-pass solution you could keep the points composing your polygon and plot the line joining the points as in the code below:
import matplotlib
import numpy,matplotlib.pyplot as plt
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
fig = plt.figure()
axe = fig.add_subplot(111)
polyval = numpy.random.rand(4,2) # Create the sequence of 4 2D points
patches = [Polygon(polyval,True)]
p = PatchCollection(patches,cmap=matplotlib.cm.jet,alpha=0.3)
p.set_array(100.*numpy.random.rand(1)) # Set a random color on jet map
axe.add_collection(p)
fig.colorbar(p)
fig.show()
for patch in patches:
axe.add_patch(Polygon(patch.get_xy(),closed=True,ec='k',lw=3,fill=False)) #draw the contours
fig.canvas.draw()

Plotting text on basemap

Suppose I want to plot 'text' on a basemap over Spain, this would work.
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
m = Basemap(resolution='l')
fig = plt.figure(figsize=(12,10))
m.drawcoastlines(linewidth=0.5)
plt.annotate('Text',xy=(0,40),ha="center")
plt.show()
But it doesn't work on Merc view, no matter what x/y value I specify. E.g:
m = Basemap(projection='merc',resolution='c',llcrnrlat=36,llcrnrlon=-20,urcrnrlat=61,urcrnrlon=33)
fig = plt.figure(figsize=(12,10))
m.drawcoastlines(linewidth=0.5)
plt.annotate('Text',xy=(0,40),ha="center")
plt.show()
Will only show the text in the very bottom left. How to plot text in this view?

mplot3D fill_between extends over axis limits

I have questions related to creating a simple lineplot in Python with mplot3D where the area under the plot is filled. I am using Python 2.7.5 on RedHatEnterprise 7.2, matplotlib 1.2.0 and numpy 1.7.2.
Using the code below, I am able to generate a line plot. This is displayed as expected with the beginning / end of the plot set by the limits of the imported data set.
I am then trying to fill the area between the line plot and -0.1 using the answer given by Bart from Plotting a series of 2D plots projected in 3D in a perspectival way. This works, however, the filled area is continued beyond the limits of the data set. This is also the case when running the example from the link.
This screen shot shows the plot generated with filled area extending beyond the set axis limits.
How do I achieve that the filled area is only the range of the data set or the axis limits whichever is smaller?
How do I add a legend for those plots onto the figure?
Code as follows:
from numpy import *
import matplotlib.pylab as plt
from mpl_toolkits.mplot3d import Axes3D
x,y = genfromtxt("data.dat",unpack=True)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.add_collection3d(plt.fill_between(x,y,-0.1, color='orange', alpha=0.3,label="filled plot"),1, zdir='y')
ax.plot(x,y,1,zdir="y",label="line plot")
ax.legend()
ax.set_xlim3d(852.353,852.359)
ax.set_zlim3d(-0.1,5)
ax.set_ylim3d(0,2)
ax.get_xaxis().get_major_formatter().set_useOffset(False)
plt.show()
I don't know how to put fill_between working the way you want it to, but I can provide an alternative using a 3D polygon:
from numpy import *
import matplotlib.pylab as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection # New import
#x,y = genfromtxt("data.dat",unpack=True)
# Generated some random data
w = 3
x,y = np.arange(100), np.random.randint(0,100+w,100)
y = np.array([y[i-w:i+w].mean() for i in range(3,100+w)])
z = np.zeros(x.shape)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#ax.add_collection3d(plt.fill_between(x,y,-0.1, color='orange', alpha=0.3,label="filled plot"),1, zdir='y')
verts = [(x[i],z[i],y[i]) for i in range(len(x))] + [(x.max(),0,0),(x.min(),0,0)]
ax.add_collection3d(Poly3DCollection([verts],color='orange')) # Add a polygon instead of fill_between
ax.plot(x,z,y,label="line plot")
ax.legend()
ax.set_ylim(-1,1)
plt.show()
The code above generates some random data. Builds vertices from it and plots a polygon with those vertices. This will give you the plot you wish (but does not use fill_between). The result is:

Rotating Basemap Meridian labels on x-axis

Is it possible to rotate the meridian labels so that they are no longer overlapping? See the image for an example below. I don't want to reduce the number of meridian lines.
I've tried:
ax = plt.gca()
ax.set_xticklabels( meridians, rotation=45 )
This doesn't do anything in Basemap though.
The meridian labels aren't xaxis labels. You can still manipulate their text objects:
from mpl_toolkits.basemap import Basemap, cm
import numpy as np
import matplotlib.pyplot as plt
# create figure and axes instances
fig = plt.figure(figsize=(8,8))
ax = fig.add_axes([0.1,0.1,0.8,0.8])
# create polar stereographic Basemap instance.
m = Basemap(projection='stere',lon_0=0,lat_0=30.,lat_ts=45.,\
width=10000000, height=4000000,
rsphere=6371200.,resolution='l',area_thresh=10000)
m.drawcoastlines()
m.drawstates()
m.drawcountries()
# draw parallels.
parallels = np.arange(0.,90,5.)
m.drawparallels(parallels,labels=[1,0,0,0],fontsize=10)
# draw meridians
merid_values = np.arange(0.,360.,10.)
meridians = m.drawmeridians(merid_values,labels=[0,0,0,1],fontsize=10)
for m in meridians:
try:
meridians[m][1][0].set_rotation(45)
except:
pass
plt.show()
Just give an angle as the "rotation" argument of the mapproj.drawmeridians().
import mpl_toolkits.basemap as bm
mapproj = bm.Basemap(ax=ax1,projection='cyl',llcrnrlat=lat_mn, \
llcrnrlon= lon_mn,urcrnrlat= lat_mx, urcrnrlon=lon_mx)
mapproj.drawmeridians(lonlines, labels=[0,0,1,0],rotation=45)
That's it!
Cheers!

Categories