matplotlib top bottom ticks different - matplotlib

Is there a way to have top ticks in and bottom tick out in matplotlib plots?
Sometimes I have data hiding ticks and I would like to set ticks out only for the side that is affected.
The following code will affect both top and bottom or both right and left.
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot( 111 )
ax.plot( [0, 1, 3], 'o' )
ax.tick_params( direction = 'out' )
plt.show()

With the upgrade from #11859 for matplotlib>=3.1.0 we can now use a Secondary Axis via secondary_xaxis and secondary_yaxis to achieve independent tick directions:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot( 111 )
ax.plot( [0, 1, 3], 'o' )
ax.tick_params( direction = 'out' )
ax_r = ax.secondary_yaxis('right')
ax_t = ax.secondary_xaxis('top')
ax_r.tick_params(axis='y', direction='in')
ax_t.tick_params(axis='x', direction='inout')
which produces this figure:

You can have twin axes, then you can set the properties for each side separately:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([0, 1, 3], 'o')
axR = ax.twinx()
axT = ax.twiny()
ax.tick_params(direction = 'out')
axR.tick_params(direction = 'in')
ax.tick_params(direction = 'out')
axT.tick_params(direction = 'in')
plt.show()

Related

Adding coastlines to GOES data

I have a lot of GOES data that I'd like to plot with coastlines. I've added matplotlib axes with the proper project of each data and plotted the data. I tried to add coastlines with cartopy but they do not appear.
import metpy
import xarray as xr
import matplotlib.pyplot as plt
def get_projection(ds, variable):
dat = ds.metpy.parse_cf(variable)
return dat.metpy.cartopy_crs
aod = xr.open_dataset('GOES/AODC/2021/001/00/OR_ABI-L2-AODC-M6_G16_s20210010001176_e20210010003549_c20210010006090.nc')
albedo = xr.open_dataset('GOES/LSAC/2021/230/21/OR_ABI-L2-LSAC-M6_G16_s20212302131172_e20212302133545_c20212302135044.nc')
rainfall = xr.open_dataset('GOES/RRQPEF/2021/001/00/OR_ABI-L2-RRQPEF-M6_G16_s20210010000209_e20210010009517_c20210010010020.nc')
precipitable_water = xr.open_dataset('GOES/TPWC/2021/001/00/OR_ABI-L2-TPWC-M6_G16_s20210010001176_e20210010003549_c20210010005512.nc')
aod_proj = get_projection(aod, 'AOD')
albedo_proj = get_projection(albedo, 'LSA')
rainfall_proj = get_projection(rainfall, 'RRQPE')
pwv_proj = get_projection(precipitable_water, 'TPW')
figsize = (11, 8.5)
fig = plt.figure(figsize=figsize)
ax1 = fig.add_subplot(2, 2, 1, projection=aod_proj)
ax2 = fig.add_subplot(2, 2, 2, projection=albedo_proj)
ax3 = fig.add_subplot(2, 2, 3, projection=rainfall_proj)
ax4 = fig.add_subplot(2, 2, 4, projection=pwv_proj)
aod['AOD'].plot(vmin=0, vmax=1, ax=ax1, transform=aod_proj)
albedo['LSA'].plot(ax=ax2, transform=albedo_proj)
rainfall['RRQPE'].plot(ax=ax3, transform=rainfall_proj)
precipitable_water['TPW'].plot(ax=ax4, transform=pwv_proj)
for ax in [ax1, ax2, ax3, ax4]:
ax.coastlines(resolution='50m', color='red', linewidth=1)
fig.tight_layout()
What I get is an image with no coastlines. I'm assuming that this is a projection issue but I don't know where the problem would be.

Changing the Matplotlib GridSpec properties after generating the subplots

Suppose something comes up in my plot that mandates that I change the height ratio between two subplots that I've generated within my plot. I've tried changing GridSpec's height ratio to no avail.
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
fig = plt.figure()
gs = GridSpec(2, 1, height_ratios=[2, 1])
ax1 = fig.add_subplot(gs[0])
ax1 = fig.axes[0]
ax2 = fig.add_subplot(gs[1])
ax2 = fig.axes[1]
ax1.plot([0, 1], [0, 1])
ax2.plot([0, 1], [1, 0])
gs.height_ratios = [2, 5]
The last line has no effect on the plot ratio.
In my actual code, it is not feasible without major reworking to set the height_ratios to 2:5 ahead of time.
How do I get this to update like I want?
The axes of relevant subplots can be manipulated and adjusted to get new height ratios.
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
fig = plt.figure()
gs = GridSpec(2, 1, height_ratios=[2, 1]) #nrows, ncols
ax1 = fig.add_subplot(gs[0])
ax1 = fig.axes[0]
ax2 = fig.add_subplot(gs[1])
ax2 = fig.axes[1]
ax1.plot([0, 1], [0, 1])
ax2.plot([0, 1], [1, 0])
# new height ratio: 2:5 is required for the 2 subplots
rw, rh = 2, 5
# get dimensions of the 2 axes
box1 = ax1.get_position()
box2 = ax2.get_position()
# current dimensions
w1,h1 = box1.x1-box1.x0, box1.y1-box1.y0
w2,h2 = box2.x1-box2.x0, box2.y1-box2.y0
top1 = box1.y0+h1
#top2 = box2.y0+h2
full_h = h1+h2 #total height
# compute new heights for each axes
new_h1 = full_h*rw/(rw + rh)
new_h2 = full_h*rh/(rw + rh)
#btm1,btm2 = box1.y0, box2.y0
new_bottom1 = top1-new_h1
# finally, set new location/dimensions of the axes
ax1.set_position([box1.x0, new_bottom1, w1, new_h1])
ax2.set_position([box2.x0, box2.y0, w2, new_h2])
plt.show()
The output for ratio: (2, 5):
The output for (2, 10):

How can I increase Horizontal Space (hspace) between two specific matplotlib subplots?

f = plt.figure(figsize=(12,10))
ax1 = f.add_subplot(411)
ax2 = f.add_subplot(422)
ax3 = f.add_subplot(423)
ax4 = f.add_subplot(424)
ax5 = f.add_subplot(425)
ax6 = f.add_subplot(426)
ax7 = f.add_subplot(427)
ax8 = f.add_subplot(428)
I want to increase space between two rows: ax1 and ax2-ax3. Other spaces should remain the same. Using "f.subplots_adjust(hspace = 0.2, wspace= 0.25)" adjusts the spacing for all subplots. What can I do to increase hspace for the top-most subplot only?
import matplotlib.pyplot as plt
fig, axs = plt.subplot_mosaic([['top', 'top'],['left1', 'right1'], ['left2', 'right2']],
constrained_layout=True)
axs['top'].set_xlabel('Xlabel\n\n')
plt.show()
This will make all the y-axes the same size. If that is not important to you, then #r-beginners answer is helpful. Note that you need-not use subplot mosaic, though it is a useful new feature.
If you are not worried about the axes sizes matching, then a slightly better way than proposed above is to use the new subfigure functionality:
import matplotlib.pyplot as plt
fig = plt.figure(constrained_layout=True)
subfigs = fig.subfigures(2, 1, height_ratios=[1, 2], hspace=0.15)
# top
axtop = subfigs[0].subplots()
# 2x2 grid
axs = subfigs[1].subplots(2, 2)
plt.show()
Based on the gridspec sample in the official reference, I customized it using this example answer.The point is to use gridspec for the separate graphs you want to configure.
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
def format_axes(fig):
for i, ax in enumerate(fig.axes):
ax.text(0.5, 0.5, "ax%d" % (i+1), va="center", ha="center")
ax.tick_params(labelbottom=False, labelleft=False)
fig = plt.figure()
gs_top = GridSpec(3, 3, top=0.95)
gs_base = GridSpec(3, 3)
ax1 = fig.add_subplot(gs_top[0, :])
# identical to ax1 = plt.subplot(gs.new_subplotspec((0, 0), colspan=3))
ax2 = fig.add_subplot(gs_base[1, :-1])
ax3 = fig.add_subplot(gs_base[1:, -1])
ax4 = fig.add_subplot(gs_base[-1, 0])
ax5 = fig.add_subplot(gs_base[-1, -2])
# fig.suptitle("GridSpec")
format_axes(fig)
plt.show()

jupyter notebook matplotlib show plot and then plot on the origin figure

I want to plot a white plot with two axes, show it to the user, then add a line to the white plot with two axes, show it to the user, then add some dot to the line, then show it to the user. How can I do this without copying the code again and again?
What I'm doing now is in the first code chunk
import math
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
fig = plt.figure(figsize=(5,5))
ax = plt.axes()
ax.set_xlabel('cat')
ax.set_ylabel('dog')
plt.title("Set of 2 animals")
plt.show()
then in the second code chunk
fig = plt.figure(figsize=(5,5))
ax = plt.axes()
x = np.linspace(0, 1.0, 1000)
ax.plot(x, 1.0-x,zorder = 0)
ax.set_xlabel('cat')
ax.set_ylabel('dog')
plt.title("Set of 2 animals")
plt.show()
then in the third code chunk
fig = plt.figure(figsize=(5,5))
ax = plt.axes()
x = np.linspace(0, 1.0, 1000)
ax.plot(x, 1.0-x,zorder = 0)
ax.set_xlabel('cat')
ax.set_ylabel('dog')
plt.title("Set of 2 animals")
p0 = 0.5
p1 = 0.5
color = "blue"
textd =0.05
ax.scatter([p0],[p1], color = color,zorder=1)
ax.text(p0+textd, p1+textd, 'tiger',color = color,zorder =2)
plt.show()
What I'm looking for is things like in the first code chunk
import math
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
fig = plt.figure(figsize=(5,5))
ax = plt.axes()
ax.set_xlabel('cat')
ax.set_ylabel('dog')
plt.title("Set of 2 animals")
plt.show()
then in the second code chunk
add line directly without duplicating the code for making axes
plt.show()
then in the third code chunk
add point directly without duplicating the code for making axes and lines
plt.show()
Update: I actually figured out the answer.
def plot(step):
fig = plt.figure(figsize=(5,5))
ax = plt.axes()
ax.set_xlabel('cat')
ax.set_ylabel('dog')
plt.title("Set of 2 animals")
if step>=1:
x = np.linspace(0, 1.0, 1000)
ax.plot(x, 1.0-x,zorder = 0)
if step>=2:
p0 = 0.5
p1 = 0.5
color = "blue"
textd =0.05
ax.scatter([p0],[p1], color = color,zorder=1)
ax.text(p0+textd, p1+textd, 'tiger',color = color,zorder =2)
plot.show()
should be able to solve the problem.

Matpliblib colormap with peak at center and zero at edges

I am looking for a custom colormap that highlights the center (value of 1) and just has white color at the edges (values of 0 and 2). Ideally there should be a gradient from 1 to [0, 2].
Usual colormaps do the opposite: diverges from center (white at center).
Thanks for your help
You can use the from_list method from LinearSegmentedColormap for this from the matplotlib.colors module.
Here, we give 3 colors as a list (["white", "red", "white"]). This can easily be customised by changing any of those color names.
For example:
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import numpy as np
cmap = LinearSegmentedColormap.from_list('wrw', ["white", "red", "white"], N=256)
a = np.arange(0, 2, 0.01).reshape(20, 10)
fig, ax = plt.subplots()
p = ax.pcolormesh(a, cmap=cmap, vmin=0, vmax=2)
fig.colorbar(p)
plt.show()
You can create based on availbale colormaps from matplotlib.
from matplotlib.colors import ListedColormap
def show_cmap(ax, cmap):
n = 256
ax.imshow(np.tile(np.arange(n), [int(n*0.20),1]),
cmap=cmap,
interpolation="nearest", aspect="auto")
ax.set_xticks([])
ax.set_yticks([])
ax.set_xticklabels([])
ax.set_yticklabels([])
c1 = plt.cm.Blues(range(0, 128))
c2 = c1[::-1]
c = np.vstack([c1, c2])
cmap = ListedColormap(c)
fig, ax = plt.subplots(1, 1, figsize=(7.2, 7.2))
show_cmap(ax, cmap)