python-3.xmatplotlibbar-chartcolormap

Bar plot with color gradient on each bar. Error: TypeError: object of type 'ListedColormap' has no len()


I'm willing to generate such a plot:enter image description here

I have troubles defining the colormap as a color for each bar. How Can I do that? I have written the following code:

import matplotlib.pyplot as plt
quiz=[1,2,0,4,8,10]
plt.barh(range(len(quiz)), quiz, align='center', alpha=0.5, color='blue')

It works but all the bars are just of one color(blue here). How to use a colormap as a color?

color=plt.cm.get_cmap('bwr')

gives an

Error: TypeError: object of type 'ListedColormap' has no len()

Edit: This post gives some hints, but doesn't tell me how to make the color gradient correspond to the x values: How to fill matplotlib bars with a gradient?


Solution

  • So , inspired by Thomas Kühn's comment, I got a solution (not sure it's the cleanest one, but it works).

    It basically puts an image with the gradient over the initial horizontal barplot. ax.imshow() normalizes by default the given values. Therefore to make the gradient depend on the x values, we need to remove this forced normalization using the option norm=mpl.colors.NoNorm(vmin=0,vmax=1):

    fig, ax = plt.subplots()
    data=[4,5,6,3,7,5]  
    bar = ax.barh(range(len(data)),data)
    def gradientbars(bars):
          
          ax = bars[0].axes
          lim = ax.get_xlim()+ax.get_ylim()
          for bar in bars:
              
              bar.set_zorder(1)
              bar.set_facecolor("none")
              x,y = bar.get_xy()
              w, h = bar.get_width(), bar.get_height()
              grad = np.atleast_2d(np.linspace(0,1*w/max(data),256))
              ax.imshow(grad, extent=[x,x+w,y,y+h], aspect="auto", zorder=0, norm=mpl.colors.NoNorm(vmin=0,vmax=1))
          ax.axis(lim)  
      
    gradientbars(bar)
      
    

    Result: enter image description here

    You can also change the colormap using the option cmap in ax.imshow(), for example:
    cmap = plt.get_cmap('coolwarm')