Change bar color in histogram - python

I would like to display an histogram with bars in different colors according to a condition.
I mean, I would like to set bars which are between 2 and 5 in a different color.
I've tried this:
bins = np.linspace(0, 20, 21)
lista_float_C1 = [1,1,1,2,2,2,3,4,4,5,5,6,7,8,8,8,8,10,11,11]
colors = []
y = plt.hist(lista_float_C1, bins, alpha=0.5 )
for x in y[1]:
if (x >= 2)&(x=<5):
colors.append('r')
else:
colors.append('b')
print(colors)
plt.hist(lista_float_C1, bins, alpha=0.5, color = colors )
plt.show()
I get this error :
color kwarg must have one color per data set. 1 data sets and 21 colors were provided

You can modify the patches after you plot them:
lista_float_C1 = [1,1,1,2,2,2,3,4,4,5,5,6,7,8,8,8,8,10,11,11]
fig,ax = plt.subplots()
ax.hist(lista_float_C1, bins, alpha=0.5 )
for p in ax.patches:
x = p.get_height()
# modify this to fit your needs
color = 'r' if (2<=x<=5) else 'b'
p.set_facecolor(color)
plt.show()
plt.show()
Output:
If you want to color by bin values:
for p in ax.patches:
# changes here
x,y = p.get_xy()
color = 'r' if (2<=x<=5) else 'b'
p.set_facecolor(color)
plt.show()
Output:

Related

Python : How to create a 2D density map/heat map

I'm coding with python.
I have 3 arrays x, y and z, and I would like to do 2d density map of the z values in the plan (x,y) with colorbar.
So in my plot, the color at the point x[0] and y[0] would be determined by the value of z[0], the color at the point x[1] and y[1] would be determined by the value of z[1], etc.
Does anyone know how to do this ?
Thank you
Check out https://matplotlib.org/api/_as_gen/matplotlib.pyplot.scatter.html
For different colormaps: https://matplotlib.org/tutorials/colors/colormaps.html
A sample piece of code for your need will be something like this
#--------------------------Plotting starts here---------------------------------#
fig, ax0 = plt.subplots()
im0 = plt.scatter(x,y,s=1,c=z, cmap='bwr')
#------------------if you want to use pcolormesh-------------------
#----------and have Z values stored as a numpy array Data---------------------#
#X,Y = np.meshgrid(x,y)
#im0 = ax0.pcolormesh(X,Y,Data, cmap="YourFavouriteColormap')
cbar = fig.colorbar(im0,ax=ax0)
ax0.set_title("Your title")
plt.xlabel("xlabel")
plt.ylabel("ylabel")
filename = "prefix" + "."+ "fileformat"
plt.savefig(filename)
Edit 1:
From one of your comments, if you have grid data, you can try pcolormesh and try shading, an optional argument for interpolation.
shading{'flat', 'gouraud'}, optional
The fill style, Possible values:
'flat': A solid color is used for each quad. The color of the quad (i, j), (i+1, j), (i, j+1), (i+1, j+1) is given by C[i, j].
'gouraud': Each quad will be Gouraud shaded: The color of the corners (i', j') are given by C[i',j']. The color values of the area in between is interpolated from the corner values. When Gouraud shading is used, edgecolors is ignored.
You can use matplotlib's scatter plots with legends and grid where the size of each circle can be referred to z values. This is an example I got from here:
volume = np.random.rayleigh(27, size=40)
amount = np.random.poisson(10, size=40)
ranking = np.random.normal(size=40)
price = np.random.uniform(1, 10, size=40)
fig, ax = plt.subplots()
scatter = ax.scatter(volume, amount, c=ranking, s=0.3*(price*3)**2,
vmin=-3, vmax=3, cmap="Spectral")
legend1 = ax.legend(*scatter.legend_elements(num=5),
loc="upper left", title="Ranking")
ax.add_artist(legend1)
kw = dict(prop="sizes", num=5, color=scatter.cmap(0.7), fmt="$ {x:.2f}",
func=lambda s: np.sqrt(s/.3)/3)
legend2 = ax.legend(*scatter.legend_elements(**kw),
loc="lower right", title="Price")
plt.show()
Output:
In response to your comment AshlinJP :
Either way I still got the error message : "imshow() got multiple values for keyword argument 'cmap'"
I don't know if it has any importance but I use python 2.7
Actually my code is :
import numpy as np
import matplotlib.pyplot as plt
x,y,z = np.loadtxt('gamma.txt', unpack = True)
fig, ax0 = plt.subplots()
cmap = plt.get_cmap('viridis')
im0 = ax0.imshow(x,y,z, cmap=cmap, interpolation="gaussian")
cbar = fig.colorbar(im0,ax=ax0)
ax0.set_title("Your title")
plt.xlabel("xlabel")
plt.ylabel("ylabel")

How to rotate matplotlib bar-chart?

The following code is used to produce a barchart. I would like to rotate it so that it becomes vertical e.g. the current labels at the x axis go to the y axis ,the current y axis labels to the x axis and the bars rotate accordingly.
I am new to matplotlib and python so any help would be welcomed.
def plot_coefficients(classifier, feature_names, top_features=40):
if classifier.__class__.__name__ == 'SVC':
coef = classifier.coef_
coef2 = coef.toarray().ravel()
coef1 = coef2[:len(feature_names)]
else:
coef2 = classifier.coef_.ravel()
coef1 = coef2[:len(feature_names)]
top_positive_coefficients = np.argsort(coef1)[-top_features:]
top_negative_coefficients = np.argsort(coef1)[:top_features]
top_coefficients = np.hstack([top_negative_coefficients, top_positive_coefficients])
# create plot
plt.figure(figsize=(15, 5))
colors = ['red' if c < 0 else 'blue' for c in coef1[top_coefficients]]
plt.bar(np.arange(2 * top_features), coef1[top_coefficients], color=colors)
feature_names = np.array(feature_names)
plt.xticks(np.arange(1, 1 + 2 * top_features), feature_names[top_coefficients], rotation=90, ha='right')
plt.show()
Update
Expected output:
Look at the matplotlib method barh. You can find example from: https://matplotlib.org/gallery/lines_bars_and_markers/barh.html

Font size of axis labels in seaborn

In seaborn, how can you change just the x and y axis label font size? Instead of using the "set context" method, is there a way to specifically change just the axis labels? Here is my code:
def corrfunc(x, y, **kws):
r = stats.pearsonr(x, y)[0] ** 2
ax = plt.gca()
ax.annotate("r$^2$ = {:.2f}".format(r),
xy=(.1, .9), xycoords=ax.transAxes, fontsize=16)
if r > 0.6:
col = 'g'
elif r < 0.6:
col = 'r'
sns.regplot(x, y, color=col)
return r
IC_Plot = sns.PairGrid(df_IC, palette=["red"])
IC_Plot.map_offdiag(corrfunc)
IC_Plot.savefig("Save_Pair.png")
The easiest way to change the fontsize of all x- and y- labels in a plot is to use the rcParams property "axes.labelsize" at the beginning of the script, e.g.
plt.rcParams["axes.labelsize"] = 15
You may also set the font size of each individual label
for ax in plt.gcf().axes:
l = ax.get_xlabel()
ax.set_xlabel(l, fontsize=15)

How to display the value of the bar on each bar with pyplot.barh()

I generated a bar plot, how can I display the value of the bar on each bar?
Current plot:
What I am trying to get:
My code:
import os
import numpy as np
import matplotlib.pyplot as plt
x = [u'INFO', u'CUISINE', u'TYPE_OF_PLACE', u'DRINK', u'PLACE', u'MEAL_TIME', u'DISH', u'NEIGHBOURHOOD']
y = [160, 167, 137, 18, 120, 36, 155, 130]
fig, ax = plt.subplots()
width = 0.75 # the width of the bars
ind = np.arange(len(y)) # the x locations for the groups
ax.barh(ind, y, width, color="blue")
ax.set_yticks(ind+width/2)
ax.set_yticklabels(x, minor=False)
plt.title('title')
plt.xlabel('x')
plt.ylabel('y')
#plt.show()
plt.savefig(os.path.join('test.png'), dpi=300, format='png', bbox_inches='tight') # use format='svg' or 'pdf' for vectorial pictures
Update: there's a built in method for this now! Scroll down a couple answers to "New in matplotlib 3.4.0".
If you can't upgrade that far, it doesn't take much code. Add:
for i, v in enumerate(y):
ax.text(v + 3, i + .25, str(v), color='blue', fontweight='bold')
result:
The y-values v are both the x-location and the string values for ax.text, and conveniently the barplot has a metric of 1 for each bar, so the enumeration i is the y-location.
New in matplotlib 3.4.0
There is now a built-in Axes.bar_label helper method to auto-label bars:
fig, ax = plt.subplots()
bars = ax.barh(indexes, values)
ax.bar_label(bars)
Note that for grouped/stacked bar plots, there will multiple bar containers, which can all be accessed via ax.containers:
for bars in ax.containers:
ax.bar_label(bars)
More details:
How to add thousands separators (commas) to labels
How to apply f-strings to labels
How to add spacing to labels
I have noticed api example code contains an example of barchart with the value of the bar displayed on each bar:
"""
========
Barchart
========
A bar plot with errorbars and height labels on individual bars
"""
import numpy as np
import matplotlib.pyplot as plt
N = 5
men_means = (20, 35, 30, 35, 27)
men_std = (2, 3, 4, 1, 2)
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, men_means, width, color='r', yerr=men_std)
women_means = (25, 32, 34, 20, 25)
women_std = (3, 5, 2, 3, 3)
rects2 = ax.bar(ind + width, women_means, width, color='y', yerr=women_std)
# add some text for labels, title and axes ticks
ax.set_ylabel('Scores')
ax.set_title('Scores by group and gender')
ax.set_xticks(ind + width / 2)
ax.set_xticklabels(('G1', 'G2', 'G3', 'G4', 'G5'))
ax.legend((rects1[0], rects2[0]), ('Men', 'Women'))
def autolabel(rects):
"""
Attach a text label above each bar displaying its height
"""
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()
output:
FYI What is the unit of height variable in "barh" of matplotlib? (as of now, there is no easy way to set a fixed height for each bar)
Use plt.text() to put text in the plot.
Example:
import matplotlib.pyplot as plt
N = 5
menMeans = (20, 35, 30, 35, 27)
ind = np.arange(N)
#Creating a figure with some fig size
fig, ax = plt.subplots(figsize = (10,5))
ax.bar(ind,menMeans,width=0.4)
#Now the trick is here.
#plt.text() , you need to give (x,y) location , where you want to put the numbers,
#So here index will give you x pos and data+1 will provide a little gap in y axis.
for index,data in enumerate(menMeans):
plt.text(x=index , y =data+1 , s=f"{data}" , fontdict=dict(fontsize=20))
plt.tight_layout()
plt.show()
This will show the figure as:
For anyone wanting to have their label at the base of their bars just divide v by the value of the label like this:
for i, v in enumerate(labels):
axes.text(i-.25,
v/labels[i]+100,
labels[i],
fontsize=18,
color=label_color_list[i])
(note: I added 100 so it wasn't absolutely at the bottom)
To get a result like this:
I know it's an old thread, but I landed here several times via Google and think no given answer is really satisfying yet. Try using one of the following functions:
EDIT: As I'm getting some likes on this old thread, I wanna share an updated solution as well (basically putting my two previous functions together and automatically deciding whether it's a bar or hbar plot):
def label_bars(ax, bars, text_format, **kwargs):
"""
Attaches a label on every bar of a regular or horizontal bar chart
"""
ys = [bar.get_y() for bar in bars]
y_is_constant = all(y == ys[0] for y in ys) # -> regular bar chart, since all all bars start on the same y level (0)
if y_is_constant:
_label_bar(ax, bars, text_format, **kwargs)
else:
_label_barh(ax, bars, text_format, **kwargs)
def _label_bar(ax, bars, text_format, **kwargs):
"""
Attach a text label to each bar displaying its y value
"""
max_y_value = ax.get_ylim()[1]
inside_distance = max_y_value * 0.05
outside_distance = max_y_value * 0.01
for bar in bars:
text = text_format.format(bar.get_height())
text_x = bar.get_x() + bar.get_width() / 2
is_inside = bar.get_height() >= max_y_value * 0.15
if is_inside:
color = "white"
text_y = bar.get_height() - inside_distance
else:
color = "black"
text_y = bar.get_height() + outside_distance
ax.text(text_x, text_y, text, ha='center', va='bottom', color=color, **kwargs)
def _label_barh(ax, bars, text_format, **kwargs):
"""
Attach a text label to each bar displaying its y value
Note: label always outside. otherwise it's too hard to control as numbers can be very long
"""
max_x_value = ax.get_xlim()[1]
distance = max_x_value * 0.0025
for bar in bars:
text = text_format.format(bar.get_width())
text_x = bar.get_width() + distance
text_y = bar.get_y() + bar.get_height() / 2
ax.text(text_x, text_y, text, va='center', **kwargs)
Now you can use them for regular bar plots:
fig, ax = plt.subplots((5, 5))
bars = ax.bar(x_pos, values, width=0.5, align="center")
value_format = "{:.1%}" # displaying values as percentage with one fractional digit
label_bars(ax, bars, value_format)
or for horizontal bar plots:
fig, ax = plt.subplots((5, 5))
horizontal_bars = ax.barh(y_pos, values, width=0.5, align="center")
value_format = "{:.1%}" # displaying values as percentage with one fractional digit
label_bars(ax, horizontal_bars, value_format)
For pandas people :
ax = s.plot(kind='barh') # s is a Series (float) in [0,1]
[ax.text(v, i, '{:.2f}%'.format(100*v)) for i, v in enumerate(s)];
That's it.
Alternatively, for those who prefer apply over looping with enumerate:
it = iter(range(len(s)))
s.apply(lambda x: ax.text(x, next(it),'{:.2f}%'.format(100*x)));
Also, ax.patches will give you the bars that you would get with ax.bar(...). In case you want to apply the functions of #SaturnFromTitan or techniques of others.
I needed the bar labels too, note that my y-axis is having a zoomed view using limits on y axis. The default calculations for putting the labels on top of the bar still works using height (use_global_coordinate=False in the example). But I wanted to show that the labels can be put in the bottom of the graph too in zoomed view using global coordinates in matplotlib 3.0.2. Hope it help someone.
def autolabel(rects,data):
"""
Attach a text label above each bar displaying its height
"""
c = 0
initial = 0.091
offset = 0.205
use_global_coordinate = True
if use_global_coordinate:
for i in data:
ax.text(initial+offset*c, 0.05, str(i), horizontalalignment='center',
verticalalignment='center', transform=ax.transAxes,fontsize=8)
c=c+1
else:
for rect,i in zip(rects,data):
height = rect.get_height()
ax.text(rect.get_x() + rect.get_width()/2., height,str(i),ha='center', va='bottom')
I was trying to do this with stacked plot bars. The code that worked for me was.
# Code to plot. Notice the variable ax.
ax = df.groupby('target').count().T.plot.bar(stacked=True, figsize=(10, 6))
ax.legend(bbox_to_anchor=(1.1, 1.05))
# Loop to add on each bar a tag in position
for rect in ax.patches:
height = rect.get_height()
ypos = rect.get_y() + height/2
ax.text(rect.get_x() + rect.get_width()/2., ypos,
'%d' % int(height), ha='center', va='bottom')
Simply add this:
for i in range(len(y)):
plt.text(x= y[i],y= i,s= y[i], c='b')
for every item in the list(y), print the value(s) as blue-colored text on the plot in the position specified (x=position on x-axis and y=position on y-axis)
Check this link
Matplotlib Gallery
This is how I used the code snippet of autolabel.
def autolabel(rects):
"""Attach a text label above each bar in *rects*, displaying its height."""
for rect in rects:
height = rect.get_height()
ax.annotate('{}'.format(height),
xy=(rect.get_x() + rect.get_width() / 2, height),
xytext=(0, 3), # 3 points vertical offset
textcoords="offset points",
ha='center', va='bottom')
temp = df_launch.groupby(['yr_mt','year','month'])['subs_trend'].agg(subs_count='sum').sort_values(['year','month']).reset_index()
_, ax = plt.subplots(1,1, figsize=(30,10))
bar = ax.bar(height=temp['subs_count'],x=temp['yr_mt'] ,color ='g')
autolabel(bar)
ax.set_title('Monthly Change in Subscribers from Launch Date')
ax.set_ylabel('Subscriber Count Change')
ax.set_xlabel('Time')
plt.show()

how to make colors in line graph fade in matplotlib and python

I have two figures with 3 subplots in each of them. In each subplot, there are 20 different curves, which represents 20 steps, by using a for loop. How can I make the color of the curves gradually fade? Like in the code I have below, the top subplot (311) has 20 blue curves...how can I make the 1st step be dark blue and have the blue gradually fade until the last step be a light blue? Also, how do I make the two figures pop up on screen at once? Right now, I have to manually close the first figure in order for the second figure to pop up.
from pylab import *
for raw_step in raw:
raw_step = zip(*raw_step)
Raw_Vertex, Raw_KI, Raw_KII, Raw_KIII = raw_step[0], raw_step[1], raw_step[2], raw_step[3]
subplot(311)
plot(Raw_Vertex, Raw_KI, 'bo-')
grid(True)
title('Raw SIFs')
ylabel('K_I')
subplot(312)
plot(Raw_Vertex, Raw_KII, 'go-')
grid(True)
ylabel('K_II')
subplot(313)
plot(Raw_Vertex, Raw_KIII, 'ro-')
grid(True)
xlabel('Vertex')
ylabel('K_III')
show()
for mls_step in mls:
mls_step = zip(*mls_step)
MLS_Vertex, MLS_KI, MLS_KII, MLS_KIII = mls_step[0], mls_step[1], mls_step[2], mls_step[3]
subplot(311)
plot(MLS_Vertex, MLS_KI, 'bo-')
grid(True)
title('MLS SIFs')
ylabel('K_I')
subplot(312)
plot(MLS_Vertex, MLS_KII, 'go-')
grid(True)
ylabel('K_II')
subplot(313)
plot(MLS_Vertex, MLS_KIII, 'ro-')
grid(True)
xlabel('Vertex')
ylabel('K_III')
show()
To get lightening shades of blue, use
blues = plt.get_cmap('Blues') # this returns a colormap
color = blues(1 - float(i)/(len(raw)-1)) # blues(x) returns a color for each x between 0.0 and 1.0
To place the subplots side-by-side, use fig.add_subplots(row, columns, n) to define the 6 axes.
fig = plt.figure()
ax[1] = fig.add_subplot(3, 2, 1) # 3x2 grid, 1st plot
...
ax[6] = fig.add_subplot(3, 2, 6) # 3x2 grid, 6th plot
import matplotlib.pyplot as plt
import numpy as np
raw = range(20)
mls = range(20)
ax = {}
blues = plt.get_cmap('Blues')
reds = plt.get_cmap('Reds')
greens = plt.get_cmap('Greens')
fig = plt.figure()
ax[1] = fig.add_subplot(3, 2, 1)
ax[1].set_title('Raw SIFs')
ax[1].grid(True)
ax[1].set_ylabel('K_I')
ax[3] = fig.add_subplot(3, 2, 3)
ax[3].grid(True)
ax[3].set_ylabel('K_II')
ax[5] = fig.add_subplot(3, 2, 5)
ax[5].grid(True)
ax[5].set_xlabel('Vertex')
ax[5].set_ylabel('K_III')
ax[2] = fig.add_subplot(3, 2, 2)
ax[2].set_title('MLS SIFs')
ax[2].grid(True)
ax[2].set_ylabel('K_I')
ax[4] = fig.add_subplot(3, 2, 4)
ax[4].grid(True)
ax[4].set_ylabel('K_II')
ax[6] = fig.add_subplot(3, 2, 6)
ax[6].grid(True)
ax[6].set_xlabel('Vertex')
ax[6].set_ylabel('K_III')
for i, raw_step in enumerate(raw):
Raw_Vertex = np.arange(10)
Raw_KI = Raw_Vertex*(i+1)
Raw_KII = Raw_Vertex*(i+1)
Raw_KIII = Raw_Vertex*(i+1)
ax[1].plot(Raw_Vertex, Raw_KI, 'o-', color = blues(1 - float(i)/(len(raw)-1)))
ax[3].plot(Raw_Vertex, Raw_KII, 'o-', color = greens(1 - float(i)/(len(raw)-1)))
ax[5].plot(Raw_Vertex, Raw_KIII, 'o-', color = reds(1 - float(i)/(len(raw)-1)))
for i, mls_step in enumerate(mls):
MLS_Vertex = np.arange(10)
MLS_KI = MLS_Vertex**2*(i+1)
MLS_KII = MLS_Vertex**2*(i+1)
MLS_KIII = Raw_Vertex**2*(i+1)
ax[2].plot(MLS_Vertex, MLS_KI, 'o-', color = blues(1 - float(i)/(len(mls)-1)))
ax[4].plot(MLS_Vertex, MLS_KII, 'o-', color = greens(1 - float(i)/(len(mls)-1)))
ax[6].plot(MLS_Vertex, MLS_KIII, 'o-', color = reds(1 - float(i)/(len(mls)-1)))
plt.show()
If you want a bit more flexibility with your colour choices, then i'd suggest using colorsys;
it has some very useful functions for converting between different colour maps;
http://en.wikipedia.org/wiki/HSL_and_HSV, which can give you MUCH more flexibility.
http://docs.python.org/library/colorsys.html
you can use it like this:
ax[1].plot(Raw_Vertex, Raw_KI, 'o-', color =colorsys.hsv_to_rgb(0,1-i/float(curves),1))
It's easy to vary the lightness, darkness, and colour to anywhere you want, in a much more intuitive manner.

Categories

Resources