Dears, I need to make a fill between two thresholds in my chart I have tried with my code but it does not display, could you please tell me what I am doing wrong? I would like my figure like contour red like figure 2
fig = plt.figure(figsize=(15, 6))
ax = fig.add_subplot(111)
ax = lacebita['Prob'].plot(figsize=(15, 7), )
xtime = np.linspace(1990,2021,384)
ax.plot(xtime, lacebita['Prob'], 'black', alpha=1.00, linewidth=2, label = 'Deciles')
ax.fill_between(xtime, 0., lacebita['Prob'], lacebita['Prob']< 30., color='red', alpha=.75)
ax.axhline(50, linestyle='--', color='black',label='Percentile 50')
ax.axhline(33, linestyle='--', color='orange', label='Percentile 33')
ax.set_xlim(1990, 2021)
ax.set_ylim(0, 100, 10)
plt.grid(True)
plt.legend(loc = "upper left")
#ax.autoscale_view()
ax.set_title('Deciles para 12-Meses La Cebita(1990-2020)', fontsize=16)
ax.set_xlim(lacebita.index.min(), lacebita.index.max())
plt.savefig('deciles_12_lacebita.jpg')
There are a couple of ways to go about it. One approach is to fill the space in between the two horizontal threshold lines:
# Make a fake function
t = 20
fs = 10
samples = np.linspace(0, t, int(fs*t), endpoint=False)
wave_y = np.sin(samples)
time_x = np.arange(0, len(wave_y))
# Set upper and lower thresholds where horizontal lines will go and fill in between
upper_th = 0.5
lower_th = -0.5
# Plot function
fig, ax = plt.subplots()
ax.plot(time_x, wave_y)
ax.grid()
ax.set_ylim([-1.25, 1.25])
ax.set_ylabel('y label')
ax.set_xlim([0, 125])
ax.set_xlabel('x label')
# Fill in area under the curve and the horizontal lines
ax.fill_between(x=time_x, y1=upper_th, y2=lower_th, color='red', interpolate=True, alpha=.75)
# Horizontal lines
ax.axhline(upper_th, linestyle='--', color='black', label="upper_th: 0.5")
ax.axhline(lower_th, linestyle='--', color='orange', label='lower_th: - 0.5')
ax.legend()
plt.show()
Or if you change y1
or y2
, for example to y1=0
, you can play around with where exactly the fill is.
Another method is to fill in between the curve and the horizontal dashed lines. To do that you could modify the original data so that the values that go above the upper threshold and below the lower threshold become the threshold values. In other words, we want to make a new y curve that includes the threshold points by eliminating the points that go above/below the threshold so that matplotlib understands that the horizontal lines are part of the y curve.
# Copy original data, we are now going to modify
new_wave_y = np.copy(wave_y)
# Change values outside thresholds to threshold value for fill in
new_wave_y[new_wave_y < lower_th] = lower_th
new_wave_y[new_wave_y > upper_th] = upper_th
This way we can use where
in fill between
to point out where exactly under the curve, including under/above the horizontal lines, matplotlib needs to fill in the area. The full script:
# Make a fake function
t = 20
fs = 10
samples = np.linspace(0, t, int(fs*t), endpoint=False)
wave_y = np.sin(samples)
time_x = np.arange(0, len(wave_y))
# Set upper and lower thresholds where horizontal lines will go and fill in between
upper_th = 0.5
lower_th = -0.5
# Copy original data, we are now going to modify
new_wave_y = np.copy(wave_y)
# Change values outside thresholds to threshold value for fill in
new_wave_y[new_wave_y < lower_th] = lower_th
new_wave_y[new_wave_y > upper_th] = upper_th
# Plot function
fig, ax = plt.subplots()
ax.plot(time_x, wave_y)
ax.grid()
ax.set_ylim([-1.25, 1.25])
ax.set_ylabel('y label')
ax.set_xlim([0, 125])
ax.set_xlabel('x label')
# Fill in area under the curve and the horizontal lines
ax.fill_between(x=time_x, y1=new_wave_y, where=(lower_th < new_wave_y), color='red', interpolate=True, alpha=.75)
ax.fill_between(x=time_x, y1=new_wave_y, where=(new_wave_y < upper_th), color='red', interpolate=True, alpha=.75)
# Horizontal lines
ax.axhline(upper_th, linestyle='--', color='black', label="upper_th: 0.5")
ax.axhline(lower_th, linestyle='--', color='orange', label='lower_th: - 0.5')
ax.legend()
plt.show()
You can get some more information in the Matplotlib fill between demo and the fill between docs.
Edit:
If you want to fill in below or above the threshold line, for example fill in below the lower threshold, you can modify the y curve so that the values above the threshold become the threshold value (same as before but reverse) and change the values in fill_between
. The full script:
# Make a fake function
t = 20
fs = 10
samples = np.linspace(0, t, int(fs*t), endpoint=False)
wave_y = np.sin(samples)
time_x = np.arange(0, len(wave_y))
# Set upper and lower thresholds where horizontal lines will go and fill in between
upper_th = 0.5
lower_th = -0.5
# Copy original data, we are now going to modify
new_wave_y = np.copy(wave_y)
# Change values outside thresholds to threshold value for fill in
new_wave_y[new_wave_y > lower_th] = lower_th
# Plot function
fig, ax = plt.subplots()
ax.plot(time_x, wave_y)
ax.grid()
ax.set_ylim([-1.25, 1.25])
ax.set_ylabel('y label')
ax.set_xlim([0, 125])
ax.set_xlabel('x label')
# Fill in area under the curve and the horizontal lines
ax.fill_between(x=time_x, y1=new_wave_y, y2=lower_th, where=(new_wave_y < lower_th), color='red', interpolate=True, alpha=.75)
# Horizontal lines
ax.axhline(upper_th, linestyle='--', color='black', label="upper_th: 0.5")
ax.axhline(lower_th, linestyle='--', color='orange', label='lower_th: - 0.5')
ax.legend()
plt.show()