I have a plot in which I merge two datas. Given that, I have to show two different color bars, one for each data. I'm currently plotting my datas as follows:
plt.figure()
# Data 1
fig = plt.imshow(data1, interpolation='nearest', cmap='binary', vmin=0, vmax=1)
# Plotting just the nonzero values of data2
data2_x = numpy.nonzero(data2)[0]
data2_y = numpy.nonzero(data2)[1]
pts = plt.scatter(data2_x, data2_y, marker='s', c=data2[data2_x, data2_y])
plt.colorbar(pts)
plt.colorbar(fig, orientation="horizontal")
And this is the plot that I get:
However, I would like to reposition the color bars to have something like this (made with Photoshop):
Is that possible?
Thank you in advance.
Probably the 'easiest' way to do this is to lay the axes to be used for the color bars out by hand (via cbax = fig.add_axes([....])). You can then pass that axes to the color bar calls:
Something like:
from matplotlib import pyplot as plt
import numpy as np
fig = plt.figure(figsize=(8, 8))
ax = fig.add_axes([.1, .1, .8, .8])
im = ax.imshow(np.random.rand(150, 150), cmap='gray', interpolation='none')
sc = ax.scatter(2 + 146 * np.random.rand(150), 2 + 146 * np.random.rand(150),
c=np.random.rand(150), cmap='Accent', s=50, lw=0)
ax_cb1 = fig.add_axes([.1, .05, .8, .02])
ax_cb2 = fig.add_axes([.92, .1, .02, .8])
cb1 = fig.colorbar(im, cax=ax_cb1, orientation='horizontal')
cb1.ax.xaxis.set_label_position('top')
cb2 = fig.colorbar(sc, cax=ax_cb2, orientation='vertical')
you can link the colorbar to the axes with the ax-keyword, plt.gca() gives you the current axes:
plt.colorbar(object1, ax=plt.gca())
Related
I have a figure with multiple subplot rows that all share an x axis.
Some of the rows require a color bar, but the other rows don't.
If I just use the color bar function, the subplots will be misaligned.
How do I place the color bars outside of the subplots such that all the rows will still be aligned?
I made a function that may help:
import numpy as np
from matplotlib import pyplot as plt
#function to add colorbar for imshow data and axis
def add_colorbar_outside(im,ax):
fig = ax.get_figure()
bbox = ax.get_position() #bbox contains the [x0 (left), y0 (bottom), x1 (right), y1 (top)] of the axis.
width = 0.01
eps = 0.01 #margin between plot and colorbar
# [left most position, bottom position, width, height] of color bar.
cax = fig.add_axes([bbox.x1 + eps, bbox.y0, width, bbox.height])
cbar = fig.colorbar(im, cax=cax)
#Example code:
x = np.random.random((10, 100))
fig, axes = plt.subplots(5,1, sharex = True)
im = axes[0].imshow(x, cmap = "Reds", aspect="auto", origin="lower")
add_colorbar_outside(im, axes[0])
im2 = axes[2].imshow(x, cmap = "coolwarm", aspect="auto", origin="lower")
add_colorbar_outside(im2, axes[2])
plt.show()
I am trying to create an axis plot. I was trying to loop over it as I am plotting the same variable for two different categories. Currently, I have written code two times but I am looking for a smarter way with looping, if possible. Any other suggestion will also be helpful.
zone = ['AB','CD']
plt.style.use('default')
fig,(ax0,ax1) = plt.subplots(2,1, figsize = (18,18), sharex = False)
i = 0
while i < len(zone):
if zone[i] == zone[0]:
ax0.plot(df0['datetime'], df0['pnl1'], color='k', linewidth=1, label ='PnL1')
ax0.plot(df0['datetime'], df0['pnl2'], color='m', linewidth=1, label ='PnL2')
ax00 = ax0.twinx()
ax00.bar(df0['datetime'], df0['qty'], width = 1/96, color='g', align = 'edge', alpha = 0.5, label ='Qty')
elif zone[i] == zone[1]:
ax1.plot(df0['datetime'], df0['pnl1'], color='k', linewidth=1, label ='PnL1')
ax1.plot(df0['datetime'], df0['pnl2'], color='m', linewidth=1, label ='PnL2')
ax01 = ax1.twinx()
ax01.bar(df0['datetime'], df0['hedge'], width = 1/96, color='g', align = 'edge', alpha = 0.5, label ='Qty')
i = i + 1
I want to check if something like below can be done with axis plots or not.
zone = ['AB','CD']
plt.style.use('default')
fig,(ax0,ax1) = plt.subplots(2,1, figsize = (18,18), sharex = False)
i = 0
while i < len(zone):
ax{''}.format(i).plot(df0['datetime'], df0['pnl1'], color='k', linewidth=1, label ='PnL1')
ax{''}.format(i).plot(df0['datetime'], df0['pnl2'], color='m', linewidth=1, label ='PnL2')
ax0{''}.format(i) = ax{''}.format(i).twinx()
ax0{''}.format(i).bar(df0['datetime'], df0['qty'], width = 1/96, color='g', align = 'edge', alpha = 0.5, label ='Qty')
It did not work for me. Any leads to execute axis plot with loop will be helpful.
Here are some ways:
Simply loop over the list of axes
import matplotlib.pyplot as plt
import numpy as np
fig,axes = plt.subplots(2,1)
x = np.linspace(0,5,21)
for ax in axes:
ax.plot(x,np.sin(x))
plt.show()
Works also with index:
for i in range(len(axes)):
axes[i].plot(x,np.sin(x))
For a grid of plot you can use a similar approach:
import matplotlib.pyplot as plt
import numpy as np
fig,axes = plt.subplots(2,2)
x = np.linspace(0,5,21)
for i in range(len(axes)):
for j in range(len(axes[0])):
axes[i][j].plot(x,np.sin(x))
plt.show()
If you don't like double-loops, you can flatten the array with np.ravel()
fig,axes = plt.subplots(2,2)
x = np.linspace(0,5,21)
for ax in np.ravel(axes):
ax.plot(x,np.sin(x))
plt.show()
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()
Using the below code I have made the data to be plotted using only the upper half (0.5 to 1) of the default 'jet' colormap, the range of the colormap being 0 to 1.
If I want the data to show colors only between the range of 0.7 - 1, how do I do it?
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
np.random.seed(1)
# Evaluate an existing colormap from 0.5 (midpoint) to 1 (upper end)
cmap = plt.get_cmap('jet')
colors = cmap(np.linspace(0.5, 1, cmap.N ))
# Create a new colormap from those colors
cmap2 = LinearSegmentedColormap.from_list('Upper Half', colors)
z = np.random.random((4,4))
fig, axes = plt.subplots(ncols=2)
for ax, cmap in zip(axes.flat, [cmap, cmap2]):
cax = ax.imshow(z, cmap=cmap, origin='lower')
cbar = fig.colorbar(cax, ax=ax, orientation='horizontal')
cbar.set_label(cmap.name)
plt.show()
Result:
I want to get something looking like
You can use vmin and vmax argument. Define the ranges in a list called vlst which are 0-1 for the left figure and 0.7-1 for the right figure.
vlst = [[0, 1], [0.7, 1]]
fig, axes = plt.subplots(ncols=2)
for ax, cmap, v in zip(axes.flat, [cmap, cmap2], vlst):
cax = ax.imshow(z, cmap=cmap, origin='lower',vmin=v[0], vmax=v[1])
cbar = fig.colorbar(cax, ax=ax, orientation='horizontal')
cbar.set_label(cmap.name)
plt.show()
I have 8 plots that I want to compare with 8 different but corresponding plots. So I set up 8 subplots, then try to use axes_grid1.make_axes_locatable to divide the subplots. However, it appears that when I use the new_vertical function it returns something of the type matplotlib.axes.AxesSubplot.
Here's the code I have:
fig = plt.figure()
for i in range(7):
ax = fig.add_subplot(4,2,i+1)
idarray = ice_dict[i]
mdarray = model_dict[i]
side_by_side(ax, idarray, mdarray)
def side_by_side(ax1, idata, mdata):
from mpl_toolkits.axes_grid1 import make_axes_locatable
global mycmap
global ice_dict, titles
divider = make_axes_locatable(ax1)
ax2 = divider.new_vertical(size="100%", pad=0.05)
fig1 = ax1.get_figure()
fig1.add_axes(ax2)
cax1 = divider.append_axes("right", size = "5%", pad= 0.05)
plt.sca(ax1)
im1 = ax1.pcolor(idata, cmap = mycmap)
ax1.set_xlim(space.min(), space.max()+1)
ax1.set_ylim(0, len(idata))
plt.colorbar(im1, cax=cax1)
im2 = ax2.pcolor(mdata, cmap = mycmap)
ax2.set_xlim(space.min(), space.max()+1)
for tl in ax2.get_xticklabels():
tl.set_visible(False)
ax2.set_ylim(0, len(mdata))
ax2.invert_yaxis()
Which produces something like this, where ax2 is on top and ax1 is on bottom in each subplot:
I should probably mention that they're on a different scale so I cant just use the same colorbar for both. Thanks in advance.
tl;dr how can I get a colorbar on ax2, an AxesSubplot, as well as ax1, an Axes? Or is there a better way to get the same look?