Home > Mobile >  How can I plot bar plots with variable widths but without gaps in Python, and add bar width as label
How can I plot bar plots with variable widths but without gaps in Python, and add bar width as label

Time:12-25

I have three lists: x, y and w as shown: x is the name of objects. y is its height and w is its width.

x = ["A","B","C","D","E","F","G","H"]

y = [-25, -10, 5, 10, 30, 40, 50, 60]

w = [30, 20, 25, 40, 20, 40, 40, 30]

I'd like to plot these values in a bar plot in Python such that y represents height and w represents width of the bar.

When I plot it using

colors = ["yellow","limegreen","green","blue","red","brown","grey","black"]

plt.bar(x, height = y, width = w, color = colors, alpha = 0.8)

I get a plot as shown: enter image description here

Next, I tried to normalize the widths so that the bars would not overlap with each other using

w_new = [i/max(w) for i in w]
plt.bar(x, height = y, width = w_new, color = colors, alpha = 0.8)
#plt.axvline(x = ?)
plt.xlim((-0.5, 7.5))

I get much better results than before as shown: enter image description here

However, the gaps between the bars are still uneven. For example, between B and C, there is large gap. But between F and G, there is no gap.

I'd like to have plots where there is even gap width or no gap between two consecutive bars. It should look something as shown: enter image description here

How can I create this type of plot in Python? Is it possible using any data visualization libraries such as matplotlib, seaborn or Plotly? Is there any alternative to do it if the data is available in dataframe?

Additionally, I'd like to add labels for A, B, C, etc. to the right of the plot and rather have actual width of the bar as labels on the x-axis (for e.g. depicted by red numbers in the x-axis plot above). I'd also like to add a vertical red line at distance 50 from the x-axis. I know this can be added using plt.axvline(x = ...) But I am not sure what is the value I should state as x as the scale of W is not exact with the length of x-axis.

CodePudding user response:

IIUC, you can try something like this:

import matplotlib.pyplot as plt

x = ["A","B","C","D","E","F","G","H"]

y = [-25, -10, 5, 10, 30, 40, 50, 60]

w = [30, 20, 25, 40, 20, 40, 40, 30]

colors = ["yellow","limegreen","green","blue","red","brown","grey","black"]

#plt.bar(x, height = y, width = w, color = colors, alpha = 0.8)

xticks=[]
for n, c in enumerate(w):
    xticks.append(sum(w[:n])   w[n]/2)
    
w_new = [i/max(w) for i in w]
a = plt.bar(xticks, height = y, width = w, color = colors, alpha = 0.8)
_ = plt.xticks(xticks, x)

plt.legend(a.patches, x)

Output:

enter image description here

Or change xticklabels for bar widths:

xticks=[]
for n, c in enumerate(w):
    xticks.append(sum(w[:n])   w[n]/2)
    
w_new = [i/max(w) for i in w]
a = plt.bar(xticks, height = y, width = w, color = colors, alpha = 0.8)
_ = plt.xticks(xticks, w)
plt.legend(a.patches, x)

Output:

enter image description here

CodePudding user response:

I figured out an alternative way to do this.

x = ["A","B","C","D","E","F","G","H"]

y = [-25, -10, 5, 10, 30, 40, 50, 60]

w = [30, 20, 25, 40, 20, 40, 40, 30]

xpos = []

a = 0
for i in range(len(w)):
    if i == 0:
        a =w[i]
       
        xpos.append(w[i]/2)
        
    else:
        a  = w[i]
       
        xpos.append(a - w[i]/2)

colors = ["yellow","limegreen","green","blue","red","brown","grey","black"]


fig = plt.bar(xpos,
        height = y,
        width = w,
        color = colors,
        alpha = 0.5,
      )

plt.xticks(ticks = xpos, labels = w)

plt.xlim((0, 245))
plt.axvline(x = 150)
plt.legend(fig.patches, x)

plt.show()

enter image description here

  • Related