Search code examples
pythonmatplotlibseabornmatplotlibpyplot

Barplot coloring using seaborn.color_palette


I have the following code fragment:

import seaborn
import matplotlib.pyplot as plt
plt.bar(df['Col1'], df['Col2'], width = 0.97, color=seaborn.color_palette("coolwarm", df['Col1'].shape[0], 0.999)) 

Now, my bars are colored in the blue-red spectrum (as given by the parameter coolwarm). How can I change the distribution between these two colors and their order, for example, to get 80% of all bars red and only the rest (i.e., 20%) in blue? (Now it is 50-50% ratio)


Solution

  • There's no built in way to do this using seaborn or the matplotlib colormaps, but here's a solution that seems to do the trick

    import seaborn as sns
    import matplotlib.pyplot as plt
    import pandas as pd
    import numpy as np
    
    ## function that generates a color palette
    def gen_palette(n_left, n_right, cmap_name="coolwarm", desat=0.999):
        """
        n_left: number of colors from "left half" of the colormap
        n_right: number of colors from the "right half"
        cmap_name: name of the color map to use (ideally one of the diverging palettes)
    
        return: palette, list of RGB-triples
        """
        palette_1 = sns.color_palette(palette=cmap_name, 
                                      n_colors=2 * n_left, 
                                      desat=desat)[:n_left]
        palette_2 = sns.color_palette(palette=cmap_name, 
                                      n_colors=2 * n_right, 
                                      desat=desat)[n_right:]
        return palette_1 + palette_2
    
    ## generate example data
    N = 20
    rng = np.random.default_rng(seed=42)
    y_vals = 10 * rng.random(N)
    df = pd.DataFrame(
        {"Col1": np.arange(N),
         "Col2": y_vals}
    )
    
    ## build the color palette with the desired blue-red split
    n_red = round(0.8 * N)
    palette = gen_palette(N - n_red, n_red)
    
    ## plot
    plt.bar(df['Col1'], df['Col2'], 
            width=0.97, 
            color=palette)