I have to plot a figure that contains three curves that are close to each other. When I plot the confidence intervals in each curve, I get an ugly figure that contains confidence intervals that are overlapped.
Here is an example.
from matplotlib import pyplot as plt
import numpy as np
y1 = [2, 3.9, 5.8, 7.2]
y2 = [2, 3.7, 5.6, 7.1]
y3 = [1.9, 3.6, 5.4, 6.8]
x = [2, 4, 6, 8]
ci1 = 1.96 * np.std(y1)/np.sqrt(len(x))
ci2 = 1.96 * np.std(y2)/np.sqrt(len(x))
ci3 = 1.96 * np.std(y3)/np.sqrt(len(x))
fig, ax = plt.subplots()
ax.plot(x, y1)
ax.fill_between(x, (y1-ci1), (y1+ci1), color='b', alpha=.1)
ax.plot(x, y2)
ax.fill_between(x, (y2-ci2), (y2+ci2), color='b', alpha=.1)
ax.plot(x, y3)
ax.fill_between(x, (y3-ci3), (y3+ci3), color='b', alpha=.1)
plt.show()
Do you know of any better way to show the curves with the confidence intervals? I tried with error bars but it is even uglier. Is it a good alternative to show the confidence intervals in the legend or some where in the x- or y-axis?
I'm not sure about your confidence interval being constant along the x-axis.
Your data should have multiple points for each x values, then you have a confidence interval for each x value, something like this:
import numpy as np
x = [2, 4, 6, 8]
num_x = len(x)
num_y = 20
y1 = np.array([2, 3.9, 5.8, 7.2])
y2 = np.array([2, 3.7, 5.6, 7.1])
y3 = np.array([1.9, 3.6, 5.4, 6.8])
# Multiple points for each x values
y1 = np.stack([y1 for _ in range(num_y)], axis=0)
y2 = np.stack([y2 for _ in range(num_y)], axis=0)
y3 = np.stack([y3 for _ in range(num_y)], axis=0)
# Some randomness for CI
y1 = y1 + np.random.randn(*y1.shape)
y2 = y2 + np.random.randn(*y2.shape)
y3 = y3 + np.random.randn(*y3.shape)
For your actual question, maybe you can plot individual boxes for each point of each curve:
from matplotlib import pyplot as plt
fig, ax = plt.subplots()
# Tweaks the position so no overlapping
num_curves = 3
pos1 = np.arange(1, (num_curves + 1) * num_x + 1, num_curves + 1)
pos2 = np.arange(2, (num_curves + 1) * num_x + 2, num_curves + 1)
pos3 = np.arange(3, (num_curves + 1) * num_x + 3, num_curves + 1)
# But then fix the ticks
xticks = [2, 6, 10, 14]
xtickslabels = [1, 2, 3, 4]
bplot1 = ax.boxplot(y1, positions=pos1, patch_artist=True)
bplot2 = ax.boxplot(y2, positions=pos2, patch_artist=True)
bplot3 = ax.boxplot(y3, positions=pos3, patch_artist=True)
ax.set_xticks(xticks)
ax.set_xticklabels(xtickslabels)
bplots = (bplot1, bplot2, bplot3)
colors = ["pink", "lightblue", "lightgreen"]
for bplot, clr in zip(bplots, colors):
for patch in bplot["boxes"]:
patch.set_facecolor(clr)
plt.show()