Search code examples
pythonmatplotlibbar-chartaxis-labelsx-axis

How to reduce the number of tick labels on a bar plot


The following bar graph is too cluttered on the x axis.

Is there a manner in which I can increment my ticks? Instead of showing every tick between 18-55, it increments by 3 or 5 (or more) so it looks nicer? I noticed that when I ran a line plot, it incremented automatically by 10.**

import matplotlib as mpl
from matplotlib import pyplot as plt
import numpy as np

agesx = [18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
          36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55]

py_devy = [20046, 17100, 20000, 24744, 30500, 37732, 41247, 45372, 48876, 53850, 57287, 63016, 65998, 70003, 70000, 71496, 75370, 83640, 84666,
            84392, 78254, 85000, 87038, 91991, 100000, 94796, 97962, 93302, 99240, 102736, 112285, 100771, 104708, 108423, 101407, 112542, 122870, 120000]

js_devy = [16446, 16791, 18942, 21780, 25704, 29000, 34372, 37810, 43515, 46823, 49293, 53437, 56373, 62375, 66674, 68745, 68746, 74583, 79000,
            78508, 79996, 80403, 83820, 88833, 91660, 87892, 96243, 90000, 99313, 91660, 102264, 100000, 100000, 91660, 99240, 108000, 105000, 104000]

all_devy = [17784, 16500, 18012, 20628, 25206, 30252, 34368, 38496, 42000, 46752, 49320, 53200, 56000, 62316, 64928, 67317, 68748, 73752, 77232,
         78000, 78508, 79536, 82488, 88935, 90000, 90056, 95000, 90000, 91633, 91660, 98150, 98964, 100000, 98988, 100000, 108923, 105000, 103117]

width = 0.25
x_indexes = np.arange(len(agesx))
 
plt.xticks(ticks=x_indexes,labels=agesx)

plt.style.use("seaborn-dark")
plt.bar(x_indexes-width, all_devy, width=width, label= "All Devs")
plt.bar(x_indexes,py_devy,width=width, label= "Python Devs")
plt.bar(x_indexes + width, js_devy, width=width, label= "Javascript Dev")

plt.title("Median Developer Salaries by Age (USD)")
plt.xlabel("Ages")
plt.ylabel("Salary (USD)")
plt.tight_layout()

plt.legend()
plt.show()

This results in the following graph:

Graph1

Initially I thought that I could solve this just by

plt.xticks(np.arange(18,55,3))

However it results in this output:

AttemptedGraph

How can I modify this to get the graph to begin at 18 as opposed to starting the tick at position 18?


Solution

  • 1. Increase Figure Size

    # increase the figure size
    plt.figure(figsize=(10, 6))
    
    plt.bar(x_indexes-width, all_devy, width=width, label= "All Devs")
    plt.bar(x_indexes,py_devy,width=width, label= "Python Devs")
    plt.bar(x_indexes + width, js_devy, width=width, label= "Javascript Dev")
    _ = plt.xticks(ticks=x_indexes, labels=agesx)
    

    enter image description here

    2. Specify the xtick labels with plt.xticks

    • plt.xticks(np.arange(18, 55, 3)) didn't work because, unlike a line plot, bar plot ticks are 0 indexed. print(plt.gca().get_xticklabels()) shows '18' at index 0.
      • You preset the ticks and labels with plt.xticks(ticks=x_indexes, labels=agesx)
      • [v if i%2 == 0 else '' for i, v in enumerate(agesx)] uses a list-comprehension to set every other label to an empty string.
        • Increase 2, for fewer tick labels.
    plt.bar(x_indexes-width, all_devy, width=width, label= "All Devs")
    plt.bar(x_indexes,py_devy,width=width, label= "Python Devs")
    plt.bar(x_indexes + width, js_devy, width=width, label= "Javascript Dev")
    
    # adjust the frequency of the visible labels; the number of ticks and labels must be the same
    _ = plt.xticks(ticks=range(len(agesx)), labels=[v if i%2 == 0 else '' for i, v in enumerate(agesx)])
    

    enter image description here


    import pandas as pd
    
    # load data to pandas
    data = {'Python Devs': py_devy, 'Javascript Devs': js_devy, 'All Devs': all_devy}
    df = pd.DataFrame(data=data, index=agesx)
    
    # 1. plot the bars with rotated labels
    ax = df.plot(kind='bar', width=0.85, rot=90)
    
    # 2. plot with increased figure size
    ax = df.plot(kind='bar', width=0.85, figsize=(10, 6), rot=0)
    
    # 3. plot horizontal bars, which may be better for many bars, and long labels
    ax = df.plot(kind='barh', width=0.85, figsize=(6, 7))
    
    # 4. every other tick label
    ax = df.plot(kind='bar', width=0.85, rot=0, xticks=range(len(df.index))[::2])
    _ = ax.set_xticklabels(df.index[::2])
    

    plot1 plot2 plot3 plot4

    df.head()

        Python Devs  Javascript Devs  All Devs
    18        20046            16446     17784
    19        17100            16791     16500
    20        20000            18942     18012
    21        24744            21780     20628
    22        30500            25704     25206