codes4toads
codes4toads

Reputation: 65

Python Barplot to represent Ranges

I want to make a categorical plot in python to represent the range of several variables. I thought maybe I would use a bar plot and set ranges for the bars. Here is my bar plot

import matplotlib.pyplot as plt
import numpy as np

data = {'a':.3, 'b': .3, 'c': .3, 'd': .1,'e':.1,'f':.1}

names = list(data.keys())    
values = list(data.values())

plt.bar(names,values)
plt.show()

Barplot produced from given code: enter image description here Please tell me how set the value of the bars to something like range(.3,.4). In other words, I want the bars to go from say (.3 to .4 to represent a range) instead of (0 to .3 the way it currently is).

I know using a barplot to represent a range is odd, and if someone has another way for me to do this please add your code. I don't really care as long as I get a plot which represents ranges of at least 6 variables in which I can easily and manually change the value of the ranges.

Upvotes: 6

Views: 13589

Answers (2)

Fourier
Fourier

Reputation: 2993

Updated answer

To solve the issue with axvline, the ratio of width (pixels) versus the range has to be taken into account. I feel that this is a hack.

Therefore, here is a solution that uses axvspan.

import numpy as np
from matplotlib import pyplot as plt

data = {'a':(0,.3), 'b': (0.2,.3), 'c': (.1,.3), 'd': (0.3,0.4),'e':(.1,.2),'f':(.1,.4)}

width = 0.5 # adjust to your liking

fig, ax = plt.subplots()

for i, values in enumerate(data.values()):

    ymin, ymax = values

    ax.axvspan(xmin=i-width/2, xmax=i+width/2, ymin=ymin,ymax=ymax)

# to illustrate that ranges are properly drawn
ax.grid(True)

#add ticks 
ax.set_xticks(np.arange(0,len(data)))    
ax.set_xticklabels(data.keys())

Output:

enter image description here

Original answer

Another option would be to use axvline:

from matplotlib import pyplot as plt

data = {'a':(0,.3), 'b': (0.2,.3), 'c': (.1,.3), 'd': (0.3,0.4),'e':(.1,.2),'f':(.1,.4)}

for key, values in data.items():
    ymin, ymax = values
    plt.axvline(x=key, ymin=ymin, ymax=ymax, lw=5)

Output:

enter image description here

By adjusting lw you can approach a bar plot if required.

Upvotes: 3

dubbbdan
dubbbdan

Reputation: 2740

One approach would be to use a LineCollection and set the linewidth to resemble a bar plot.

To use a LineCollection you need to provide a set of x values that plot each range provided in data. To create the y values associated with your range, I used np.arange. Since np.arange can only count integers, I multiplied each value in data 10 and divided the result by 10 to get back to the input data.

data = {'a':(.3,.4), 'b': (.3,.4), 'c': (.3,.4), 'd': (0,.1),'e':(0,.1),'f':(0,.1)}

names = list(data.keys())    
values = list(data.values())

values = [np.arange(a[0]*10, (a[1]+0.1)*10,1)/10 for a in values]
xs = [np.ones(a.shape) for a in values]

xs = [i*a for i,a in zip(range(len(xs)), xs)]

verts = []
for x,y in zip(xs, values):
    verts.append(list(zip(x.tolist(), y.tolist())))

lc = LineCollection(verts, linewidths=40)

fig,ax = plt.subplots()
ax.add_collection(lc)
ax.set_xlim(-0.5,len(values) )
plt.xticks(np.arange(len(values)), names)

enter image description here

Upvotes: 3

Related Questions