How to Prevent Overlapping of Subplots in Python? - python

I am plotting various parameters in three different subplots. My second and third subplots are overlapping and I'm not understanding what is causing it. I have specified ax1, ax2, and ax3 and I'm thinking the issue may be from fig.add_subplot() but I'm not sure how to fix it. See my code below for reference. I only included the portions for the set up of the figure and the final plot since all three plots are generated practically in the same manner. I also included an image of what the plot is looking like that I wish to fix.
# Convert dataframe to 2D maps
lon_grid, lat_grid = np.meshgrid(data.lon.unique(), data.lat.unique())
L_grid = data.L.values.reshape(len(data.lat.unique()), len(data.lon.unique()))
Lam_grid = data.lam.values.reshape(len(data.lat.unique()), len(data.lon.unique()))
R_grid = data.R2.values.reshape(len(data.lat.unique()), len(data.lon.unique()))
# Make figures
fig = plt.figure(figsize= (10, 30), facecolor='white')
ax1 = fig.add_subplot(1,1,1,projection=ccrs.PlateCarree())
ax2 = fig.add_subplot(2,1,2,projection=ccrs.PlateCarree())
ax3 = fig.add_subplot(3,1,3,projection=ccrs.PlateCarree())
# Draw coastlines, states and countries for plot 3
ax3.coastlines()
ax3.add_feature(cfeature.BORDERS)
ax3.add_feature(cfeature.STATES)
# Draw parallels and meridians for plot 3
parallels = np.arange(-90,91,30)
meridians = np.arange(-180,181,60)
gl = ax3.gridlines(crs=ccrs.PlateCarree(), draw_labels=False,
linewidth=2, color='gray', alpha=0.5, linestyle='--')
gl.xlocator = mticker.FixedLocator(meridians)
gl.ylocator = mticker.FixedLocator(parallels)
ax3.set_xticks(np.arange(-180,181,30), crs=ccrs.PlateCarree())
ax3.set_yticks(parallels, crs=ccrs.PlateCarree())
lon_formatter = LongitudeFormatter(zero_direction_label=True)
lat_formatter = LatitudeFormatter()
ax3.xaxis.set_major_formatter(lon_formatter)
ax3.yaxis.set_major_formatter(lat_formatter)
# Add Longitude wrap-around points at 0/360 for plot 3
cyclic_R_grid, cyclic_lons = cutil.add_cyclic_point(R_grid, coord=data.lon.unique())
c3 = ax3.contourf(cyclic_lons, data.lat.unique(), cyclic_R_grid, alpha = 1.0,
transform=ccrs.PlateCarree(), levels = np.arange(0,100), \
vmin = 0.0, vmax = 100.0)
# Overplot rigidity
c3_ = ax3.imshow(np.flip(R_grid, axis=1), interpolation = 'gaussian', alpha = 0.6, extent = (-180,180,-90,90))
cbar = plt.colorbar(c3, ax=ax3, fraction=0.025)
cbar.set_label('R')
plt.show()

You are adding your subplots wrong. fig.add_subplot expects n_rows,n_cols, index in that order. So the correct definition would be
fig = plt.figure(figsize= (10, 30), facecolor='white')
ax1 = fig.add_subplot(3,1,1,projection=ccrs.PlateCarree())
ax2 = fig.add_subplot(3,1,2,projection=ccrs.PlateCarree())
ax3 = fig.add_subplot(3,1,3,projection=ccrs.PlateCarree())

Related

Matplotlib colorbar in multiple plots and it's placement

I am trying to plot 2 subplots and with colorbars for each of them. I have written the following code-
fig, ax = plt.subplots(nrows=1, ncols=2,figsize = (9,6))
fg1 = ax[0].scatter(no_trans["S1_ALL_DEM"].values, no_trans["Del_CAD"].values, c=no_trans["alpha"], cmap = "Set1", alpha=0.4 )
fg2 = ax[1].scatter(no_trans["S1_ALL_DEM"].values, no_trans["Del_CAD"].values, c=no_trans["alpha"], cmap = "Set1", alpha=0.4 )
cbar1 = plt.colorbar(fg1)
cbar1.ax.set_ylabel('alpha', labelpad=20, rotation =-90, fontsize = 12)
cbar2 = plt.colorbar(fg2)
cbar2.ax.set_ylabel('alpha', labelpad=20, rotation =-90, fontsize = 12)
ax[0].set_xlabel("DEM S1")
ax[0].set_ylabel("Del CAD")
ax[0].set_xlim(0,50)
ax[0].invert_yaxis()
ax[1].set_xlabel("DEM S1")
ax[1].set_ylabel("Del CAD")
ax[1].set_xlim(50,35000)
ax[1].invert_yaxis()
I need to fix the colorbars side by side with both of them, how can I do that?

Prevent color bar and title from affecting size of the plot in Matplotlib

def plot_rain(num, show=False):
i = 0
for x in range(num):
ifile = "{:02d}".format(x)
saveimg_name = 'noaa_images/rain/rain.f0{}.png'.format(ifile)
data, _, lats, lons, datetime = collect_data(ifile, RAIN)
lons = np.apply_along_axis(lambda row: row - 360, 1, lons)
# 0.0001, 0.003,0.0005 make no blue background not sure why
cint = np.arange(0.0001, 0.003,0.0005)
fig, ax = plt.subplots()
# Create new figure
mapcrs = ccrs.Mercator(central_longitude=263, min_latitude=23, max_latitude=50, globe=None)
# Set data projection
datacrs = ccrs.PlateCarree()
gs = gridspec.GridSpec(2, 1, height_ratios=[1, .02], bottom=.07,
top=.99, hspace=0.01, wspace=0.01)
# Add the map and set the extent
ax = plt.subplot(gs[0], projection=mapcrs, frameon=False)
ax.set_extent([293, 233 , 23, 55], ccrs.PlateCarree())
ax.set_frame_on(False)
# Add state/country boundaries to plot
ax.add_feature(cfeature.STATES)
ax.add_feature(cfeature.BORDERS)
#Choose colormap https://matplotlib.org/2.0.1/users/colormaps.html
cf = ax.contourf(lons, lats, data, cint, cmap=plt.cm.jet,transform=datacrs, alpha=0.7)
# add color bar and title
# fig.text(.2, .12, "Kg of rainfall per m^2 s",fontweight="bold")
# cb = fig.colorbar(cf, pad=0, aspect=50, orientation='horizontal')
ax.axis('off')
i = i + 1
if show:
plt.show()
else:
plt.savefig(saveimg_name, transparent=True, bbox_inches='tight', pad_inches=0,quality =100,progressive= True)
This above code will generate an image and then I use folium to overlay the image on a map.
Image1 is what it looks like without adding title and color bar.
Here is what it looks like with title and color bar
I use this code
fig.text(.2, .12, "Kg of rainfall per m^2 s",fontweight="bold")
cb = fig.colorbar(cf, pad=0, aspect=50, orientation='horizontal')
After I added title and color bar, the original plots are shrunk. What I want is to add color bar and title without affecting the size of the plot. Thanks for the help!
To avoid resizing of existing axes when adding a colorbar you can give the colorbar its own axes via the cax keyword argument. Here is a minimal example as I cannot reproduce your plot without more data.
fig, ax = plt.subplots()
c = ax.imshow(np.random.random((10, 10)))
cbar_ax = fig.add_axes([0.1, 0.1, 0.05, 0.8])
# new ax with dimensions of the colorbar
cbar = fig.colorbar(c, cax=cbar_ax)
plt.show()

Unwanted Color Palette on Plot

I am having issues with a plot that I have created where I am getting an unwanted additional color palette on the plot.
My script uses to list of data to create a plot with colored points.
plt.close('all')
fig, axes = plt.subplots(nrows = 1, ncols = 1)
fig.set_facecolor('white')
axes.set_ylabel('$dz$ [$\AA$]')
axes.set_xlabel('Time [ns]')
axes.spines['right'].set_visible(False)
axes.spines['top'].set_visible(False)
axes.yaxis.set_ticks_position('left')
axes.xaxis.set_ticks_position('bottom')
axes.tick_params(direction='out')
#axes.set_title('N/A')
axes.set_ylim(-20,10)
axes.set_xlim(0, 90)
cmap = plt.get_cmap('plasma')
colors = [cmap(i) for i in np.linspace(0, 1, 9)]
# Make Color Bar ------------------------------------------------------
cax = 0
divider = make_axes_locatable(axes)
cax = divider.append_axes('right', size='5%', pad=0.1)
im = axes.imshow(np.linspace(1, 8.5, 100).reshape(10, 10), cmap='plasma')
fig.colorbar(im, cax=cax)
#----------------------------------------------------------------------
for i, dist in enumerate(dz):
if i % 100 == 0:
x = i / 1000
y = dist
phval = final_pH_array[i]
axes.plot(x, y, 'k.', markersize = 4 , color = colors[int(phval)], clip_on = False)
plt.savefig('plot.pdf')
plt.show()
The results looks like this:
As you can see there is an additional color bar / color palette that I don't want on the plot but can't seem to get rid of it.
Any help with this would be great!
I think im.set_visible(False) should achieve what you want.
But maybe you should take a look at plt.scatter. scatter returns a PathCollection that you can pass to the colorbar function.

fix colorbar range in basemap python

I'm plotting a 2D temperature array over a world map, using Basemap. All works fine, except for the colorbar, that I want to fix within a certain range Tmin-Tmax. Unfortunately, vmin and vmax that I use for matplotlib, here seem not to work and I wasn't able to find the right keywords (if any) used for this purpose. Any suggestion? Thanks.
fig = plt.figure(figsize=(20,10))
map = Basemap(projection='cyl', lat_0 = 57, lon_0 = -135, resolution = RES, area_thresh = 0.1, llcrnrlon=-180., llcrnrlat=-90., urcrnrlon=180., urcrnrlat=90.)
map.drawcoastlines()
map.drawcountries()
map.drawparallels(np.arange(-90,90,15),labels=[1,1,0,1])
map.drawmeridians(np.arange(-180,180,15),labels=[1,1,0,1])
map.drawmapboundary()
map.imshow(IR1)
cbar = map.colorbar(location='right', pad="5%")
cbar.set_label('T [Celsius]')
plt.title("temperature")
plt.savefig("temperature.png")
Here I give an idea by using np.ma.masked. Any advice on my work would be appreciate.
I use an netcdf file and read the temperature of the whole area. This is similar with your job.
Before setting vmin and vmax
### Read the file
wrf_file1 = "wrf_201401.nc"
t_m1 = gdal.Open('NETCDF:"'+wrf_file1+'":T2')
lon = gdal.Open('NETCDF:"'+wrf_file1+'":XLONG')
lat = gdal.Open('NETCDF:"'+wrf_file1+'":XLAT')
### plot
fig =plt.figure(figsize=(6,4))
ax = plt.subplot()
map = basemap(llcrnrlon=xxx,llcrnrlat=xxx,urcrnrlon=xxx,urcrnrlat=xxx)
x, y = map(lon.ReadAsArray()[362], lat.ReadAsArray()[362])
t = t_m1.ReadAsArray()[30,:,:] ### select one dataframe
cf = map.pcolormesh(x, y,t,cmap=plt.cm.Spectral_r,alpha = 0.8)
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="3%", pad=0.4)
cbar = plt.colorbar(cf, cax=cax)
plt.show()
The colorbar represent that the temperature were range from 268.5 to 281.
If I want to plot the area which temperature were range from 270 to 275. Here is my solution.
Improvement
fig =plt.figure(figsize=(6,4))
ax = plt.subplot()
t = t_m1.ReadAsArray()[30,:,:]
t_mask_1 = np.ma.masked_greater(t,275)
t_mask_2 = np.ma.masked_less(t_mask_1,270)
cf = map.pcolormesh(x, y,t_mask_2,cmap=plt.cm.Spectral_r,alpha = 0.8)
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="3%", pad=0.4)
cbar = plt.colorbar(cf, cax=cax)
plt.show()

How to add a single colobar that will show the data from 2 different subplot

What i wanna do is adding a single colorbar (at the right side of the figure shown below), that will show the colorbar for both subplots (they are at the same scale).
Another thing doesn't really make sense for me is why the lines I try to draw on the end of the code are not drawn (they are supposed to be horizontal lines on the center of both plots)
Thanks for the help.
Here are the code:
idx=0
b=plt.psd(dOD[:,idx],Fs=self.fs,NFFT=512)
B=np.zeros((2*len(self.Chan),len(b[0])))
B[idx,:]=20*log10(b[0])
c=plt.psd(dOD_filt[:,idx],Fs=self.fs,NFFT=512)
C=np.zeros((2*len(self.Chan),len(b[0])))
C[idx,:]=20*log10(c[0])
for idx in range(2*len(self.Chan)):
b=plt.psd(dOD[:,idx],Fs=self.fs,NFFT=512)
B[idx,:]=20*log10(b[0])
c=plt.psd(dOD_filt[:,idx],Fs=self.fs,NFFT=512)
C[idx,:]=20*log10(c[0])
## Calculate the color scaling for the imshow()
aux1 = max(max(B[i,:]) for i in range(size(B,0)))
aux2 = min(min(B[i,:]) for i in range(size(B,0)))
bux1 = max(max(C[i,:]) for i in range(size(C,0)))
bux2 = min(min(C[i,:]) for i in range(size(C,0)))
scale1 = 0.75*max(aux1,bux1)
scale2 = 0.75*min(aux2,bux2)
fig, axes = plt.subplots(nrows=2, ncols=1,figsize=(7,7))#,sharey='True')
fig.subplots_adjust(wspace=0.24, hspace=0.35)
ii=find(c[1]>=frange)[0]
## Making the plots
cax=axes[0].imshow(B, origin = 'lower',vmin=scale2,vmax=scale1)
axes[0].set_ylim((0,2*len(self.Chan)))
axes[0].set_xlabel(' Frequency (Hz) ')
axes[0].set_ylabel(' Channel Number ')
axes[0].set_title('Pre-Filtered')
cax2=axes[1].imshow(C, origin = 'lower',vmin=scale2,vmax=scale1)
axes[1].set_ylim(0,2*len(self.Chan))
axes[1].set_xlabel(' Frequency (Hz) ')
axes[1].set_ylabel(' Channel Number ')
axes[1].set_title('Post-Filtered')
axes[0].annotate('690nm', xy=((ii+1)/2, len(self.Chan)/2-1),
xycoords='data', va='center', ha='right')
axes[0].annotate('830nm', xy=((ii+1)/2, len(self.Chan)*3/2-1 ),
xycoords='data', va='center', ha='right')
axes[1].annotate('690nm', xy=((ii+1)/2, len(self.Chan)/2-1),
xycoords='data', va='center', ha='right')
axes[1].annotate('830nm', xy=((ii+1)/2, len(self.Chan)*3/2-1 ),
xycoords='data', va='center', ha='right')
axes[0].axis('tight')
axes[1].axis('tight')
## Set up the xlim to aprox frange Hz
axes[0].set_xlim(left=0,right=ii)
axes[1].set_xlim(left=0,right=ii)
## Make the xlabels become the actual frequency number
ticks = linspace(0,ii,10)
tickslabel = linspace(0.,frange,10)
for i in range(10):
tickslabel[i]="%.1f" % tickslabel[i]
axes[0].set_xticks(ticks)
axes[0].set_xticklabels(tickslabel)
axes[1].set_xticks(ticks)
axes[1].set_xticklabels(tickslabel)
## Draw a line to separate the two different wave lengths, and name each region
l1 = Line2D([0,frange],[28,28],ls='-',color='black')
axes[0].add_line(l1)
axes[1].add_line(l1)
And here the figure it makes:
If any more info are needed, just ask.
Basically, figure.colorbar() is good for both images, as long as their are not with too different scales. So you could let matplotlib do it for you... or you manually position your colorbar on axes inside the images. Here is how to control the location of the colorbar:
import numpy as np
from matplotlib import pyplot as plt
A = np.random.random_integers(0, 10, 100).reshape(10, 10)
B = np.random.random_integers(0, 10, 100).reshape(10, 10)
fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
mapable = ax1.imshow(A, interpolation="nearest")
cax = ax2.imshow(A, interpolation="nearest")
# set the tickmarks *if* you want cutom (ie, arbitrary) tick labels:
cbar = fig.colorbar(cax, ax=None)
fig = plt.figure(2)
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
mapable = ax1.imshow(A, interpolation="nearest")
cax = ax2.imshow(A, interpolation="nearest")
# on the figure total in precent l b w , height
ax3 = fig.add_axes([0.1, 0.1, 0.8, 0.05]) # setup colorbar axes.
# put the colorbar on new axes
cbar = fig.colorbar(mapable,cax=ax3,orientation='horizontal')
plt.show()
Note ofcourse you can position ax3 as you wish, on the side, on the top, where ever,
as long as it is in the boundaries of the figure.
I don't know why your line2D is not appearing.
I added to my code before plt.show() the following and everything is showing:
from mpl_toolkits.axes_grid1 import anchored_artists
from matplotlib.patheffects import withStroke
txt = anchored_artists.AnchoredText("SC",
loc=2,
frameon=False,
prop=dict(size=12))
if withStroke:
txt.txt._text.set_path_effects([withStroke(foreground="w",
linewidth=3)])
ax1.add_artist(txt)
## Draw a line to separate the two different wave lengths, and name each region
l1 = plt.Line2D([-1,10],[5,5],ls='-',color='black',lineswidth=10)
ax1.add_line(l1)

Categories

Resources