I would like to adjust the bar value text position below each bar top with barwidth/5 offset.
text_y -= bar.get_width()/5 # <- not work
Full code:
#!/usr/bin/env python3
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.patheffects as PathEffects
import math
import numpy as np
def save_fig(fig,pngname):
fig.savefig(pngname, dpi=fig.dpi, bbox_inches="tight")
print("[[%s]]"%pngname)
return
def plot_bar(df):
xname = df.columns[0]
fig, ax = plt.subplots(figsize=(10, 5))
x = np.arange(len(df[xname]))
n = len(df.columns[1:])
bar_width = 0.95/n
fontsize = 20
colors = ['#5891ad','#004561','#ff6f31','#1c7685','#0f45a8','#4cdc8b','#0097a7']
dy = -bar_width/10
bars = []
# add bars
for i,colname in enumerate(df.columns[1:]):
bar = ax.bar(x+i*bar_width, df[colname], width=bar_width,color=colors[i])
bars.append(bar)
# add text on bars
for bar in ax.patches:
bar_value = bar.get_height()
text = f'{bar_value:,}'
text_x = bar.get_x() + bar.get_width() / 2
text_y = bar.get_y() + bar_value
text_y -= bar.get_width()/5 # <- not work
bar_color = bar.get_facecolor()
t = ax.text(text_x, text_y, text, ha='center', va='top', color=bar_color,
size=fontsize)
t.set_path_effects([PathEffects.withStroke(linewidth=bar_width*15, foreground='w')])
ax.set_xticks(x + 1/ 2 - bar_width/2)
ax.set_xticklabels(df[xname])
ax.legend()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
#ax.spines['left'].set_visible(False)
#ax.spines['bottom'].set_color('#DDDDDD')
ax.tick_params(bottom=False, left=False)
ax.set_axisbelow(True)
ax.yaxis.grid(True, color='#EEEEEE')
ax.xaxis.grid(False)
ax.set_xlabel('x', labelpad=15)
ax.set_ylabel('y', labelpad=15)
ax.set_title('title', pad=15)
fig.tight_layout()
plt.show()
return
data = [['a',3,2,1],
['b',2,3,1],
['c',3,1,3],
['d',5,1,3],
]
df = pd.DataFrame(data,columns=['f1','f2','f3','f4'])
plot_bar(df)
Related
Say below example code, the annotation line not match the start and end point exactly:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
def annotate_delta(ax,df0,colname,col0,col1):
x = col1
y0 = df0[colname].iloc[col0]
y1 = df0[colname].iloc[col1]
d = 0.05
ax.annotate('',
xy=(x+d, y0),
xytext=(x+d, y1),
xycoords='data',
textcoords='data',
arrowprops=dict(arrowstyle='|-|',facecolor='red',color='r'),
annotation_clip=False)
ax.annotate('%.1f'%(y1-y0),
xy=(x+d+0.15, (y1+y0)/2),
color='r',ha='center',
va='center',
rotation=-90
,annotation_clip=False)
return
def plotme(df0,label):
fig = plt.figure(figsize=(12,6))
ax1 = fig.add_subplot(111)
xcol = 'A'
ycol = 'B'
df.plot(x=xcol,y=ycol,ax=ax1,marker='.')
annotate_delta(ax1,df0,ycol,0,len(df0)-1)
ax1.set_xticks(np.arange(len(df0)))
ax1.set_xticklabels(df0[xcol],rotation=45, ha='right')
plt.tight_layout()
ax1.grid(axis='y')
ax1.spines['right'].set_visible(False)
ax1.spines['top'].set_visible(False)
plt.xlabel("X")
plt.ylabel("Y")
fig.savefig("demo.png", dpi=fig.dpi)
return
df = pd.DataFrame({'A':['apple','orange','bananna','watermelon'],'B':[1,3.5,2.5,4]})
plotme(df,"Sample")
Arrow annotations are shrunk by 2 points by default:
shrinkA: default is 2 points
shrinkB: default is 2 points
Set shrinkA=0 and shrinkB=0 in arrowprops to remove the default padding:
arrowprops=dict(arrowstyle='|-|',color='r',shrinkA=0,shrinkB=0)
How to colour the base on y = 0.3 by the same color as the middle part of the cylinder have, please?
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d import proj3d
def data_for_cylinder_along_z(center_x,center_y,radius,height_z):
z = np.linspace(0, height_z, 200)
theta = np.linspace(0, 2*np.pi, 200)
theta_grid, z_grid=np.meshgrid(theta, z)
x_grid = radius*np.cos(theta_grid) + center_x
y_grid = radius*np.sin(theta_grid) + center_y
return x_grid,y_grid,z_grid
fig = plt.figure(figsize=[6,5])
ax = fig.add_subplot(111, projection='3d')
ax.azim = -39
ax.elev = 15
Xc,Zc,Yc = data_for_cylinder_along_z(0,0,0.05,0.3)
ax.plot_surface(Xc, Yc, Zc, alpha=0.4, color = 'grey')
plt.show()
I read the document of matplotlib and write the following code, it supposed to capture my mouse event and move the grey line position when i clicked. I read this code in jupiter notebook online, it stop to show the coordinate of my cursor as it usually do, What's happend? Can anyone help me?
import pandas as pd
import numpy as np
import matplotlib.colors as mcol
import matplotlib.cm as cm
from scipy import stats
from matplotlib.lines import Line2D
import matplotlib.pyplot as plt
import scipy.spatial as spatial
np.random.seed(12345)
df = pd.DataFrame([np.random.normal(33500,150000,3650),
np.random.normal(41000,90000,3650),
np.random.normal(41000,120000,3650),
np.random.normal(48000,55000,3650)],
index=[1992,1993,1994,1995])
fig, ax = plt.subplots()
year_avg = df.mean(axis = 1)
year_std = df.std(axis = 1)
yerr = year_std / np.sqrt(df.shape[1]) * stats.t.ppf(1-0.05/2, df.shape[1]-1)
bars=ax.bar(range(df.shape[0]), year_avg, yerr = yerr, color = 'lightslategrey')
threshold=42000
line=plt.axhline(y = threshold, color = 'grey', alpha = 0.5)
cm1 = mcol.LinearSegmentedColormap.from_list("CmapName",["yellow", "orange", "red"])
cpick = cm.ScalarMappable(cmap=cm1)
percentages = []
cpick.set_array([])
def setColor(bars, yerr,threshold):
for bar, yerr_ in zip(bars, yerr):
low = bar.get_height() - yerr_
high = bar.get_height() + yerr_
percentage = (high-threshold)/(high-low)
if percentage>1: percentage = 1
if percentage<0: percentage=0
percentages.append(percentage)
cpick.to_rgba(percentages)
bars = ax.bar(range(df.shape[0]), year_avg, yerr = yerr, color = cpick.to_rgba(percentages))
return bars
line=plt.axhline(threshold, color = 'grey', alpha = 0.5)
setColor(bars, yerr,threshold)
plt.colorbar(cpick, orientation='horizontal')
plt.xticks(range(df.shape[0]), df.index)
fig = plt.figure()
plt.show()
def onclick(event):
print('%s click: button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
('double' if event.dblclick else 'single', event.button,
event.x, event.y, event.xdata, event.ydata))
line.set_ydata(event.ydata)
#plt.draw()
cid = fig.canvas.mpl_connect('button_press_event', onclick)
I created the following histogram from the frequeny of each class in a training set
The label of each class is too long and is similar to
Speed limit (20km/h)
Can I place each label on the bar itself?
Maybe something like this?
import numpy as np
import matplotlib.pyplot as plt
N=5
xlabel = ["Speed limit ("+str(i)+"km/h)" for i in range(0,N)]
xs = np.arange(0,7,1.5)
ys = [8,6,10,7,9]
width = 0.3*np.ones(N)
fig, ax = plt.subplots()
bars = ax.bar(xs, ys, width, color='k',alpha=0.3)
plt.xticks(xs, xlabel,rotation=270)
for i,bar in enumerate(bars):
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2., 0.1*height,
'%s' % xlabel[i],rotation=90,ha='center', va='bottom')
plt.show()
To change it to horizontal bar plot:
import numpy as np
import matplotlib.pyplot as plt
N = 5
xlabel = ["Speed limit ("+str(i)+"km/h)" for i in range(0,5)]
xs = np.arange(0,5)/2
ys = [8,6,10,7,9]
width = 0.3*np.ones(N)
fig, ax = plt.subplots()
bars = ax.barh(xs, ys, width, color='k',alpha=0.3)
plt.xticks([])
for i,bar in enumerate(bars):
height = bar.get_height()
ax.text(bar.get_x()+3, bar.get_y()+bar.get_height()/3,
'%s' % xlabel[i],rotation=0,ha='center', va='bottom')
plt.tight_layout()
plt.show()
I have a problem with PolyCollection matplotlib when I work with python 2.5. In random mode, it shows me following error: array dimensions must agree except for d_0 (file:collection.py - xy = np.concatenate([xy, np.zeros((1,2))])). This is my code:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.collections import PolyCollection
from matplotlib.colors import colorConverter
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.font_manager as fm
from matplotlib.patches import Rectangle
import matplotlib.cm as cm
colors = ['#be1e2d',
'#666699',
'#92d5ea',
'#ee8310',
'#8d10ee',
'#5a3b16',
'#26a4ed',
'#f45a90',
'#e9e744']
row_names = ['2005','2006','2007']
data = [[1,1,1,1,1,1],[2,2,2,2,2,2],[4,4,4,4,4,4],[5,5,5,5,5,5],[7,7,7,7,7,7],[8,8,8,8,8,8]]
column_names = ['Ri','Pe']
#0 to start and end list
i=0
for i in range(len(data)):
data[i].append(0)
for i in range(len(data)):
data[i].insert(0,0)
dpi = 50.0
width = 460
height = 440
fig = plt.figure(1, figsize=(width/dpi,height/dpi),facecolor='w')
ax = fig.gca(projection='3d')#,azim=40, elev=0)
#Build axes
size = len(row_names) * len(data[0])
zs = np.arange(len(data))
# Setto le properties dei font
fp = fm.FontProperties()
fp.set_size('xx-small')
#Build Graph
verts = []
step = 1.0/len(data[0])
vertsColor = []
#Verify Single series or not
if len(column_names) > 1:
idx = 0
xs = np.arange(0, size, step)
change_color = len(column_names) - 1
for z in zs:
verts.append(zip(xs, data[z]))
vertsColor.append(colors[idx])
if idx == change_color:
idx = 0
else:
idx = idx + 1
################################################
# I THINK THE PROBLEM IS HERE
poly = PolyCollection(verts,facecolors=vertsColor)
ax.add_collection3d(poly, zs=zs, zdir='y')
################################################
ax.set_ylim3d(0, len(row_names)*len(column_names))
zs = np.arange(0,len(row_names) * len(column_names), len(column_names))
ax.set_yticks(zs)
lim = ((size*step)-step) - (len(row_names) - 1)
ax.set_xlim3d(0, lim)
rect = []
serie = []
#Build legend
for i in range(len(column_names)):
rect.insert(i,Rectangle((0,0), 1,1, facecolor=colors[i]))
serie.insert(i,column_names[i])
ax.legend((rect), (serie), loc=3, ncol=3, prop=fp)
else:
xs = np.arange(0, size, step)
for z in zs:
verts.append(zip(xs, data[z]))
poly = PolyCollection(verts,facecolors=colors) #[:len(data)])
poly.set_alpha(0.6)
ax.add_collection3d(poly, zs=zs, zdir='y')
ax.set_xlabel('Rec')
lim = ((size*step)-step) - (len(row_names) - 1)
ax.set_xlim3d(0, lim)
ax.set_yticks(zs)
ax.set_ylim3d(0, len(row_names))
#Find Max Value
max_value = 0
i=0
for i in data:
mass = max(i)
if mass > max_value:
max_value = mass
#Font Label X,Y,Z
for label in ax.get_xticklabels():
label.set_fontproperties(fp)
for label in ax.get_yticklabels():
label.set_fontproperties(fp)
for label in ax.get_zticklabels():
label.set_fontproperties(fp)
ax.set_xticklabels('')
ax.set_ylabel('Years')
ax.set_yticklabels(row_names, fontproperties = fp)
ax.set_zlabel('Values')
ax.set_zlim3d(0, max_value)
ax.set_title('Test',x=0.5, y=1)
plt.show()
THANKS.