diff = [[10,20,30],[40,50,60],[70,80,90]]
comp = ["foo","bar","baz"]
fig,ax = plt.subplots()
for foo in range(0, len(diff)):
x = [diff[foo]]
name = comp
color = ['0.1', '0.2', '0.3']
label = ['1000000','1200000', '1400000']
y = zip(*x)
pos = np.arange(len(x))
width = 1. / (1 + len(x))
fig = plt.subplot(3,1,foo)
for idx, (serie, color,label) in enumerate(zip(y, color,label)):
ax.bar(pos + idx * width, serie, width, color=color,label=label)
fig = plt.gcf()
fig.set_size_inches(28.5,10.5)
ax.set_xticks(pos + 1.5*width)
plt.ylabel(name[foo])
ax.set_xticklabels(comp)
ax.legend()
plt.gray()
plt.savefig("file" + '.jpg', bbox_inches='tight', pad_inches=0.5,dpi=100)
plt.clf()
I want to subplot foo bar and baz. But when I try to do that using the above code. The data is not being displayed on the graph. Any idea why?
You are replacing the first fig when you call subplot inside the loop, here is a fixed version. See that ax returned by subplots is a np.ndarray, so you have to give an index ax[foo] to obtain the AxesSubplot object.
diff = [[10, 20, 30], [40, 50, 60], [70, 80, 90]]
comp = ["foo", "bar", "baz"]
fig, ax = plt.subplots(3, 1)
for foo in range(0, len(diff)):
x = [diff[foo]]
name = comp
color = ['0.1', '0.2', '0.3']
label = ['1000000', '1200000', '1400000']
y = zip(*x)
pos = np.arange(len(x))
width = 1. / (1 + len(x))
for idx, (serie, color,label) in enumerate(zip(y, color,label)):
ax[foo].bar(pos + idx * width, serie, width, color=color,label=label)
fig.set_size_inches(28.5, 10.5)
ax[foo].set_xticks(pos + 1.5*width)
plt.ylabel(name[foo])
ax[foo].set_xticklabels(comp)
ax[foo].legend()
plt.gray()
fig.savefig("file" + '.jpg', bbox_inches='tight', pad_inches=0.5, dpi=100)
plt.clf()
Related
So I have this plot here:
What I want to do is to have every second element of yaxis to be coloured for example in blue and the rest in red.
Here is the result I want to get:
and here is the code I got:
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
mpl.rcParams['toolbar'] = 'None'
plt.style.use('fivethirtyeight')
result_7_s = amount * s_7_days
result_14_s = amount * s_14_days
result_21_s = amount * s_21_days
result_7_fc = amount * fc_7_days
result_14_fc = amount * fc_14_days
result_21_fc = amount * fc_21_days
final_y = np.array([int(result_7_s), int(result_14_s),
int(result_21_s), int(result_7_fc),
int(result_14_fc), int(result_21_fc)])
fig, ax = plt.subplots(num = 'Test')
x = np.array([7, 14, 21])
plt.xticks(ticks = x, labels = x)
plt.yticks(ticks = final_y, labels = final_y)
plt.title(f'Prices for {amount} people')
plt.xlabel('Days')
plt.ylabel('Price')
plt.tight_layout()
ax.bar(x - 0.5, final_y[:3], width=1, color='#444444', label='Standard')
ax.bar(x + 0.5, final_y[3:], width=1, color='#e5ae38', label='First Class')
ax.tick_params(axis='y', colors = 'blue') # <-------
ax.yaxis.set_major_formatter('{x}$')
plt.legend()
plt.savefig('result.png')
plt.show()
Iterate over the tick labels to apply the desired color to each one of them:
for n, tick_label in enumerate(ax.yaxis.get_ticklabels()):
tick_label.set_color("red" if n%2 else "blue")
Here is the solution I came with:
for i in range(0, 3):
plt.gca().get_yticklabels()[i].set_color('blue')
for i in range(3, 6):
plt.gca().get_yticklabels()[i].set_color('red')
I am working on an energy balance and I am currently creating a barplot. I want to compare the generation and consumption of electricity over the years. Therefore I have 2 stacked bars for each year. This is how far I got:
import matplotlib.pyplot as plt
import numpy as np
generation_2020 = [20, 30, 40, 20, 10]
consumption_2020 = [50,50]
import_2020 = 20
if import_2020 >0:
generation_2020 = np.append(generation_2020, import_2020)
else:
consumption_2020 = np.insert(consumption_2020, 0, import_2020*-1, axis=0)
generation_2025 = np.array([20, 20, 20, 20, 10])
consumption_2025 = np.array([50,50])
import_2025 = -10
if import_2025 >0:
generation_2025 = np.append(generation_2025, import_2025)
else:
consumption_2025 = np.insert(consumption_2025, 0, import_2025*-1, axis=0)
data = np.array([generation_2020, generation_2025])
data2 = np.array([consumption_2020, consumption_2025])
label_data = ['renewables','gas','cole', 'storage', 'nuclear', 'import', 'consumption', 'storage']
x2 = ['2020', '2025']
x3 = ['Erzeugung' , '\n\n\n\n\n\n2020', 'Verbrauch', 'Erzeugung' , '\n\n\n\n\n\n2025', 'Verbrauch']
x_pos = np.arange(len(x2))
width = 0.2
x = list()
for i in x_pos:
x.extend([i-width, i, i+width])
fig, ax = plt.subplots()
for i in range(data.shape[1]):
bottom = np.sum(data[:, 0:i], axis=1)
ax.bar(x_pos - width, data[:, i], bottom=bottom, width=width, label=f"label {i}")
for i in range(data2.shape[1]):
bottom = np.sum(data2[:, 0:i], axis=1)
ax.bar(x_pos+ width, data2[:, i], bottom=bottom, width=width, label=f"label {i}")
ax.set_ylabel('[TWh]')
ax.set_xticks(x)
ax.set_xticklabels(x3)
ax.tick_params(axis='x', which='both',length=0, labelsize = 10)
for label in ax.get_xmajorticklabels():
if 'u' in label.get_text(): label.set_rotation(90)
ax.margins(y=0.1) # some extra padding to place the bar labels
plt.legend(label_data, bbox_to_anchor=(1, 1))
fig.tight_layout()
plt.show()
This works if both import_2020 and import_2025 are either both negative or both positive. If one is negative and the other is positive it doesnt.
This is the error message I get:
for i in range(data.shape[1]):
IndexError: tuple index out of range
The problem is that generation_2020 and generation_2025 dont have the same length. One has 5 entries and the other 6. Does someone have an Idea how to solve this?
I have a grouped bar chart and each bar is stacked.
I have annotated each section of the stack with its individual value and now I would like to sum those values and annotate the total value(height) of each bar. I would like this annotation to be on top of each bar.
This is one of the two dataframes I am working from:
df_title = pd.DataFrame(index=['F','M'],
data={'<10':[2.064897, 1.573255], '10-12':[3.933137, 4.326450], '13-17':[9.242871, 16.715831],
'18-24':[10.226155, 12.487709], '18-24':[8.161259, 10.717797], '35-44':[5.801377, 4.916421],
'45-54':[3.539823, 2.851524], '55+':[1.671583, 1.769912]})
I convert both dataframes (df_title and df_comps) into numpy arrays before plotting.
df_title_concat = np.concatenate((np.zeros((len,1)), df_title.T.values), axis=1)
Here is the full code:
df_title
df_comps
len = df_title.shape[1]
df_title_concat = np.concatenate((np.zeros((len,1)), df_title.T.values), axis=1)
df_comps_concat = np.concatenate((np.zeros((len,1)), df_comps.T.values), axis=1)
fig = plt.figure(figsize=(20,10))
ax = plt.subplot()
title_colors = ['skyblue', 'royalblue']
comps_colors = ['lightgoldenrodyellow', 'orange']
for i in range(1,3):
for j in list(range(0, df_title.shape[1]-1)):
j += 1
ax_1 = ax.bar(j, df_title_concat[j,i], width=-0.4, bottom=np.sum(df_title_concat[j,:i]), color = title_colors[i-1],
edgecolor='black', linewidth=3, align='edge')
for p in ax_1.patches:
width, height = p.get_width(), p.get_height()
x, y = p.get_xy()
if height > 2:
ax.annotate('{:.2f}%'.format(height), (p.get_x()+0.875*width, p.get_y()+.4*height),
fontsize=16, fontweight='bold', color='black')
ax_2 = ax.bar(j, df_comps_concat[j,i], width=0.4, bottom=np.sum(df_comps_concat[j,:i]), color = comps_colors[i-1],
edgecolor='black', linewidth=3, align='edge')
for p in ax_2.patches:
width, height = p.get_width(), p.get_height()
x, y = p.get_xy()
if height > 2:
ax.annotate('{:.2f}%'.format(height), (p.get_x()+0.15*width, p.get_y()+.4*height),
fontsize=16, fontweight='bold', color='black')
Here is a solution:
df_title = pd.DataFrame(index=['F','M'],
data={'<10':[2.064897, 1.573255], '10-12':[3.933137, 4.326450], '13-17':[9.242871, 16.715831],
'18-24':[10.226155, 12.487709], '18-24':[8.161259, 10.717797], '35-44':[5.801377, 4.916421],
'45-54':[3.539823, 2.851524], '55+':[1.671583, 1.769912]})
df_title_concat = np.concatenate((np.zeros((len(df_title),1)), df_title.T.values), axis=1)
fig = plt.figure(figsize=(12,8))
ax = plt.subplot()
title_colors = ['skyblue', 'royalblue']
for i in range(1,3):
for j in list(range(0, df_title.shape[1]-1)):
j += 1
bottom=np.sum(df_title_concat[j,:i])
ax_1 = ax.bar(j, df_title_concat[j,i], width=-0.4, bottom=bottom, color = title_colors[i-1],
edgecolor='black', linewidth=3, align='edge')
for p in ax_1.patches:
width, height = p.get_width(), p.get_height()
if bottom != 0:
ax.annotate('{:.2f}%'.format(height+bottom), (p.get_x()+0.875*width, (height+bottom)+0.3),
fontsize=16, fontweight='bold', color='black')
However, I would suggest you to rethink the whole approach you are following and change the plot to something like:
plt.bar(df_title.columns,df_title.loc['M'])
plt.bar(df_title.columns,df_title.loc['F'],bottom=df_title.loc['M'])
I get different plots for each value that I wrote in for loop's upper range as I expected. But I would like to animate the plot from range (0,0) an goes to (0,15) as the upper limit changes 1 by 1, by using matplotlib animation function animation.FuncAnimation(). So there will be 16 frames total in the animation. I messed up with the animation part, so I'm pasting the code that gives 1 plot output. Thanks in advance!
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
g = 1.0
def distance(x1,y1,x2,y2):
r = np.sqrt((x2-x1)**2+(y2-y1)**2)
return r
def gravit(m1,m2,r):
f = g*m1*m2/(r**2)
return f
def angle(y2, y1, x2, x1):
ydif = y1-y2
xdif = x1-x2
angle = np.arctan2(ydif,xdif)
return angle
m1 = 100
x1, y1 = 0,0
m2 = 1
x2, y2 = -15,-10
vx1 = 1
vy1 = 0
ax1 = 0
ay1 = 0
vx2 = 2
vy2 = 3.9
ax2 = 0
ay2 = 0
x1coor = [x1]
y1coor = [y1]
x2coor = [x2]
y2coor = [y2]
for t in range(0,10): #This value of 10 should be change from 0 to 15 in the animation
r = distance(x1,y1,x2,y2)
fx1 = gravit(m1, m2, r) * np.cos(angle(y2,y1,x2,x1))
fy1 = gravit(m1, m2, r) * np.sin(angle(y2,y1,x2,x1))
ax2 = fx1/m2
vx2 = vx2 + ax2
ay2 = fy1/m2
vy2 = vy2 + ay2
x2 = x2 + vx2 + 0.5*ax2
y2 = y2 + vy2 + 0.5*ay2
x1 = x1 + vx1 + 0.5*ax1
y1 = y1 + vy1 + 0.5*ay1
x1coor.append(x1)
y1coor.append(y1)
x2coor.append(x2)
y2coor.append(y2)
plt.axes().set_aspect('equal')
plt.axis([-30,30,-30,30])
plt.plot(x1coor,y1coor, '-.', color='blue')
plt.plot(x2coor,y2coor, '-.', color='black')
plt.scatter(x1,y1,s=m1*20, color='blue')
plt.scatter(x2,y2,s=m2*20, color='red')
The FuncAnimation function of matplotlib's animation module requires a figure and a function to draw each frame, so first initialize your figure following :
fig = plt.figure()
ax1 = fig.add_subplot(1, 1, 1)
ax1.set_aspect("equal")
ax1.set_xlim(-30, 30)
ax1.set_ylim(-30, 30)
l1, = ax1.plot([], [], linestyle = "-.", color = "blue")
l2, = ax1.plot([], [], '-.', color = "black")
s1, = ax1.plot([], [], linestyle = None, marker = "o", markersize = 5, color = "blue")
s2, = ax1.plot([], [], linestyle = None, marker = "o", markersize = 5, color = "red")
Note that the different line plots contain no input data and are saved in the variables l1, l2, s1 and s2.
Now define the function that will be called to draw each frame. The first argument is always the frame number. This function should return all the plot objects that are updated using their methods 'set_data':
def update_fig(i, x1coor, y1coor, x2coor, y2coor):
l1.set_data(x1coor[:i+1], y1coor[:i+1])
l2.set_data(x2coor[:i+1], y2coor[:i+1])
s1.set_data(x1coor[i], y1coor[i])
s2.set_data(x2coor[i], y2coor[i])
return l1, l2, s1, s2,
You can now run your animation (note that 'update_fig' arguments, except 'i', are passed to the function using the keyword 'fargs'):
ani = animation.FuncAnimation(fig, update_fig,
frames = len(x1coor),
fargs = (x1coor, y1coor, x2coor, y2coor),
interval = 100,
repeat = True,
)
I finally forced the 3 plots I want into one plot with 3 subplots...now I need to add a common colorbar, preferably horizontally oriented. Also, now that I have them as subplots, I have lost the labels that were there in a previous iteration.
It seems that the examples suggest I add an axes, but I don't quite get what the numbers in the arguments are.
def plot_that_2(x_vals, y_vals, z_1_vals, z_2_vals, z_3_vals, figname, units, efficiency_or_not):
global letter_pic_width
plt.close() #I moved this up from the end of the file because it solved my QTagg problem
UI = [uniformity_calc(z_1_vals), uniformity_calc(z_2_vals), uniformity_calc(z_3_vals)]
ranges = [ str(int(np.max(z_1_vals) - np.min(z_1_vals))), str(int(np.max(z_2_vals) - np.min(z_2_vals))), str(int(np.max(z_3_vals) - np.min(z_3_vals)))]
z_vals = [z_1_vals, z_2_vals, z_3_vals]
fig = plt.figure(figsize = (letter_pic_width, letter_pic_width/3 ))
ax0 = fig.add_subplot(1,3,1, aspect = 1)
ax1 = fig.add_subplot(1,3,2, aspect = 1)
ax2 = fig.add_subplot(1,3,3, aspect = 1)
axenames = [ax0, ax1, ax2]
for z_val, unif, rangenum, ax in zip(z_vals, UI, ranges, axenames):
ax.scatter(x_vals, y_vals, c = z_val, s = 100, cmap = 'rainbow')
if efficiency_or_not:
ax.vmin = 0
ax.vmax = 1
ax.xlabel = 'Uniformity: ' + unif
else:
ax.xlabel = 'Uniformity: ' + unif + ' ' + rangenum + ' ppm'
plt.savefig('./'+ figname + '.jpg', dpi = 100)
To set the xlabel, use ax.set_xlabel('Uniformity: ' + unif) See more information here in the documentation for axes.
The example you linked to uses the add_axes method of a figure as an alternative to add_subplot. The documentation for figures explains what the numbers in add_axes are: "Add an axes at position rect [left, bottom, width, height] where all quantities are in fractions of figure width and height."
rect = l,b,w,h
fig.add_axes(rect)
To answer your question about the colorbar axis, the numbers represent
[bottom_left_x_coord, bottom_left_y_coord, width, height]
An appropriate colorbar might be
# x y w h
[0.2, 0.1, 0.6, 0.05]
Here's your code, somewhat reworked which adds a colorbar:
import numpy as np
import matplotlib.pyplot as plt
WIDTH = 9
def uniformity_calc(x):
return x.mean()
def plotter(x, y, zs, name, units, efficiency=True):
fig, axarr = plt.subplots(1, 3, figsize=(WIDTH, WIDTH/3),
subplot_kw={'aspect':1})
fig.suptitle(name)
UI = map(uniformity_calc, zs)
ranges = map(lambda x: int(np.max(x)-np.min(x)), zs)
for ax, z, unif, rangenum in zip(axarr, zs, UI, ranges):
scat = ax.scatter(x, y, c=z, s=100, cmap='rainbow')
label = 'Uniformity: %i'%unif
if not efficiency:
label += ' %i ppm'%rangenum
ax.set_xlabel(label)
# Colorbar [left, bottom, width, height
cax = fig.add_axes([0.2, 0.1, 0.6, 0.05])
cbar = fig.colorbar(scat, cax, orientation='horizontal')
cbar.set_label('This is a colorbar')
plt.show()
def main():
x, y = np.meshgrid(np.arange(10), np.arange(10))
zs = [np.random.rand(*y.shape) for _ in range(3)]
plotter(x.flatten(), y.flatten(), zs, 'name', None)
if __name__ == "__main__":
main()