I've been playing around with Matplotlib and created a horizontal bar using the following algorithm (Full code and junk data provided at the bottom of this post).
# Version 1
ax.broken_barh([(depth_start[0], thick[0]), (depth_start[1], thick[1]), (depth_start[2], thick[2])], (25, 0.8),
facecolors=('tab:brown', 'tab:blue', 'tab:green'))
which produces the following graphical output:
So I've been trying to make the code more efficient by introducing itertools
I managed to simplify the above code into a version 2:
# Version 2
for i in thick:
ax.broken_barh([(next(cycle_depth), next(cycle_thick))], (15, 0.8), facecolors=(next(cycle_colour)))
Great, this also produces the above bar in the same order with the same colours.
The Problem
But I'm struggling with my next objective which is to replace facecolors=('tab:brown', 'tab:blue', 'tab:green') with a function that uses a for loop. This function ideally selects the correct colour for each bar based on the thickness. All 3 bars return a brown colour as the function continuously returns the value associated with the else statement (see image below).
I've attempted substituting next(cycle_thick) in place of the variable cycle_think in the function, but then only one of the colours is correct again.
The colour_checker() function is as follows:
def colour_checker():
if cycle_thick == 10:
return 'tab:green'
elif cycle_thick == 20:
return 'tab:blue'
else:
return 'tab:brown'
# Version 3
for i in thick:
ax.broken_barh([(next(cycle_depth), next(cycle_thick))], (10, 0.8), facecolors=colour_checker())
Any hints or suggestions welcomed!
Full Code and Junk Data
import itertools
import matplotlib.pyplot as plt
# Junk data in the form of lists
depth_start = [90, 70, 40] # top of lithology
thick = [30, 20, 10] # thickness for each lithology
colour = ('tab:brown', 'tab:blue', 'tab:green')
# Lists to be cycled through
cycle_colour = itertools.cycle(colour)
cycle_depth = itertools.cycle(depth_start)
cycle_thick = itertools.cycle(thick)
#setting up the plot
fig, ax = plt.subplots()
def colour_checker():
if cycle_thick == [0]:
return 'tab:green'
elif cycle_thick == [1]:
return 'tab:blue'
else:
return 'tab:brown'
# Version 1
ax.broken_barh([(depth_start[0], thick[0]), (depth_start[1], thick[1]), (depth_start[2], thick[2])], (25, 0.8),
facecolors=('tab:brown', 'tab:blue', 'tab:green'))
# Version 2
for i in thick:
ax.broken_barh([(next(cycle_depth), next(cycle_thick))], (15, 0.8), facecolors=(next(cycle_colour)))
# Version 3
for i in thick:
ax.broken_barh([(next(cycle_depth), next(cycle_thick))], (10, 0.8), facecolors=colour_checker())
ax.set_ylabel('X_UTM Position')
ax.set_xlabel('MAMSL')
plt.show()
Since the intention of the outcome was ambiguous, I have created examples for all three versions I can imagine.
import matplotlib.pyplot as plt
# Junk data in the form of lists
depth_start = [90, 70, 40, 200, 170, 140] # top of lithology
thick = [30, 20, 10, 20, 10, 30] # thickness for each lithology
colour = ('tab:brown', 'tab:blue', 'tab:green')
#setting up the plot
fig, ax = plt.subplots()
#Version 1: using zip to chain all three lists
for start, length, color in zip(depth_start, thick, colour+colour[::-1]):
ax.broken_barh([(start, length)], (-0.4, 0.8), facecolors=color)
#Version 2: color cycler repetitive color assignments
from itertools import cycle
cycle_colour = cycle(colour)
for start, length in zip(depth_start, thick):
ax.broken_barh([(start, length)], (0.6, 0.8), facecolors=next(cycle_colour))
#Version 3: lookup table to color bars of a specific length with a certain color
color_dic = {30: 'tab:brown', 20: 'tab:blue', 10: 'tab:green'}
for start, length in zip(depth_start, thick):
ax.broken_barh([(start, length)], (1.6, 0.8), facecolors=color_dic[length])
ax.set_yticks(range(3))
ax.set_yticklabels(["Version 1", "Version 2", "Version 3"])
plt.show()
Sample output:
Related
I need to create something like this
in Google Colab. I have all the data on an array. First, I tried using matplotlib to create a horizontal bar chart. I made this based on the examples given on their documentation:
import matplotlib.pyplot as plt
import numpy as np
n = 4
bars1 = (20, 35, 30, 35)
bars2 = (25, 32, 34, 20)
ind = np.arange(n) # the x locations for the groups
fig, ax = plt.subplots()
p1 = ax.barh(ind, bars1)
p2 = ax.barh(ind, bars2, left=bars1)
ax.set_ylabel('Bars')
ax.set_title('Divisions of each bars')
plt.yticks(ind)
# Label with label_type 'center' instead of the default 'edge'
ax.bar_label(p1, label_type='center')
ax.bar_label(p2, label_type='center')
plt.show()
and this is the result of this code
This looks good, but has a major limitation: I need to have the same number of intervals on every bar, which doesn't always happen on the first picture. Which library could I use to recreate something like this? I tried searching but I don't know exactly how to specify my problem.
The trick to getting a section to not appear is to add a value of np.nan, not float("nan"). So, using this data:
bars1 = (20, 35, 30, 35)
bars2 = (25, 32, 34, np.nan)
results in this graph:
I think you can achieve that with the code you already wrote.
The first thing let's consider is that each bar needs to have an
accumulated value = 100 (it can be any number) let's called MAX.
Then for each bar, you calculate the actual value you have, and if
it's less of our MAX, add the MAX - current value to your bar.
like that we will have all bars at MAX value.
but you will not have the exact same number of sections in each bar if one of those is already at MAX value. to fix that you will need to calculate the MAX value by finding the maximum value in your bars and add x value to it.
code :
import matplotlib.pyplot as plt
import numpy as np
def get_added_bar(bars):
max = 0
new_limit = 0
added_val = 5
vertic_sums = []
added_bar = []
for x in bars:
t=0
for item in x:
if t > len(vertic_sums)-1:
vertic_sums.append(item)
else:
vertic_sums[t] = vertic_sums[t]+item
if vertic_sums[t] > max:
max = vertic_sums[t]
t=t+1
new_limit = max + added_val
t=0
for x in vertic_sums:
added_bar.append(new_limit-vertic_sums[t])
t=t+1
return tuple(added_bar)
def sum_bars(bars) :
vertic_sums = []
for x in bars:
t=0
for item in x:
if t > len(vertic_sums)-1:
vertic_sums.append(item)
else:
vertic_sums[t] = vertic_sums[t]+item
t=t+1
return tuple(vertic_sums)
n = 4
# 0 for missing value
bars1 = (0, 35, 30, 35)
bars2 = (25, 32, 0, 20)
added_bar = get_added_bar((bars1,bars2)) #
ind = np.arange(n) # the x locations for the groups
fig, ax = plt.subplots()
print((bars1,bars2,added_bar))
p1 = ax.barh(ind, bars1)
p2 = ax.barh(ind, bars2, left=bars1)
p3 = ax.barh(ind, added_bar, left=sum_bars((bars1,bars2)), color='white')
ax.set_ylabel('Bars')
ax.set_title('Divisions of each bars')
plt.yticks(ind)
print(ind)
# Label with label_type 'center' instead of the default 'edge'
ax.bar_label(p1, label_type='center')
ax.bar_label(p2, label_type='center')
# ax.bar_label(p3, label_type='center')
plt.show()
you can check, I created a working example here:
https://replit.com/join/mgpidbnqfb-amirping
you can change any value in your bars with 0 if it's missing and you will still have it working
I would like to add error bar in my plot that I can show the min max of each plot. Please, anyone can help me. Thanks in advance.
The min max is as follow:
Delay = (53.46 (min 0, max60) , 36.22 (min 12,max 70), 83 (min 21,max 54), 17 (min 12,max 70))
Latency = (38 (min 2,max 70), 44 (min 12,max 87), 53 (min 9,max 60), 10 (min 11,max 77))
import matplotlib.pyplot as plt
import pandas as pd
from pandas import DataFrame
from matplotlib.dates import date2num
import datetime
Delay = (53.46, 36.22, 83, 17)
Latency = (38, 44, 53, 10)
index = ['T=0', 'T=26', 'T=50','T=900']
df = pd.DataFrame({'Delay': Delay, 'Latency': Latency}, index=index)
ax = df.plot.bar(rot=0)
plt.xlabel('Time')
plt.ylabel('(%)')
plt.ylim(0, 101)
plt.savefig('TestX.png', dpi=300, bbox_inches='tight')
plt.show()
In order to plot in the correct location on a bar plot, the patch data for each bar must be extracted.
An ndarray is returned with one matplotlib.axes.Axes per column.
In the case of this figure, ax.patches contains 8 matplotlib.patches.Rectangle objects, one for each segment of each bar.
By using the associated methods for this object, the height, width, and x locations can be extracted, and used to draw a line with plt.vlines.
The height of the bar is used to extract the correct min and max value from dict, z.
Unfortunately, the patch data does not contain the bar label (e.g. Delay & Latency).
import pandas as pd
import matplotlib.pyplot as plt
# create dataframe
Delay = (53.46, 36.22, 83, 17)
Latency = (38, 44, 53, 10)
index = ['T=0', 'T=26', 'T=50','T=900']
df = pd.DataFrame({'Delay': Delay, 'Latency': Latency}, index=index)
# dicts with errors
Delay_error = {53.46: {'min': 0,'max': 60}, 36.22: {'min': 12,'max': 70}, 83: {'min': 21,'max': 54}, 17: {'min': 12,'max': 70}}
Latency_error = {38: {'min': 2, 'max': 70}, 44: {'min': 12,'max': 87}, 53: {'min': 9,'max': 60}, 10: {'min': 11,'max': 77}}
# combine them; providing all the keys are unique
z = {**Delay_error, **Latency_error}
# plot
ax = df.plot.bar(rot=0)
plt.xlabel('Time')
plt.ylabel('(%)')
plt.ylim(0, 101)
for p in ax.patches:
x = p.get_x() # get the bottom left x corner of the bar
w = p.get_width() # get width of bar
h = p.get_height() # get height of bar
min_y = z[h]['min'] # use h to get min from dict z
max_y = z[h]['max'] # use h to get max from dict z
plt.vlines(x+w/2, min_y, max_y, color='k') # draw a vertical line
If there are non-unique values in the two dicts, so they can't be combined, we can select the correct dict based on the bar plot order.
All the bars for a single label are plotted first.
In this case, index 0-3 are the Dalay bars, and 4-7 are the Latency bars
for i, p in enumerate(ax.patches):
print(i, p)
x = p.get_x()
w = p.get_width()
h = p.get_height()
if i < len(ax.patches)/2: # select which dictionary to use
d = Delay_error
else:
d = Latency_error
min_y = d[h]['min']
max_y = d[h]['max']
plt.vlines(x+w/2, min_y, max_y, color='k')
Some zipping and stacking will suffice—see bar_min_maxs below. Simplifying and slightly generalizing Trenton's code:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# create dataframe
Delay = (53.46, 36.22, 83, 17)
Latency = (38, 44, 53, 10)
index = ['T=0', 'T=26', 'T=50','T=900']
df = pd.DataFrame({'Delay': Delay, 'Latency': Latency,
'Delay_min': (0, 12, 21, 12), # supply min and max
'Delay_max': (60, 70, 54, 70),
'Latency_min': (2, 12, 9, 11),
'Latency_max': (70, 87, 60, 77)},
index=index)
# plot
ax = df[['Delay', 'Latency']].plot.bar(rot=0)
plt.xlabel('Time')
plt.ylabel('(%)')
plt.ylim(0, 101)
# bar_min_maxs[i] is bar/patch i's min, max
bar_min_maxs = np.vstack((list(zip(df['Delay_min'], df['Delay_max'])),
list(zip(df['Latency_min'], df['Latency_max']))))
assert len(bar_min_maxs) == len(ax.patches)
for patch, (min_y, max_y) in zip(ax.patches, bar_min_maxs):
plt.vlines(patch.get_x() + patch.get_width()/2,
min_y, max_y, color='k')
And if errorbars are expressed through margins of errors instead of mins and maxs, i.e., the errorbar is centered at the bar's height w/ length 2 x margin of error, then here's code to plot those:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# create dataframe
Delay = (53.46, 36.22, 83, 17)
Latency = (38, 44, 53, 10)
index = ['T=0', 'T=26', 'T=50','T=900']
df = pd.DataFrame({'Delay': Delay, 'Latency': Latency,
'Delay_moe': (5, 15, 25, 35), # supply margin of error
'Latency_moe': (10, 20, 30, 40)},
index=index)
# plot
ax = df[['Delay', 'Latency']].plot.bar(rot=0)
plt.xlabel('Time')
plt.ylabel('(%)')
plt.ylim(0, 101)
# bar_moes[i] is bar/patch i's margin of error, i.e., half the length of an
# errorbar centered at the bar's height
bar_moes = np.ravel(df[['Delay_moe', 'Latency_moe']].values.T)
assert len(bar_moes) == len(ax.patches)
for patch, moe in zip(ax.patches, bar_moes):
height = patch.get_height() # of bar
min_y, max_y = height - moe, height + moe
plt.vlines(patch.get_x() + patch.get_width()/2,
min_y, max_y, color='k')
One minor statistical note: if the difference b/t the two groups (Delay and Latency for each T=t) is of interest, then add a plot for the difference with an errorbar for the difference. A plot like the one above is not sufficient for directly analyzing differences; if, e.g., the two errorbars overlap at T=0, this does not imply that the difference b/t Delay and Latency is not statistically significant at whatever level was used. (Though if they don't overlap, then the difference is statistically significant.)
I have lists of data indicating responses to likert questions with a one (very unhappy) to five (very happy) scale. I would like to create a page of plots showing these lists as skewed stacked horizontal bar charts. The lists of responses can be of different sizes (e.g. when someone has opted out of answering a particular question). Here is a minimal example of the data:
likert1 = [1.0, 2.0, 1.0, 2.0, 1.0, 3.0, 3.0, 4.0, 4.0, 1.0, 1.0]
likert2 = [5.0, 4.0, 5.0, 4.0, 5.0, 3.0]
I would like to be able to plot this with something like:
plot_many_likerts(likert1, likert2)
At the moment I've written a function to iterate over the lists, and plot each one as its own subplot on a shared figure in matplotlib:
def plot_many_likerts(*lsts):
#get the figure and the list of axes for this plot
fig, axlst = plt.subplots(len(lsts), sharex=True)
for i in range(len(lsts)):
likert_horizontal_bar_list(lsts[i], axlst[i], xaxis=[1.0, 2.0, 3.0, 4.0, 5.0])
axlst[i].axis('off')
fig.show()
def likert_horizontal_bar_list(lst, ax, xaxis):
cnt = Counter(lst)
#del (cnt[None])
i = 0
colour_float = 0.00001
previous_right = 0
for key in sorted(xaxis):
ax.barh(bottom=0, width=cnt[key], height=0.4, left=previous_right, color=plt.cm.jet(colour_float),label=str(key))
i += 1
previous_right = previous_right + cnt[key]
colour_float = float(i) / float(len(xaxis))
This works not badly and create stacked bar charts all with the same representative sizes (e.g. the widths share common axis scales). Here is a screen shot:
What is currently Produced http://s7.postimg.org/vh0j816gn/figure_1.jpg
What I would like is to have these two plots centered on midpoints of the mode of the datasets (the datasets will have the same range). For instance:
What I would like to see http://s29.postimg.org/z0qwv4ryr/figure_2.jpg
Suggestions on how I might do this?
I needed to make a divergent bar chart for some likert data. I was using pandas, but the approach would probably be similar without it. The key mechanism is to add in an invisible buffer at the start.
likert_colors = ['white', 'firebrick','lightcoral','gainsboro','cornflowerblue', 'darkblue']
dummy = pd.DataFrame([[1,2,3,4, 5], [5,6,7,8, 5], [10, 4, 2, 10, 5]],
columns=["SD", "D", "N", "A", "SA"],
index=["Key 1", "Key B", "Key III"])
middles = dummy[["SD", "D"]].sum(axis=1)+dummy["N"]*.5
longest = middles.max()
complete_longest = dummy.sum(axis=1).max()
dummy.insert(0, '', (middles - longest).abs())
dummy.plot.barh(stacked=True, color=likert_colors, edgecolor='none', legend=False)
z = plt.axvline(longest, linestyle='--', color='black', alpha=.5)
z.set_zorder(-1)
plt.xlim(0, complete_longest)
xvalues = range(0,complete_longest,10)
xlabels = [str(x-longest) for x in xvalues]
plt.xticks(xvalues, xlabels)
plt.show()
There are many limitations to this approach. First, bars no longer get a black outline, and the legend will have an extra blank element. I just hid the legend (I figure there's probably a way to hide just the individual element). I'm not sure of a convenient way to make the bars have an outline without also adding the outline to the buffer element.
First, we establish some colors and dummy data. Then we calculate the width of the left two columns and half of the middle-most column (which i know to be "SD", "D", and "N", respectively). I find the longest column, and use its width to calculate the difference needed for the other columns. Next, I insert this new buffer column into the first column position with a blank title (which felt gross, lemme tell you). For good measure, I also added a vertical line (axvline) behind the middle of the middle bar based on the advice of [2]. Finally, I adjust the x-axis to have the proper scale by offsetting its labels.
You might want more horizontal space on the left - you can easily do so by adding to "longest".
[2] Heiberger, Richard M., and Naomi B. Robbins. "Design of diverging stacked bar charts for Likert scales and other applications." Journal of Statistical Software 57.5 (2014): 1-32.
I too recently needed to make a divergent bar chart for some Likert data. I took a slightly different approach than #austin-cory-bart.
I modified an example from the gallery instead and created this:
import numpy as np
import matplotlib.pyplot as plt
category_names = ['Strongly disagree', 'Disagree',
'Neither agree nor disagree', 'Agree', 'Strongly agree']
results = {
'Question 1': [10, 15, 17, 32, 26],
'Question 2': [26, 22, 29, 10, 13],
'Question 3': [35, 37, 7, 2, 19],
'Question 4': [32, 11, 9, 15, 33],
'Question 5': [21, 29, 5, 5, 40],
'Question 6': [8, 19, 5, 30, 38]
}
def survey(results, category_names):
"""
Parameters
----------
results : dict
A mapping from question labels to a list of answers per category.
It is assumed all lists contain the same number of entries and that
it matches the length of *category_names*. The order is assumed
to be from 'Strongly disagree' to 'Strongly aisagree'
category_names : list of str
The category labels.
"""
labels = list(results.keys())
data = np.array(list(results.values()))
data_cum = data.cumsum(axis=1)
middle_index = data.shape[1]//2
offsets = data[:, range(middle_index)].sum(axis=1) + data[:, middle_index]/2
# Color Mapping
category_colors = plt.get_cmap('coolwarm_r')(
np.linspace(0.15, 0.85, data.shape[1]))
fig, ax = plt.subplots(figsize=(10, 5))
# Plot Bars
for i, (colname, color) in enumerate(zip(category_names, category_colors)):
widths = data[:, i]
starts = data_cum[:, i] - widths - offsets
rects = ax.barh(labels, widths, left=starts, height=0.5,
label=colname, color=color)
# Add Zero Reference Line
ax.axvline(0, linestyle='--', color='black', alpha=.25)
# X Axis
ax.set_xlim(-90, 90)
ax.set_xticks(np.arange(-90, 91, 10))
ax.xaxis.set_major_formatter(lambda x, pos: str(abs(int(x))))
# Y Axis
ax.invert_yaxis()
# Remove spines
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
# Ledgend
ax.legend(ncol=len(category_names), bbox_to_anchor=(0, 1),
loc='lower left', fontsize='small')
# Set Background Color
fig.set_facecolor('#FFFFFF')
return fig, ax
fig, ax = survey(results, category_names)
plt.show()
I am going through Think Stats and I would like to compare multiple data sets visually. I can see from the book examples that it is possible to generate an interleaved bar graph with a different color for each data set by using a module provided by the book author, how to obtain the same result in pyplot?
Call the bar function multiple times, one for each series. You can control the left position of the bars using the left parameter, and you can use this to prevent overlap.
Entirely untested code:
pyplot.bar( numpy.arange(10) * 2, data1, color = 'red' )
pyplot.bar( numpy.arange(10) * 2 + 1, data2, color = 'red' )
Data2 will be drawn shifted over the right compared to where data one will be drawn.
Matplotlib's example code for interleaved bar charts works nicely for arbitrary real-valued x coordinates (as mentioned by #db42).
However, if your x coordinates are categorical values (like in the case of dictionaries in the linked question), the conversion from categorical x coordinates to real x coordinates is cumbersome and unnecessary.
You can plot two dictionaries side-by-side directly using matplotlib's api. The trick for plotting two bar charts with an offset to each other is to set align=edge and a positive width (+width) for plotting one bar chart, whereas a negative width (-width) for plotting the other one.
The example code modified for plotting two dictionaries looks like the following then:
"""
========
Barchart
========
A bar plot with errorbars and height labels on individual bars
"""
import matplotlib.pyplot as plt
# Uncomment the following line if you use ipython notebook
# %matplotlib inline
width = 0.35 # the width of the bars
men_means = {'G1': 20, 'G2': 35, 'G3': 30, 'G4': 35, 'G5': 27}
men_std = {'G1': 2, 'G2': 3, 'G3': 4, 'G4': 1, 'G5': 2}
rects1 = plt.bar(men_means.keys(), men_means.values(), -width, align='edge',
yerr=men_std.values(), color='r', label='Men')
women_means = {'G1': 25, 'G2': 32, 'G3': 34, 'G4': 20, 'G5': 25}
women_std = {'G1': 3, 'G2': 5, 'G3': 2, 'G4': 3, 'G5': 3}
rects2 = plt.bar(women_means.keys(), women_means.values(), +width, align='edge',
yerr=women_std.values(), color='y', label='Women')
# add some text for labels, title and axes ticks
plt.xlabel('Groups')
plt.ylabel('Scores')
plt.title('Scores by group and gender')
plt.legend()
def autolabel(rects):
"""
Attach a text label above each bar displaying its height
"""
for rect in rects:
height = rect.get_height()
plt.text(rect.get_x() + rect.get_width()/2., 1.05*height,
'%d' % int(height),
ha='center', va='bottom')
autolabel(rects1)
autolabel(rects2)
plt.show()
The result:
I came across this problem a while ago and created a wrapper function that takes a 2D array and automatically creates a multi-barchart from it:
The code:
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import operator as o
import numpy as np
dpoints = np.array([['rosetta', '1mfq', 9.97],
['rosetta', '1gid', 27.31],
['rosetta', '1y26', 5.77],
['rnacomposer', '1mfq', 5.55],
['rnacomposer', '1gid', 37.74],
['rnacomposer', '1y26', 5.77],
['random', '1mfq', 10.32],
['random', '1gid', 31.46],
['random', '1y26', 18.16]])
fig = plt.figure()
ax = fig.add_subplot(111)
def barplot(ax, dpoints):
'''
Create a barchart for data across different categories with
multiple conditions for each category.
#param ax: The plotting axes from matplotlib.
#param dpoints: The data set as an (n, 3) numpy array
'''
# Aggregate the conditions and the categories according to their
# mean values
conditions = [(c, np.mean(dpoints[dpoints[:,0] == c][:,2].astype(float)))
for c in np.unique(dpoints[:,0])]
categories = [(c, np.mean(dpoints[dpoints[:,1] == c][:,2].astype(float)))
for c in np.unique(dpoints[:,1])]
# sort the conditions, categories and data so that the bars in
# the plot will be ordered by category and condition
conditions = [c[0] for c in sorted(conditions, key=o.itemgetter(1))]
categories = [c[0] for c in sorted(categories, key=o.itemgetter(1))]
dpoints = np.array(sorted(dpoints, key=lambda x: categories.index(x[1])))
# the space between each set of bars
space = 0.3
n = len(conditions)
width = (1 - space) / (len(conditions))
# Create a set of bars at each position
for i,cond in enumerate(conditions):
indeces = range(1, len(categories)+1)
vals = dpoints[dpoints[:,0] == cond][:,2].astype(np.float)
pos = [j - (1 - space) / 2. + i * width for j in indeces]
ax.bar(pos, vals, width=width, label=cond,
color=cm.Accent(float(i) / n))
# Set the x-axis tick labels to be equal to the categories
ax.set_xticks(indeces)
ax.set_xticklabels(categories)
plt.setp(plt.xticks()[1], rotation=90)
# Add the axis labels
ax.set_ylabel("RMSD")
ax.set_xlabel("Structure")
# Add a legend
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles[::-1], labels[::-1], loc='upper left')
barplot(ax, dpoints)
plt.show()
If you're interested in what this function does and the logic behind it, here's a (shamelessly self-promoting) link to the blog post describing it.
hi i have a dict with 3-int-tuple representing color (as key) and an int representing the numbers of occurences of that color in an image (as value)
for exemple, this is a 4x4 pixels image with 3 colors:
{(87, 82, 44): 1, (255, 245, 241): 11, (24, 13, 9): 4}
i want to plot a pie chart of list [1,11,4] in which each slice of the piechart is colored with the right color.. how can i do?
Update: the other answer from Paul is much better but there's not really any point in me just editing my original answer until it's essentially the same :) (I can't delete this answer because it's accepted.)
Does this do what you want? I just took an example from the matplotlib documentation and turned your data into parameters that pie() expects:
# This is a trivial modification of the example here:
# http://matplotlib.sourceforge.net/examples/pylab_examples/pie_demo.html
from pylab import *
data = {(87, 82, 44): 1, (255, 245, 241): 11, (24, 13, 9): 4}
colors = []
counts = []
for color, count in data.items():
colors.append([float(x)/255 for x in color])
counts.append(count)
figure(1, figsize=(6,6))
pie(counts, colors=colors, autopct='%1.1f%%', shadow=True)
title('Example Pie Chart', bbox={'facecolor':'0.8', 'pad':5})
show()
The result looks like this:
Mark beat me by 5 minutes, so points should go to him, but here's my (nearly identical, but more terse) answer anyway:
from matplotlib import pyplot
data = {(87, 82, 44): 1, (255, 245, 241): 11, (24, 13, 9): 4}
colors, values = data.keys(), data.values()
# matplotlib wants colors as 0.0-1.0 floats, not 0-255 ints
colors = [tuple(i/255. for i in c) for c in colors]
pyplot.pie(values, colors=colors)
pyplot.show()