Python matplotlib multiple bars Python matplotlib multiple bars python python

Python matplotlib multiple bars


import matplotlib.pyplot as pltfrom matplotlib.dates import date2numimport datetimex = [    datetime.datetime(2011, 1, 4, 0, 0),    datetime.datetime(2011, 1, 5, 0, 0),    datetime.datetime(2011, 1, 6, 0, 0)]x = date2num(x)y = [4, 9, 2]z = [1, 2, 3]k = [11, 12, 13]ax = plt.subplot(111)ax.bar(x-0.2, y, width=0.2, color='b', align='center')ax.bar(x, z, width=0.2, color='g', align='center')ax.bar(x+0.2, k, width=0.2, color='r', align='center')ax.xaxis_date()plt.show()

enter image description here

I don't know what's the "y values are also overlapping" means, does the following code solve your problem?

ax = plt.subplot(111)w = 0.3ax.bar(x-w, y, width=w, color='b', align='center')ax.bar(x, z, width=w, color='g', align='center')ax.bar(x+w, k, width=w, color='r', align='center')ax.xaxis_date()ax.autoscale(tight=True)plt.show()

enter image description here


The trouble with using dates as x-values, is that if you want a bar chart like in your second picture, they are going to be wrong. You should either use a stacked bar chart (colours on top of each other) or group by date (a "fake" date on the x-axis, basically just grouping the data points).

import numpy as npimport matplotlib.pyplot as pltN = 3ind = np.arange(N)  # the x locations for the groupswidth = 0.27       # the width of the barsfig = plt.figure()ax = fig.add_subplot(111)yvals = [4, 9, 2]rects1 = ax.bar(ind, yvals, width, color='r')zvals = [1,2,3]rects2 = ax.bar(ind+width, zvals, width, color='g')kvals = [11,12,13]rects3 = ax.bar(ind+width*2, kvals, width, color='b')ax.set_ylabel('Scores')ax.set_xticks(ind+width)ax.set_xticklabels( ('2011-Jan-4', '2011-Jan-5', '2011-Jan-6') )ax.legend( (rects1[0], rects2[0], rects3[0]), ('y', 'z', 'k') )def autolabel(rects):    for rect in rects:        h = rect.get_height()        ax.text(rect.get_x()+rect.get_width()/2., 1.05*h, '%d'%int(h),                ha='center', va='bottom')autolabel(rects1)autolabel(rects2)autolabel(rects3)plt.show()

enter image description here


after looking for a similar solution and not finding anything flexible enough, I decided to write my own function for it. It allows you to have as many bars per group as you wish and specify both the width of a group as well as the individual widths of the bars within the groups.

Enjoy:

from matplotlib import pyplot as pltdef bar_plot(ax, data, colors=None, total_width=0.8, single_width=1, legend=True):    """Draws a bar plot with multiple bars per data point.    Parameters    ----------    ax : matplotlib.pyplot.axis        The axis we want to draw our plot on.    data: dictionary        A dictionary containing the data we want to plot. Keys are the names of the        data, the items is a list of the values.        Example:        data = {            "x":[1,2,3],            "y":[1,2,3],            "z":[1,2,3],        }    colors : array-like, optional        A list of colors which are used for the bars. If None, the colors        will be the standard matplotlib color cyle. (default: None)    total_width : float, optional, default: 0.8        The width of a bar group. 0.8 means that 80% of the x-axis is covered        by bars and 20% will be spaces between the bars.    single_width: float, optional, default: 1        The relative width of a single bar within a group. 1 means the bars        will touch eachother within a group, values less than 1 will make        these bars thinner.    legend: bool, optional, default: True        If this is set to true, a legend will be added to the axis.    """    # Check if colors where provided, otherwhise use the default color cycle    if colors is None:        colors = plt.rcParams['axes.prop_cycle'].by_key()['color']    # Number of bars per group    n_bars = len(data)    # The width of a single bar    bar_width = total_width / n_bars    # List containing handles for the drawn bars, used for the legend    bars = []    # Iterate over all data    for i, (name, values) in enumerate(data.items()):        # The offset in x direction of that bar        x_offset = (i - n_bars / 2) * bar_width + bar_width / 2        # Draw a bar for every value of that type        for x, y in enumerate(values):            bar = ax.bar(x + x_offset, y, width=bar_width * single_width, color=colors[i % len(colors)])        # Add a handle to the last drawn bar, which we'll need for the legend        bars.append(bar[0])    # Draw legend if we need    if legend:        ax.legend(bars, data.keys())if __name__ == "__main__":    # Usage example:    data = {        "a": [1, 2, 3, 2, 1],        "b": [2, 3, 4, 3, 1],        "c": [3, 2, 1, 4, 2],        "d": [5, 9, 2, 1, 8],        "e": [1, 3, 2, 2, 3],        "f": [4, 3, 1, 1, 4],    }    fig, ax = plt.subplots()    bar_plot(ax, data, total_width=.8, single_width=.9)    plt.show()

Output:

enter image description here