Question: I try to plot the following plot with gradient color ramp using matplotlib fill_between. I can manage to get the color below the horizontal line correctly, but I had difficult time to do the same for above horizontal line. The idea is to keep color above and below the horizontal line up to y values boundary, and the rest removed. Any help would be very great. Here is the same code and data. import numpy as np import matplotlib.pyplot as plt text = "54.38,53.99,65.39,66.22,57.65,49.17,42.72,42.07,44.88,46.56,55.27,57.28,60.54,65.87,37.61,44.21,50.62,56.15,52.65,52.17,57.71,61.21,60.77,50.74,62.9,56.51,62.1,52.79,53.96,50.33,48.44,43.72,39.03,36.18,41.6,50.44,50.67,53.68,50.05,47.92,40.43,29.87,24.78,15.53,17.37,20.56,20.3,30.22,38.89,45.04,45.87,47.99,50.97,54.59,53.69,48.09,48.56,47.62,52.78,57.26,48.77,51.6,56.6,58.37,48.39,43.63,42.15,40.05,33.62,48.73,45.29,51.47,50.73,51.52,54.86,49.18,51.03,50.26,45.73,46.7,52.0,42.17,49.93,53.08,51.34,52.44,54.06,50.56,51.04,55.47,52.71,52.36,53.59,65.08,62.74,59.23,56.07,49.21,46.67,40.62,44.59,44.89,35.57,37.67,49.74,46.52,38.47,42.08,49.73,53.82,60.76,56.2,56.41,53.83,59.9,51.06,46.9,49.11,36.01,46.72,56.53,59.04,58.52,60.78,60.02,51.78,54.78,52.88,51.73,59.76,67.84,66.63,60.97,53.69,53.17,52.44,46.54,49.08,43.62,40.81,41.64,43.3,46.36,58.07,54.95,50.82,54.17,51.37,55.26,53.55,47.57,36.05,38.66,35.3,51.02,54.96,59.34,53.47,48.34,50.25,54.06,49.99,47.44,41.59,37.58,42.39,41.41,41.84,47.77,52.75,54.84,49.63,51.5,56.26,52.47,49.35,47.13,35.94,28.42,33.14,44.38,56.38,59.63,60.86,64.35,54.59,63.34,74.68,66.29,58.33,57.64,64.64,61.49,59.11,53.72,60.37,56.66,56.92,61.58,57.21,58.12,61.93,45.75,54.77,52.95,50.06,54.54,52.64,48.31,49.9,56.49,54.99,51.83,61.78,50.93,52.92,58.76,58.82,51.26,48.29,41.18,50.69,54.0,45.13,48.72,45.32,42.29,30.57,41.28,53.54,55.47,57.54,53.48,50.01,52.42,55.38,53.12,53.31,56.26,57.56,53.87,53.48,53.82,56.8,58.31,60.45,63.22,68.44,76.04,72.14,75.31,64.74,56.5,60.42,54.05,55.62,52" y = np.array([float(i) for i in text.split(",")]) x = np.arange(len(y)) fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(10,6)) cmap ="Spectral" # Define above and below threshold below = y.copy() below[below<=50]=0 above = y.copy() above[above>50]=0 ymin = 10 ymax = 80 xi, yi = np.meshgrid(x, np.linspace(ymin, ymax, 100)) ax.contourf( xi, yi, yi, cmap=cmap, levels=np.linspace(ymin, ymax, 100) ) ax.axhline(50, linestyle="--", linewidth=1.0, color="k") ax.fill_between(x=x, y1=y, color="w") ax.plot(x,y, color="k") ax.set_ylim(ymin, ymax)  

Answer: You can use fill_between with np.minimum to color below the threshold line. And with np.maximum to color above that line. import numpy as np import matplotlib.pyplot as plt y = [54.38,53.99,65.39,66.22,57.65,49.17,42.72,42.07,44.88,46.56,55.27,57.28,60.54,65.87,37.61,44.21,50.62,56.15,52.65,52.17,57.71,61.21,60.77,50.74,62.9,56.51,62.1,52.79,53.96,50.33,48.44,43.72,39.03,36.18,41.6,50.44,50.67,53.68,50.05,47.92,40.43,29.87,24.78,15.53,17.37,20.56,20.3,30.22,38.89,45.04,45.87,47.99,50.97,54.59,53.69,48.09,48.56,47.62,52.78,57.26,48.77,51.6,56.6,58.37,48.39,43.63,42.15,40.05,33.62,48.73,45.29,51.47,50.73,51.52,54.86,49.18,51.03,50.26,45.73,46.7,52.,42.17,49.93,53.08,51.34,52.44,54.06,50.56,51.04,55.47,52.71,52.36,53.59,65.08,62.74,59.23,56.07,49.21,46.67,40.62,44.59,44.89,35.57,37.67,49.74,46.52,38.47,42.08,49.73,53.82,60.76,56.2,56.41,53.83,59.9,51.06,46.9,49.11,36.01,46.72,56.53,59.04,58.52,60.78,60.02,51.78,54.78,52.88,51.73,59.76,67.84,66.63,60.97,53.69,53.17,52.44,46.54,49.08,43.62,40.81,41.64,43.3,46.36,58.07,54.95,50.82,54.17,51.37,55.26,53.55,47.57,36.05,38.66,35.3,51.02,54.96,59.34,53.47,48.34,50.25,54.06,49.99,47.44,41.59,37.58,42.39,41.41,41.84,47.77,52.75,54.84,49.63,51.5,56.26,52.47,49.35,47.13,35.94,28.42,33.14,44.38,56.38,59.63,60.86,64.35,54.59,63.34,74.68,66.29,58.33,57.64,64.64,61.49,59.11,53.72,60.37,56.66,56.92,61.58,57.21,58.12,61.93,45.75,54.77,52.95,50.06,54.54,52.64,48.31,49.9,56.49,54.99,51.83,61.78,50.93,52.92,58.76,58.82,51.26,48.29,41.18,50.69,54.,45.13,48.72,45.32,42.29,30.57,41.28,53.54,55.47,57.54,53.48,50.01,52.42,55.38,53.12,53.31,56.26,57.56,53.87,53.48,53.82,56.8,58.31,60.45,63.22,68.44,76.04,72.14,75.31,64.74,56.5,60.42,54.05,55.62,52.] x = np.arange(len(y)) ymin = 10 ymax = 80 ythresh = 50 fig, ax = plt.subplots(figsize=(10, 6)) ax.axhline(ythresh, linestyle="--", linewidth=1.0, color="k") ax.imshow(np.linspace(0, 1, 256).reshape(-1, 1), origin='lower', aspect='auto', cmap='Spectral', extent=[x[0], x[-1], ymin, ymax]) ax.fill_between(x, ymin, np.minimum(y, ythresh), color="w") ax.fill_between(x, ymax, np.maximum(y, ythresh), color="w") ax.plot(x, y, color="k") plt.show()   Here is a version combining the two fill_betweens into one and use it to clip the gradient. That way, the original background stays visible. As an example, grid lines are drawn behind the gradient. Also, a TwoSlopeNorm puts the threshold at the center of the colormap. The 'turbo' colormap is similar to 'Spectral' and a bit brighter. import matplotlib.pyplot as plt from matplotlib.colors import TwoSlopeNorm from matplotlib.patches import PathPatch import numpy as np y = [54.38,53.99,65.39,66.22,57.65,49.17,42.72,42.07,44.88,46.56,55.27,57.28,60.54,65.87,37.61,44.21,50.62,56.15,52.65,52.17,57.71,61.21,60.77,50.74,62.9,56.51,62.1,52.79,53.96,50.33,48.44,43.72,39.03,36.18,41.6,50.44,50.67,53.68,50.05,47.92,40.43,29.87,24.78,15.53,17.37,20.56,20.3,30.22,38.89,45.04,45.87,47.99,50.97,54.59,53.69,48.09,48.56,47.62,52.78,57.26,48.77,51.6,56.6,58.37,48.39,43.63,42.15,40.05,33.62,48.73,45.29,51.47,50.73,51.52,54.86,49.18,51.03,50.26,45.73,46.7,52.,42.17,49.93,53.08,51.34,52.44,54.06,50.56,51.04,55.47,52.71,52.36,53.59,65.08,62.74,59.23,56.07,49.21,46.67,40.62,44.59,44.89,35.57,37.67,49.74,46.52,38.47,42.08,49.73,53.82,60.76,56.2,56.41,53.83,59.9,51.06,46.9,49.11,36.01,46.72,56.53,59.04,58.52,60.78,60.02,51.78,54.78,52.88,51.73,59.76,67.84,66.63,60.97,53.69,53.17,52.44,46.54,49.08,43.62,40.81,41.64,43.3,46.36,58.07,54.95,50.82,54.17,51.37,55.26,53.55,47.57,36.05,38.66,35.3,51.02,54.96,59.34,53.47,48.34,50.25,54.06,49.99,47.44,41.59,37.58,42.39,41.41,41.84,47.77,52.75,54.84,49.63,51.5,56.26,52.47,49.35,47.13,35.94,28.42,33.14,44.38,56.38,59.63,60.86,64.35,54.59,63.34,74.68,66.29,58.33,57.64,64.64,61.49,59.11,53.72,60.37,56.66,56.92,61.58,57.21,58.12,61.93,45.75,54.77,52.95,50.06,54.54,52.64,48.31,49.9,56.49,54.99,51.83,61.78,50.93,52.92,58.76,58.82,51.26,48.29,41.18,50.69,54.,45.13,48.72,45.32,42.29,30.57,41.28,53.54,55.47,57.54,53.48,50.01,52.42,55.38,53.12,53.31,56.26,57.56,53.87,53.48,53.82,56.8,58.31,60.45,63.22,68.44,76.04,72.14,75.31,64.74,56.5,60.42,54.05,55.62,52.] x = np.arange(len(y)) ymin = 10 ymax = 80 ythresh = 50 fig, ax = plt.subplots(figsize=(10, 6)) ax.grid(True, zorder=-1) # set grid behind the plot ax.axhline(ythresh, linestyle="--", linewidth=1.0, color="k") gradient_rect = ax.imshow(np.linspace(ymin, ymax, 256).reshape(-1, 1), origin='lower', aspect='auto', cmap='turbo_r', norm=TwoSlopeNorm(vcenter=ythresh), extent=[x[0], x[-1], ymin, ymax], zorder=1) fill_poly = ax.fill_between(x, np.minimum(y, 50), np.maximum(y, 50), color="none") clip_poly = PathPatch(fill_poly.get_paths()[0], transform=ax.transData) gradient_rect.set_clip_path(clip_poly) fill_poly.remove() # the polygon isn't needed anymore ax.plot(x, y, color="k") plt.show()