How to seperate stacked bars in matplotlib? - python

I have two dictionaries which's values are the number of people...
d_1={1947: 1, 1950: 1, 1951: 2, 1955: 2, 1956: 1, 1957: 2, 1958: 2, 1959: 3, 1960: 1....}
d_2={1936: 1, 1945: 1, 1948: 2, 1949: 1, 1950: 2, 1951: 2, 1952: 3, 1953: 1, 1954: 41..}
And i want to create bar plot that displays the number of people . And the X-axis is formed in year .
When I used this code format is almost the same except the stacked bars. I want them to be seperated.How can I fix that?
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.pyplot as plt; plt.rcdefaults()
x1=[t for t in d_1.keys()]
y1=[k for k in d_1.values()]
x2=[m for m in d_2.keys()]
y2=[n for n in d_2.values()]
fig, ax = plt.subplots()
index = np.arange(len(years_without_duplicates))
#list which has the years without duplicates
bar_width = 0.35
rects1 = plt.bar(x1, y1, bar_width,color='b')
rects2 = plt.bar(x2, y2, bar_width, color='r')
plt.xlabel('Years')
plt.ylabel('number of people')
plt.xticks([i for i in range(min(years_without_duplicates),max(years_without_duplicates)+1)],rotation=80,fontsize=6)
plt.legend()
plt.tight_layout()
plt.show()

Just shift the bars:
bar_width = 0.35
x1 = [t - bar_width / 2 for t in d_1.keys()]
y1 = [k for k in d_1.values()]
x2 = [m + bar_width / 2 for m in d_2.keys()]
y2 = [n for n in d_2.values()]

Related

How to arrange bins in stacked histogram, Python

I am working on a code of a stacked histogram and I need help arranging the bins in the order if this is possible.
0.01 - 0.1, 0.1 - 0.5, 0.5 - 1.0, 1.0 - 2.5, > 2.5
Right now, my histogram looks like this:
with the order of bins being:
0.01 - 0.1, 1.0 - 2.5, > 2.5, 0.1 - 0.5, 0.5 - 1.0
Code:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
data = [['0.01 - 0.1','A'],['0.1 - 0.5','B'],['0.5 - 1.0','B'],['0.01 - 0.1','C'],['> 2.5','A'],['1.0 - 2.5','A'],['> 2.5','A']]
df = pd.DataFrame(data, columns = ['Size','Index'])
### HISTOGRAM OF SIZE
df_new = df.sort_values(['Size'])
x_var = 'Size'
groupby_var = 'Index'
df_new_agg = df_new.loc[:, [x_var, groupby_var]].groupby(groupby_var)
vals = [df_new[x_var].values.tolist() for i, df_new in df_new_agg]
list_of_colors_element = ['lightcoral','palegreen','forestgreen']
# Draw
plt.figure(figsize=(16,10), dpi= 80)
colors = [plt.cm.Spectral(i/float(len(vals)-1)) for i in range(len(vals))]
n, bins, patches = plt.hist(vals, df_new[x_var].unique().__len__(), stacked=True, density=False, color=list_of_colors_element)
# Decorations
plt.legend({group:col for group, col in zip(np.unique(df_new[groupby_var]).tolist(), list_of_colors_element)}, prop={'size': 16})
plt.title("Stacked Histogram of Size colored by element of highest share", fontsize=22)
plt.xlabel(x_var, fontsize=22)
plt.ylabel("Frequency", fontsize=22)
plt.grid(color='black', linestyle='--', linewidth=0.4)
plt.xticks(range(5),fontsize=15)
plt.yticks(fontsize=15)
plt.show()
Any help is appreciated!
You can use:
piv = df_new.assign(dummy=1) \
.pivot_table('dummy', 'Size', 'Index', aggfunc='count', fill_value=0) \
.rename_axis(columns=None)
ax = piv.plot.bar(stacked=True, color=list_of_colors_element, rot=0, width=1)
plt.show()
I think I'd take a different route and represent the input data differently altogether to make the code easier to read.
import matplotlib.pyplot as plt
labels = ['0.01 - 0.1', '0.1 - 0.5', '0.5 - 1', '1.0 - 2.5', '> 2.5']
A = [1, 0, 0, 1, 2]
B = [0, 1, 1, 0, 0]
C = [1, 0, 0, 0, 0]
width = 1
fig, ax = plt.subplots()
ax.bar(labels, A, width, label='A', color='lightcoral')
ax.bar(labels, B, width, bottom=A, label='B', color='palegreen')
ax.bar(labels, C, width, bottom=A, label='C', color='forestgreen')
ax.set_ylabel('Frequency')
ax.set_xlabel('Size')
ax.set_title("Stacked Histogram of Size colored by element of highest share")
plt.show()

Plotting time series data with with 30sec break point and color

I am new in python programming. I can simply plot the input data shown in the figure with my code but how can I plot the time series data as mention in the figure. Any code and suggestions will be thankful.
My code is:
import matplotlib.pyplot as plt
import numpy as np
y_values = [5, 5, 1, 1, 5, 5, 1, 1, 5, 1, 1]
x_values = np.arange(30, 331, 30)
plt.figure()
plt.plot(x_values,y_values,"-x")
plt.show()
Although there is a way to draw a series of rectangular shapes, we used a general method and used horizontal bar charts. We added a list for the values in the bar chart and stacked the values. Class label names and class titles are now supported as annotations. You can try various other parameters.
import matplotlib.pyplot as plt
import numpy as np
y = [5]*11
y_values = [5, 5, 1, 1, 5, 5, 1, 1, 5, 1, 1]
x_values = np.arange(30, 331, 30)
fig, ax = plt.subplots(figsize=(12,1))
ax.barh(y=0, height=1.0, edgecolor='k', width=y[0], label='Time Interval')
for i in range(len(y)):
if y_values[i] == 5:
color = 'y'
else:
color = 'm'
ax.barh(y=0, left=sum(y[:i]), height=1.0, width=y[i], color=color, edgecolor='k', label='Time Interval')
for s in ['top','bottom','left','right']:
ax.spines[s].set_visible(False)
for i,(p,t) in enumerate(zip(y, y_values)):
ax.text(y=0.6, x=2.5+p*i, s=str(t))
ax.text(-0.08, 1, 'Class', transform=ax.transAxes)
ax.set_xticks([])
ax.set_yticks([])
ax.set_ylabel('Time Interval', rotation=0, labelpad=40, loc='center')
plt.show()
Try:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
y_values = ['class', 5, 5, 1, 1, 5, 5, 1, 1, 5, 1, 1]
x_values = np.arange(30, 331, 30)
x_values = np.concatenate((['Time'],x_values))
df = pd.DataFrame(data={'class': y_values, 'Time': x_values})
colors = {5: 'gold', 1: 'darkviolet'}
df['colors'] = df['class'].map(colors)
df['colors'].fillna('white', inplace=True)
df['Time'].iloc[1:] = ''
print(df)
fig, ax =plt.subplots(1,1)
ax.axis('tight')
ax.axis('off')
data = df.T.values
colors = [data[2].tolist()]
table = ax.table(cellText=[data[1].tolist()], colLabels=data[0].tolist(),loc="center", cellColours=colors)
table.set_fontsize(14)
for i in range(len(data[0])):
table[0, i].visible_edges = ''
table[1, 0].visible_edges = ''
table.scale(1.5, 1.5)
plt.show()

Update text in matplotlib's plot

I want to change text in matplotlib's plot with loop. I am able to print text with loop, but unable to delete the previous text and they got printed on top of each other.
import numpy as np
import matplotlib.pyplot as plt
x = np.array([1,2,3,4,5])
y = np.array([1,2,3,4,5])
fig, ax = plt.subplots()
ax.set_xlim([0,5])
ax.set_ylim([0,5])
for i in x:
pt = ax.plot(i, i, 'o')
tx = ax.text(1, 2, str(i), fontsize = 12)
plt.pause(1)
removePt = pt.pop()
removePt.remove()
I tried to delete text by
removeTx = tx.pop()
removeTx.remove()
but it has not worked.
Kindly suggest how can I remove the previous text from plot.
Just add tx.remove() after the pause:
import numpy as np
import matplotlib.pyplot as plt
x = np.array([1, 2, 3, 4, 5])
y = np.array([1, 2, 3, 4, 5])
fig, ax = plt.subplots()
ax.set_xlim([0, 5])
ax.set_ylim([0, 5])
for i in x:
pt = ax.plot(i, i, 'o')
tx = ax.text(1, 2, str(i), fontsize = 12)
plt.pause(1)
tx.remove()
plt.show()

How to create a step-plot with a gradient based on y-value?

In Python matplotlib, how can you get the line in a line or step plot to display a gradient based on the y-value?
Example plot (made in Tableau):
Code for step plot with a line that changes gradient according to x-value, adapted from this answer:
fig, ax = plt.subplots(figsize=(10, 4))
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
y = [2, 3, 9, 10, 2, 9, 0, 1, 9, 1, -8]
T = np.linspace(0,1,np.size(x))**2
s = 1
for i in range(0, len(x)-s, s):
ax.step(x[i:i+s+1], y[i:i+s+1], marker='.', color=(0.0,0.5,T[i]))
ax.tick_params(axis='both', colors='lightgray', labelsize=8)
The following code is inspired by the multicolored-line example from the matplotlib docs. First the horizontal line segments are drawn and colored using their y-value. The vertical segments are subdivided in small chunks to colored individually.
vmin of the norm is set a bit lower to avoid the too-light range of the colormap.
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
import numpy as np
x = np.arange(50)
y = np.random.randint(-3, 4, x.size).cumsum()
fig, ax = plt.subplots()
norm = plt.Normalize(y.min() - y.ptp() * .2, y.max())
cmap = 'inferno_r' # 'Reds'
horizontal_lines = np.array([x[:-1], y[:-1], x[1:], y[:-1]]).T.reshape(-1, 2, 2)
hor_lc = LineCollection(horizontal_lines, cmap=cmap, norm=norm)
hor_lc.set_array(y[:-1])
ax.add_collection(hor_lc)
factor = 10
long_y0 = np.linspace(y[:-1], y[1:], factor)[:-1, :].T.ravel()
long_y1 = np.linspace(y[:-1], y[1:], factor)[1:, :].T.ravel()
long_x = np.repeat(x[1:], factor - 1)
vertical_lines = np.array([long_x, long_y0, long_x, long_y1]).T.reshape(-1, 2, 2)
ver_lc = LineCollection(vertical_lines, cmap=cmap, norm=norm)
ver_lc.set_array((long_y0 + long_y1) / 2)
ax.add_collection(ver_lc)
ax.scatter(x, y, c=y, cmap=cmap, norm=norm)
plt.autoscale() # needed in case the scatter plot would be omited
plt.show()
Here is another example, with a black background. In this case the darkest part of the colormap is avoided. The changed code parts are:
y = np.random.randint(-9, 10, x.size)
ax.patch.set_color('black')
norm = plt.Normalize(y.min(), y.max() + y.ptp() * .2)
cmap = 'plasma_r'
Here is an example with a TwoSlopeNorm and the blue-white-red colormap:
from matplotlib.colors import TwoSlopeNorm
y = np.random.uniform(-1, 1, x.size * 10).cumsum()[::10]
y = (y - y.min()) / y.ptp() * 15 - 5
norm = TwoSlopeNorm(vmin=-5, vcenter=0, vmax=10)
cmap = 'bwr'

Custom Colorbar-like plot with matplotlib

I'm looking to make a colorbar like plot, like so:
but with a controllable color, for example I have the following x and y arrays:
x = [0,1,2,4,7,8]
y = [1,2,1,3,4,5]
Then I would have a colorbar like the above picture, but when y=1, it would color red, y=2: green, y=3: blue, y=4:black, etc.
Here is the python code that I modified from matplotlib's gallery:
from matplotlib import pyplot
import matplotlib as mpl
fig = pyplot.figure(figsize=(8,1))
ax2 = fig.add_axes([0.05, 0.25, 0.9, 0.5])
cmap = mpl.cm.Accent
norm = mpl.colors.Normalize(vmin=5, vmax=10)
bounds = [1, 2, 4, 7, 8]
norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap=cmap,
norm=norm,
boundaries=[0]+bounds+[13],
ticks=bounds, # optional
spacing='proportional',
orientation='horizontal')
After adapting your code I managed to obtain something like you described.
In this case the colormap is generated using ListedColormap and I added the yellow color for y=5.
It is important to notice that while calculating the BoundaryNorm I am using the intervals that contain the values you described for y.
from matplotlib import pyplot,colors
import matplotlib as mpl
fig = pyplot.figure(figsize=(8,1))
ax2 = fig.add_axes([0.05, 0.25, 0.9, 0.5])
cmap = colors.ListedColormap(['r', 'g', 'b', 'k','y'])
bounds = [0, 1, 2, 4, 7, 8, 13]
yVals = [ 1, 2, 1, 3, 4, 5]
cBounds = [i+0.5 for i in range(6)]
norm = mpl.colors.BoundaryNorm(cBounds, cmap.N)
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap=cmap,
norm=norm,
values=yVals,
boundaries=bounds,
ticks=bounds[1:-1], # optional
spacing='proportional',
orientation='horizontal')
-- Edited 14 of Jan (mrcl) --
Alternatively, you can use pcolormesh to plot your colormap and have a colorbar as your legend, such as in the example below.
from pylab import *
from matplotlib import pyplot,colors
import matplotlib as mpl
fig = pyplot.figure(figsize=(8,1.5))
ax1 = fig.add_axes([0.05, 0.25, 0.82, 0.5])
cmap = colors.ListedColormap(['r', 'g', 'b', 'k','y'])
xBounds = array([0, 1, 2, 4, 7, 8, 13])
yBounds = array([0, 1])
Vals = array([[ 1, 2, 1, 3, 4, 5]])
cBounds = [i+0.5 for i in arange(amax(Vals)+1)]
norm = mpl.colors.BoundaryNorm(cBounds, cmap.N)
c = ax1.pcolormesh(xBounds,yBounds,Vals,cmap=cmap,norm=norm)
ax1.set_xticks(xBounds[1:-1])
ax1.set_yticks([])
ax1.set_xlim(xBounds[0],xBounds[-1])
ax1.set_ylim(yBounds[0],yBounds[-1])
ax2 = fig.add_axes([0.9, 0.25, 0.05, 0.5])
colorbar(c,cax=ax2,ticks=arange(amax(Vals))+1)
Hope it helps.
Cheers
Well, I sort of tinkering with other ways:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cmx
import matplotlib.colors as colors
close('all')
def ColorPlot(x,y):
figure()
jet = plt.get_cmap('jet')
cNorm = colors.Normalize(vmin=min(y), vmax=max(y))
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
if len(x) == len(y):
x.insert(0,0)
for kk in range(len(x)-1):
colorVal = scalarMap.to_rgba(y[kk])
plt.axvspan(x[kk], x[kk+1], facecolor=colorVal,
alpha=0.5,label=colorVal)
plt.yticks([])
plt.xticks(x)
xlim([x[0],x[-1]])
plt.show()
x = [1,3,5,6,10,12]
y = [1,3,4,1,4,3]
ColorPlot(x,y)

Categories

Resources