matplotlibboxplotaxismultiple-axes

Iterate Using .bxp() to Match Colors of other Axes


Here is my problem: enter image description here I want the colors of the boxplots to match the histogram colors.

In previous paired plots I iterate over datasets and when in the same loop Matplotlib handles colors for me. ax.bxp() (documentation) works differently than other plotting functions, taking a list of dictionaries so iterating is not necessary.

        ax.bxp(list_of_dicts # from my DataFrame below
                ,vert=False
                ,showfliers=False)

When I iterate through the boxplot DataFrame rows and use ax.bxp() the boxplots are plotted on top of one another making it useless.

What should I try next?

Sample data for creating the ax.bxp() plot:

       q1     med      mean      q3  whishi  whislo my_data_col label
0  73.992  74.000  73.99936  74.006  73.982  74.030        obs1  obs1
1  73.995  74.001  73.99996  74.007  73.967  74.024        obs2  obs2
2  73.993  73.998  74.00100  74.009  73.986  74.021        obs3  obs3
3  73.999  74.005  74.00332  74.007  73.985  74.020        obs4  obs4
4  73.996  74.004  74.00224  74.009  73.984  74.014        obs5  obs5

Solution

  • You can set the colors explicitly, so you can reuse them across the histograms and boxplots.

    Below is an example how you could use the batched ax.bxp() and set colors.

    If you managed to do it in a for loop but are just stuck with the boxes overlapping, then look into the positions arg of ax.bxp().

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.cbook as cbook
    
    # fake data
    np.random.seed(19680801)
    data = np.random.lognormal(size=(37, 4), mean=1.5, sigma=1.75)
    labels = list("ABCD")
    
    # compute the boxplot stats
    stats = cbook.boxplot_stats(data, labels=labels, bootstrap=10000)
    for n in range(len(stats)):
        stats[n]["med"] = np.median(data)
        stats[n]["mean"] *= 2
    
    # draw boxplots
    fig, ax = plt.subplots()
    bplots = ax.bxp(stats, patch_artist=True)
    ax.set_yscale("log")
    ax.set_yticklabels([])
    
    # change colors
    colors = ["blue", "red", "green", "orange"]
    for patch, clr in zip(bplots["boxes"], colors):
        patch.set_facecolor(clr)
    
    plt.show()
    

    colored boxes