I have the following code:
import matplotlib.pyplot as plt
import numpy as np
img1 = np.zeros([512,512])
img2 = np.zeros([512,512])
plt.figure(figsize=(10,10))
plt.imshow(img1, cmap='inferno')
plt.axis('off')
cba = plt.colorbar(shrink=0.25)
cba.ax.set_ylabel('Events / counts', fontsize=14)
cba.ax.tick_params(labelsize=12)
plt.imshow(img2, cmap='turbo', alpha=0.5)
plt.axis('off')
cba = plt.colorbar(shrink=0.25)
cba.ax.set_ylabel('Lifetime / ns)', fontsize=14)
cba.ax.tick_params(labelsize=12)
plt.tight_layout()
plt.show()
which produces the following output:
My question is, how can I get color bars that are on top of one another as opposed to next to each other? Ideally, I would like to get something like this:
You can grab the position of the ax and use it to create new axes for the colorbars. Here is an example:
import numpy as np
import matplotlib.pyplot as plt
from scipy import ndimage
data = ndimage.gaussian_filter(np.random.randn(512, 512), sigma=15, mode='nearest') * 20
fig, ax = plt.subplots()
im1 = ax.imshow(data, vmin=-1, vmax=0, cmap='viridis')
data[data < 0] = np.nan
im2 = ax.imshow(data, vmin=0.001, vmax=1, cmap='Reds_r')
ax.axis('off')
pos = ax.get_position()
bar_h = (pos.y1 - pos.y0) * 0.5 # 0.5 joins the two bars, e.g. 0.48 separates them a bit
ax_cbar1 = fig.add_axes([pos.x1 + 0.02, pos.y0, 0.03, bar_h])
cbar1 = fig.colorbar(im1, cax=ax_cbar1, orientation='vertical')
ax_cbar2 = fig.add_axes([pos.x1 + 0.02, pos.y1 - bar_h, 0.03, bar_h])
cbar2 = fig.colorbar(im2, cax=ax_cbar2, orientation='vertical')
plt.show()
How can I modify this plot to show me the value of each bar upon hovering mouse?
sns.barplot(x = "date", y = "no_of_dogs", data = dogs_adopted_per_day, palette="husl")
plt.show()
You could employ mplcursors as follows:
import matplotlib.pyplot as plt
import mplcursors
import numpy as np
import pandas as pd
import seaborn as sns
df = pd.DataFrame({"date": pd.date_range('20210101', periods=10),
"no_of_dogs": np.random.randint(10, 30, 10)})
fig, ax = plt.subplots(figsize=(15, 5))
sns.barplot(x="date", y="no_of_dogs", data=df, palette="husl", ax=ax)
x_dates = df['date'].dt.strftime('%Y-%m-%d')
ax.set_xticklabels(labels=x_dates)
cursor = mplcursors.cursor(hover=True)
#cursor.connect("add")
def on_add(sel):
x, y, width, height = sel.artist[sel.target.index].get_bbox().bounds
sel.annotation.set(text=f"{x_dates[round(x)]}\n{height:.0f}",
position=(0, 20), anncoords="offset points")
sel.annotation.xy = (x + width / 2, y + height)
plt.show()
I am having a multicolored line plot and I want to add a color bar under it in the same figure like as shown in the image below, Is it possible?
I have attached a color bar image as a reference which I took from another code.
My intention here is to use the color bar like a legend for each segment of the line in the plot.
Edit-1: I want to have the color bar using a mappable object such as an image, So don't want to create a new subplot for the sole purpose of the color bar.
Any suggestion is welcome. Thanks in Advance.
This is the code for multicolored line plot
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
Segments=[[[3,1],[6,1]],[[6,2],[9,2]],[[9,3],[12,3]],[[12,4],[15,4]], [[12,4],[15,4]]]
Points_1 = np.concatenate([Segments[:-1], Segments[1:]], axis=1)
lc = LineCollection(Points_1, colors=['r','g','b','y'], linewidths=2)
fig, ax = plt.subplots()
ax.add_collection(lc)
ax.autoscale()
plt.show()
This is a workaround I'am using:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
import matplotlib.colorbar as mcolorbar
import matplotlib.colors as mcolors
Segments=[[[3,1],[6,1]],[[6,2],[9,2]],[[9,3],[12,3]],[[12,4],[15,4]], [[12,4],[15,4]]]
Points_1 = np.concatenate([Segments[:-1], Segments[1:]], axis=1)
lc = LineCollection(Points_1, colors=['r','g','b','y'], linewidths=2)
fig, ax = plt.subplots(2, 1, gridspec_kw={'height_ratios' : [5,1]})
ax[0].add_collection(lc)
bounds = np.linspace(0, 1, 5)[:-1]
labels = ['Action1', 'Action2', 'Action3', 'Action4']
ax[0].set_xlim([0, 15])
ax[0].set_ylim([0, 10])
cb2 = mcolorbar.ColorbarBase(ax = ax[1], cmap = cmap, orientation = 'horizontal', extendfrac='auto')
cb2.set_ticks(bounds)
cb2.set_ticklabels(labels)
plt.tight_layout()
plt.show()
If you specifically want to avoid subplots, you can use a scalar mappable:
fig, ax = plt.subplots()
ax.add_collection(lc)
ax.autoscale()
cmap = mcolors.ListedColormap(['r','g','b','y'])
sm = plt.cm.ScalarMappable(cmap=cmap)
sm.set_array([]) # this line may be ommitted for matplotlib >= 3.1
cbar = fig.colorbar(sm, ax=ax, orientation='horizontal',aspect=90)
bounds = np.linspace(0, 1, 5)[:-1]
labels = ['Action1', 'Action2', 'Action3', 'Action4']
ax.set_xlim([0, 15])
ax.set_ylim([0, 10])
cbar.set_ticks(bounds)
cbar.set_ticklabels(labels)
plt.tight_layout()
plt.show()
This helped me to get what I asked.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib.collections import LineCollection
Segments=[[[3,1],[6,1]],[[6,2],[9,2]],[[9,3],[12,3]],[[12,4],[15,4]], [[12,4],[15,4]]]
Points_1 = np.concatenate([Segments[:-1], Segments[1:]], axis=1)
lc = LineCollection(Points_1, colors=['r','g','b','y'], linewidths=2)
fig, ax = plt.subplots()
ax.add_collection(lc)
ax.autoscale()
c=[1,2,3,4,5]
labels = ['Action1', 'Action2', 'Action3', 'Action4']
cmap = mcolors.ListedColormap(['r','g','b','y'])
norm = mcolors.BoundaryNorm([1,2,3,4,5],4)
sm = plt.cm.ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([]) # this line may be ommitted for matplotlib >= 3.1
cbar=fig.colorbar(sm, ticks=c, orientation='horizontal')
cbar.set_ticklabels(['Action1', 'Action2', 'Action3', 'Action4'])
plt.show()
I am trying to color the errorbar points based on the color from an array. But getting an error. My code is shown below:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.cm import ScalarMappable, coolwarm as cmap
from matplotlib.colors import Normalize
fig = plt.figure(1)
sp = fig.add_subplot(1, 1, 1)
sp.set_xlabel(r'$x$')
sp.set_ylabel(r'$y$')
x = np.random.rand(10)
y = np.random.rand(10)
M = np.logspace(9, 10, 10)
norm = Normalize(vmin=8, vmax=11,clip=False) # controls the min and max of the colorbar
smap = ScalarMappable(cmap=cmap, norm=norm)
for xi, yi, Mi in zip(x, y, M):
c = cmap(norm(np.log10(Mi))) # make sure to color by log of mass, not mass
sp.errorbar(
xi,
yi,
yerr=[[.1], [.1]],
xerr=[[.1], [.1]],
ecolor=c,
marker='o',
mec=c,
mfc=c
)
cb = plt.colorbar(smap)
cb.set_label(r'$\log_{10}M$')
I am getting the following error:
TypeError: You must first set_array for mappable
For matplotlib < 3.1, you need to set an array - which can be empty
sm = ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
fig.colorbar(sm)
For matplotlib >= 3.1, this is not necessary any more.
sm = ScalarMappable(cmap=cmap, norm=norm)
fig.colorbar(sm)
I'm trying to build a violin plot using matplotlib.
While setting the manual X-axis ticks based on the example provided here, I am failing to do so. Where am I missing out?
Here is a MWE
#!/usr/bin/env python3
import os
import numpy as np
import warnings
import matplotlib.pyplot as plt
import matplotlib.cbook
import matplotlib as mpl
warnings.filterwarnings("ignore",category=matplotlib.cbook.mplDeprecation)
OUTPUT_PATH=os.getcwd() + "/"
# Dots per inch for figure.
DPI = 500
def test_plot():
fig = plt.figure()
vector_size=100
bucket2 = np.random.rand(vector_size)
bucket3 = np.random.rand(vector_size)
bucket4 = np.random.rand(vector_size)
bucket5 = np.random.rand(vector_size)
bucket6 = np.random.rand(vector_size)
pos = [1,2,3,4,5]
data= [np.array(bucket2), np.array(bucket3), np.array(bucket4), np.array(bucket5), np.array(bucket6)]
axes1 = fig.add_subplot(111)
axes1.violinplot(data, pos, points=100, widths=0.7, showmeans=False, showextrema=True, showmedians=True)
axes1.set_xlabel('x-axis')
axes1.set_ylabel('y-axis')
xticks_t = ["",".1-.2", ".2-.3", ".3-.4", ".4-.5", ">.5"]
axes1.set_xticklabels(xticks_t)
axes1.set_xlim([0, 5])
axes1.spines['right'].set_visible(False)
axes1.spines['top'].set_visible(False)
axes1.xaxis.set_ticks_position('bottom')
axes1.yaxis.set_ticks_position('left')
fig.tight_layout()
file_name = 'test_violin.pdf'
fig.savefig(OUTPUT_PATH + str(file_name), bbox_inches='tight', dpi=DPI, pad_inches=0.1)
fig.clf()
plt.close()
pass
test_plot()
You can use the LaTeX expressions for the last tick to correctly display > as
xticks_t = ["",".1-.2", ".2-.3", ".3-.4", ".4-.5", r"$>.5$"]
and comment out the x-axis limits # axes1.set_xlim([0, 5])
which produces