How do I subplot each contour with a legenda? - numpy

I want to subplot correctly and get two legends. I think that if you open the added image you get what I am trying to achieve because it sucks right now. I am learning to code so I don't understand everyone else's code on here so I am probably asking something that has been asked tons but I don't understand anyone else's code. My current code exists of the following
from IPython import get_ipython
get_ipython().magic('reset -f')
# Set up your graphics environment
get_ipython().magic('matplotlib')
# Import the modules you always need
import numpy as np
import matplotlib.pyplot as plt
# Import the modules for 3D plotting
from mpl_toolkits.mplot3d.axes3d import Axes3D
from matplotlib import cm
plt.close('all')
slopeangle = np.arange(5, 45, 1)
intangle = np.arange(20, 45, 1)
slopeangle_m, intangle_m = np.meshgrid(slopeangle, intangle)
#F = np.zeros(np.shape(slopeangle_m)
F = (((15.2-(9.81*0.5))*2.0*((np.cos(slopeangle_m*np.pi/180))**2)*np.tan(((np.pi*intangle_m)/180)))/(15.2*2.0*np.sin(slopeangle_m*np.pi/180)*(np.cos(slopeangle_m*np.pi/180))))
M0 = (((15.2-(9.81*0))*2.0*((np.cos(slopeangle_m*np.pi/180))**2)*np.tan(((np.pi*intangle_m)/180)))/(15.2*2.0*np.sin(slopeangle_m*np.pi/180)*(np.cos(slopeangle_m*np.pi/180))))
M75 = (((15.2-(9.81*0.75))*2.0*((np.cos(slopeangle_m*np.pi/180))**2)*np.tan(((np.pi*intangle_m)/180)))/(15.2*2.0*np.sin(slopeangle_m*np.pi/180)*(np.cos(slopeangle_m*np.pi/180))))
fig2 = plt.figure()
ax = fig2.add_subplot(211)
plt.contourf(slopeangle, intangle, M0, levels=[np.min(M0),1 ,np.max(M0)], cmap=plt.cm.seismic)
ax.legend
ax=plt.gca()
ax.set_title("Factor m as value 0")
ax.set_xlabel('Slope angle (°)')
ax.set_ylabel('Internal angle (°)')
ax2 = fig2.add_subplot(212)
plt.contourf(slopeangle, intangle, M75, levels=[np.min(M75),1 ,np.max(M75)], cmap=plt.cm.seismic)
ax2=plt.gca()
ax2.set_title("Factor m as value 0.75")
ax2.set_xlabel('Slope angle (°)')
ax2.set_ylabel('Internal angle (°)')
I get the following

Related

Matplotlib video zooming and quality

I already figured out how to save a video animation and zooming a picture with matplotlib.
I want now to merge the two things and understand how to introduce zoom in an animation: reading some documentation I noticed it's not straightforward for just a picture, I expect to be the same or worse for a video.
In the following I write a simple working code, relating to that you can find on the first link
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
from matplotlib import cm
#Define x,y vectors and meshgrid with function u on it
x = np.arange(0,10,.1)
y = np.arange(0,10,.1)
X,Y = np.meshgrid(x,y)
#Create a figure and an axis object for the surface
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
#Animation without axes and with colormap
def animate(n):
ax.cla()
u = np.sin(X+Y+(n/10))
plt.axis('off')
plt.grid('off')
ax.plot_surface(X,Y,u,cmap=cm.inferno)
return fig,
anim = animation.FuncAnimation(fig,animate,frames=63)
anim.save('A.mp4',fps=20)
Here the output
As you can see is not bad zoomed, but it's not enough, I want it more!
In the actual code I'm using, video animations are very very small, and I don't know why because it's very similar to this. I hope also that this way I can increase video quality, that is quite poor.
Thanks for any help.
I finally got to a raw, but effective solution. The code almost doesn't change
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
from matplotlib import cm
#Define x,y vectors and meshgrid with function u on it
x = np.arange(0,10,.1)
y = np.arange(0,10,.1)
X,Y = np.meshgrid(x,y)
#Create a figure and an axis object for the surface
fig = plt.figure(frameon=False)
ax = fig.add_subplot(111,projection='3d')
#Definition? and zooming
fig.set_size_inches(10,10)
fig.subplots_adjust(left=0,right=1,bottom=0,top=1,wspace=None,hspace=None)
#Animation without axes and with colormap
def animate(n):
ax.cla()
u = np.sin(X+Y+(n/10))
plt.axis('off')
plt.grid('off')
ax.plot_surface(X,Y,u,cmap=cm.inferno)
print(n)
return fig,
anim = animation.FuncAnimation(fig,animate,frames=63)
anim.save('A.gif',fps=20)
As you can see the zooming is good.
The bad quality is due to compression I did in a second moment, because the actual output gif is quite heavy with those parameters, in fact the quality is very good.

In Matplotlib, adding `trantsform` breaks rectangles [duplicate]

I wanted to rotate a Rectangle in matplotlib but when I apply the transformation, the rectangle doesn't show anymore:
rect = mpl.patches.Rectangle((0.0120,0),0.1,1000)
t = mpl.transforms.Affine2D().rotate_deg(45)
rect.set_transform(t)
is this a known bug or do I make a mistake?
The patch in the provided code makes it hard to tell what's going on, so I've made a clear demonstration that I worked out from a matplotlib example:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib as mpl
fig = plt.figure()
ax = fig.add_subplot(111)
r1 = patches.Rectangle((0,0), 20, 40, color="blue", alpha=0.50)
r2 = patches.Rectangle((0,0), 20, 40, color="red", alpha=0.50)
t2 = mpl.transforms.Affine2D().rotate_deg(-45) + ax.transData
r2.set_transform(t2)
ax.add_patch(r1)
ax.add_patch(r2)
plt.xlim(-20, 60)
plt.ylim(-20, 60)
plt.grid(True)
plt.show()
Apparently the transforms on patches are composites of several transforms for dealing with scaling and the bounding box. Adding the transform to the existing plot transform seems to give something more like what you'd expect. Though it looks like there's still an offset to work out.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib as mpl
fig = plt.figure()
ax = fig.add_subplot(111)
rect = patches.Rectangle((0.0120,0),0.1,1000)
t_start = ax.transData
t = mpl.transforms.Affine2D().rotate_deg(-45)
t_end = t_start + t
rect.set_transform(t_end)
print repr(t_start)
print repr(t_end)
ax.add_patch(rect)
plt.show()

very weird behaviour of matplotlib with predefined styles on jupyter and on terminal

I have been banging my head to draw correct plot using the below code. The below code is a piece from a large code. At some point, I am calling this function with reg as the data input (which is very big) to plot it. When I try the below code on Jupyter it works well. But when I try to it in my pipeline, it does not work. It simply gives me a normal plot not the seaborn-paper style based. Any help please
import matplotlib.pyplot as plt
from matplotlib import rc
f = plt.figure()
f.clear()
plt.clf()
plt.close(f)
fig, ax = plt.subplots(frameon=False)
rc('mathtext',default='regular')
rc('text', usetex=True)
plt.style.use('seaborn-paper')
col = {'sar':'b', 'r':'r'}
pslon_ix = ['sar', 'r']
reg = {'sar':{1:[1,2,3],2:[3,4,5]}, 'r':{1:[1,1,4],2:[1,3,6]}}
labels = {'sar':'sar', 'r':'r'}
for pslon in pslon_ix:
cum_reg = [sum(x)/3 for x in zip(*reg[pslon].values())]
ax.plot(range(3), cum_reg, c=col[pslon], ls='-', label=labels[pslon])
ax.set_xlabel(r'pslon')
ax.set_ylabel('cumreg')
ax.legend()
fig.savefig('sim.pdf',format='pdf')
plt.close()
f = plt.figure()
f.clear()
plt.close(f)
Managed to solve it by using
with plt.style.context(("seaborn-paper",)):

Plotting a rasterio raster on a Cartopy GeoAxes

I've seen a few other questions on this topic, but the library has changed enough that the answers to those no longer seem to apply.
Rasterio used to include an example for plotting a rasterio raster on a Cartopy GeoAxes. The example went roughly like this:
import matplotlib.pyplot as plt
import rasterio
from rasterio import plot
import cartopy
import cartopy.crs as ccrs
world = rasterio.open(r"../tests/data/world.rgb.tif")
fig = plt.figure(figsize=(20, 12))
ax = plt.axes(projection=ccrs.InterruptedGoodeHomolosine())
ax.set_global()
plot.show(world, origin='upper', transform=ccrs.PlateCarree(), interpolation=None, ax=ax)
ax.coastlines()
ax.add_feature(cartopy.feature.BORDERS)
However, this code no longer draws the raster. Instead, I get something like this:
It should look like this:
When I asked about this in the rasterio issues tracker, they told me the example was deprecated (and deleted the example). Still, I wonder if there's some way to do what I'm trying to do. Can anyone point me in the right direction?
I think you may want to read the data to a numpy.ndarray and plot it using ax.imshow, where ax is your cartopy.GeoAxes (as you have it already). I offer an example of what I mean, below.
I clipped a small chunk of Landsat surface temperature and some agricultural fields for this example. Get them on this drive link.
Note fields are in WGS 84 (epsg 4326), Landsat image is in UTM Zone 12 (epsg 32612), and I want my map in Lambert Conformal Conic. Cartopy makes this easy.
import numpy as np
import cartopy.crs as ccrs
from cartopy.io.shapereader import Reader
from cartopy.feature import ShapelyFeature
import rasterio
import matplotlib.pyplot as plt
def cartopy_example(raster, shapefile):
with rasterio.open(raster, 'r') as src:
raster_crs = src.crs
left, bottom, right, top = src.bounds
landsat = src.read()[0, :, :]
landsat = np.ma.masked_where(landsat <= 0,
landsat,
copy=True)
landsat = (landsat - np.min(landsat)) / (np.max(landsat) - np.min(landsat))
proj = ccrs.LambertConformal(central_latitude=40,
central_longitude=-110)
fig = plt.figure(figsize=(20, 16))
ax = plt.axes(projection=proj)
ax.set_extent([-110.8, -110.4, 45.3, 45.6], crs=ccrs.PlateCarree())
shape_feature = ShapelyFeature(Reader(shapefile).geometries(),
ccrs.PlateCarree(), edgecolor='blue')
ax.add_feature(shape_feature, facecolor='none')
ax.imshow(landsat, transform=ccrs.UTM(raster_crs['zone']),
cmap='inferno',
extent=(left, right, bottom, top))
plt.savefig('surface_temp.png')
feature_source = 'fields.shp'
raster_source = 'surface_temperature_32612.tif'
cartopy_example(raster_source, feature_source)
The trick with Cartopy is to remember to use the projection keyword for your axes object, as this renders the map in a nice projection of your choice (LCC in my case). Use transform keyword to indicate what projection system your data is in, so Cartopy knows how to render it.
No need of rasterio. Get a bluemarble image, then plot it.
Here is the working code:
import cartopy
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
fig = plt.figure(figsize=(10, 5))
ax = plt.axes(projection=ccrs.InterruptedGoodeHomolosine())
# source of the image:
# https://eoimages.gsfc.nasa.gov/images/imagerecords/73000/73909/world.topo.bathy.200412.3x5400x2700.jpg
fname = "./world.topo.bathy.200412.3x5400x2700.jpg"
img_origin = 'lower'
img = plt.imread(fname)
img = img[::-1]
ax.imshow(img, origin=img_origin, transform=ccrs.PlateCarree(), extent=[-180, 180, -90, 90])
ax.coastlines()
ax.add_feature(cartopy.feature.BORDERS)
ax.set_global()
plt.show()
The output plot:

Python3 Seaborn PairGrid legend outside subplots

I'm making a large PairGrid figure and I am unable to set the legend outside the plots (on the right). PairGrid doesn't seem to inherit the legend_out option of FaceGrid. Here is my attempt so far as you can see the legend overlaps the figure.
from random import choice
from numpy import random
from matplotlib import pyplot as plt
import seaborn as sns
import pandas as pd
def my_kdeplot(dfx, dfy, *args, **kwargs):
ax = sns.kdeplot(dfx, dfy, alpha=0.7,
cmap=sns.light_palette(kwargs['color'], as_cmap=True))
names = [choice('ABCDE') for _ in range(1000)]
df = pd.DataFrame(list(zip(names, *[random.random(1000) for _ in range(5)])),
columns=['names','A','B','C','D','E'])
g = sns.PairGrid(df, hue='names')
g.map_lower(my_kdeplot)
g.map_upper(plt.scatter, alpha=0.7)
g.map_diag(plt.hist)
g = g.add_legend(fontsize=14)
sns.plt.savefig('fig.png')
You can adjust the location of your legend using bbox_to_anchor=(horizontal, vertical):
g = g.add_legend(fontsize=14, bbox_to_anchor=(1.5,1))
You'll need to play with the numbers a little to find the right legend position.