Search code examples
pythonmatplotlibaxis-labels

I can't figure out how to set multi-line xticklabels when reading labels from a list - matplotlib


As the title suggests, I am having trouble finding any documentation on how to print multi-line xticklabels onto my graph when reading from two separate lists. I have heard theories on how to make a separate invisible x-axis and then set the second row of labels off of that, but I have yet to see any code that would explain how that would be done. Thoughts? Thanks for your time.

from inventoryClass import stockItem

import numpy as np
import matplotlib.pyplot as plt

def plotInventory(itemRecords) :

    stockBegin = []
    stockFinish = []  
    stockID = []   
    stockItems = []
    for rec in itemRecords.values() :
        stockBegin.append(rec.getStockStart())
        stockFinish.append(rec.getStockOnHand())
        stockID.append(rec.getID())
        stockItems.append(rec.getName())
    N = len(stockBegin)    
    tuple(stockBegin)
    tuple(stockFinish)

    ind = np.arange(N)  # the x locations for the groups
    width = 0.35       # the width of the bars

    fig, ax = plt.subplots()
    rects1 = ax.bar(ind, stockBegin, width, color='r')
    rects2 = ax.bar(ind + width, stockFinish, width, color='c')
    ymax = ax.get_ylim()    
    ax.set_ylim(0, (max(ymax) + 30))    



    # add some text for labels, title and axes ticks
    ax.set_ylabel('Inventory')
    ax.set_title('Stock start and end inventory, by item')
    ax.set_xticks(ind + width)
    ax.set_xticklabels(stockItems)
    ax.set_xticklabels(stockID)    
    ax.legend((rects1[0], rects2[0]), ('Start', 'End'))

    def autolabel(rects) :

        for rect in rects :
            height = rect.get_height()
            ax.text(rect.get_x() + rect.get_width()/2., 1.05*height,
                    '%d' % int(height),
                ha='center', va='bottom')

    autolabel(rects1)
    autolabel(rects2)

plt.show()

Example of what I am trying to accomplish here:

enter image description here


Solution

  • Join your two lists with a new line character. You can pass the list into ax.set.

    import matplotlib.pyplot as plt
    xlab1 = [ "a", "b", "c"]
    xlab2 = ["1", "2", "3"] 
    xlabels = [f"{x1}\n{x2}" for x1, x2, in zip(xlab1,xlab2)]
    
    fig, ax = plt.subplots()
    _ = ax.bar([0, 3, 6], range(3), width=1)
    _ = ax.bar([1, 4, 7], range(3), width=1)
    _ = ax.set(xticks=[.5, 3.5, 6.5], xticklabels=xlabels)
    

    enter image description here