matplotlib-axis-with-two-scales-shared-origin - python

Matplotlib axis with two scales shared origin
I have already tried to implement this the existing stackflow solution and my both x-axes are not aligning to 0.
My Code :
def align_xaxis(ax1, v1, ax2, v2):
"""adjust ax2 xlimit so that v2 in ax2 is aligned to v1 in ax1"""
x1, _ = ax1.transData.transform((v1, 0))
x2, _ = ax2.transData.transform((v2, 0))
inv = ax2.transData.inverted()
dx, _ = inv.transform((0, 0)) - inv.transform((x1-x2, 0))
minx, maxx = ax1.get_xlim()
ax2.set_xlim(minx+dx, maxx+dx)
def unrealized_profit_loss_graph(profit_loss):
plt.style.use('ggplot');
fig = plt.figure()
ax1 = fig.add_subplot(111);
ax2 = ax1.twiny()
profit_loss['total_G/l'].
plot(kind='barh',color=profit_loss.positive.map({True: 'g', False: 'r'}))
profit_loss['gain_loss_perc'].plot(kind='barh',color=profit_loss.positive.map({True: 'b', False: 'y'}))
ax1.set_xlabel('%', fontsize=12)
ax2.set_xlabel('$', fontsize=12);
align_xaxis(ax1,0,ax2,0)
plt.xlim(-5000, 20000)
plt.xticks(rotation=45);
plt.show();
I would like both x axes to align at 0.
Also to show the negative plus the positive of the ax1.
Working example :
def unrealized_profit_loss():
Profit_loss = Path("C:/Users/champ/Documents/Pers/Python/stock_dfs/Profit_loss_tranactions.xlsx")
df = pd.read_excel(Profit_loss, sheet_name='Unrealized')
current_prices_ROTH=price_data_ROTH.loc[price_data_ROTH.index[-1]] current_prices_Personal=price_data_Personal.loc[price_data_Personal.index[-1]]
df2 = pd.DataFrame({'Symbol':current_prices_ROTH.index, 'Prices':current_prices_ROTH.values})
df2 = pd.DataFrame({'Symbol':current_prices_Personal.index, 'Prices':current_prices_Personal.values})
da= pd.merge(df,df2, how='left',on=['Symbol','Symbol'])
da['gain_loss_perc']=round(((da['Prices']-da['Cost/share'])/da['Cost/share'])*100,2)
da['total_G/l']=round((da['Prices']*da['Quantity'])-(da['Cost Basis']),0)
da['Account_symbol'] = str(da['Account'])
da['Account_symbol'] = da.agg(lambda x: f"{x['Symbol']} - {x['Account']}", axis=1)
da = da.sort_values(by=['total_G/l'],ascending=True)
da.index = da['Account_symbol']
da['positive'] = da['total_G/l'] > 0
del da.index.name
return(da)
def unrealized_profit_loss_graph(profit_loss):
# graph the profit and loss
#fig, (ax1,ax2) = plt.subplots(1,2,sharex=False,sharey=True,figsize=(16,8));
#fig, ax1 = plt.subplots(1,1,figsize=(16,8));
plt.style.use('ggplot');
fig = plt.figure()
ax1 = fig.add_subplot(111);
ax1.set_title('Total G/L (UNREALIZED - IN THE MARKET)');
#ax1 = fig.add_subplot() # Create matplotlib axes
ax2 = ax1.twiny()
profit_loss['total_G/l'].plot(kind='barh',color=profit_loss.positive.map({True: 'g', False: 'r'}))
profit_loss['gain_loss_perc'].plot(kind='barh',color=profit_loss.positive.map({True: 'b', False: 'y'}))
ax1.set_xlabel('%', fontsize=12);
ax2.set_xlabel('$', fontsize=12);
plt.xlim(-5000, 20000);
plt.xticks(rotation=45);
align_xaxis(ax1,0,ax2,0);
plt.show();
# Profit and loss
profit_loss = unrealized_profit_loss()
p_l = unrealized_profit_loss_graph(profit_loss)
xls file I read from

You failed to provide a working example. Nevertheless, try the following: Pass the respective axis to the plot function and then try aligning
def unrealized_profit_loss_graph(profit_loss):
plt.style.use('ggplot')
fig = plt.figure()
ax1 = fig.add_subplot(111)
profit_loss['total_G/l'].plot(kind='barh',
color=profit_loss.positive.map({True: 'g', False: 'r'}),
ax=ax1)
ax2 = ax1.twiny()
profit_loss['gain_loss_perc'].plot(kind='barh',
color=profit_loss.positive.map({True: 'b', False: 'y'}),
ax=ax2)
ax1.set_xlabel('%', fontsize=12)
ax2.set_xlabel('$', fontsize=12)
plt.xlim(-5000, 20000)
plt.xticks(rotation=45)
align_xaxis(ax1,0,ax2,0)
plt.show();

Related

Plot multiple lines in a loop

I try to plot lines in a loop,but its connecting it,i tried many variants,but cand understand and find the answer,maybe the dataframe
im a newbie in Matplotlib
the code of method:
self.testnewnewventnest[Debit] - is a nested dict with the data i need for plotting
def showmainplot(self):
for Debit in self.Debitlist:
self.Presinit = self.VentTable.loc[Debit]
self.Tinit= float(self.Tinit)
self.Presinit=int(float(self.Presinit))
self.Powinit = float(self.Powinit)
x = symbols("x")
for Turatie in self.Tfin:
eqPres = (Turatie/self.Tinit)*(Turatie/self.Tinit)*self.Presinit-x
PresFin = solve(eqPres)
eqDebit = (Turatie/self.Tinit)*int(Debit)
DebitFin = solve(eqDebit)
eqPow = (Turatie/self.Tinit)*(Turatie/self.Tinit)*(Turatie/self.Tinit)*float(self.Powinit)
self.TestnewVentnest['KW'] = float(eqPow)
self.TestnewVentnest['Turatie'] = Turatie
self.TestnewVentnest['Presiune'] = float(PresFin[0])
self.TestnewVent[float(eqDebit)] = dict(self.TestnewVentnest)
self.testnewnewventnest[Debit] = dict(self.TestnewVent)
print(self.testnewnewventnest)
axeslist = []
n=0
fig, ax = plt.subplots(figsize=(5, 5))
ax1 = ax.twinx()
ax1.spines.right.set_position(("axes", 1.06))
ax.set_xlabel("Debit")
for dicts in self.testnewnewventnest:
Ventdataframe = pd.DataFrame(self.testnewnewventnest[dicts])
print(Ventdataframe)
ax2 = plt.subplot()
fig, ax = plt.subplots(figsize=(5, 5))
ax1 = ax.twinx()
ax1.spines.right.set_position(("axes", 1.06))
ax.set_xlabel("Debit")
axeslist.append(plt.subplot())
# print(df.iloc[0])
# ax1.set_ylabel("Turatie")
# ax.set_ylabel("Presiune")
# Ventdataframe.plot(Ventdataframe.loc["Presiune"], color="b",label="Presiune"+str(n),marker = 'o')
Ventdataframe.loc["Presiune"].plot(color="b",label="Presiune"+str(n),marker = 'o')
n+=1
# ax2 = ax.twinx()
# ax2.set_ylabel('KW')
# ax1.plot(Ventdataframe.loc["Turatie"],color='#000000',label="Turatie",marker = 'o')
# ax2.plot(Ventdataframe.loc["KW"], color='r',label="KW",marker = 'o')
# ax1.grid()
# ax2.yaxis.set_major_locator(FixedLocator(Ventdataframe.loc["KW"]))
# ax.yaxis.set_major_locator(FixedLocator(Ventdataframe.loc["Presiune"]))
# ax1.yaxis.set_major_locator(FixedLocator(self.Tfin))
# ax.xaxis.set_major_locator(FixedLocator(Ventdataframe.columns))
# lc = matpl.ticker.NullLocator()
# ax.yaxis.set_major_locator(lc)
plt.show()
and the self.testnewnewventnest look like:
Yes,the problem was in the loop,and in the dictionaries,in every iteration he added all previous dictionaries from iterations
I would put that in a dataframe and do it like this.
uniques = df['ID'].unique()
for i in uniques:
fig, ax = plt.subplots()
fig.set_size_inches(4,3)
df_single = df[df['ID']==i]
sns.lineplot(data=df_single, x='Month', y='Expense')
ax.set(xlabel='Time', ylabel='Total Expense')
plt.xticks(rotation=45)
plt.show()

Matpolitlib Stacked Barchart - Adding Labels for the Total Value on each of my bars [duplicate]

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'])

overlay interaction visual in python

I want to visualize the interactions between two data's. Original (green) and prediction (brown). The length of the top line is from 200 to -20 and bottom from -20 to 200.
For the above table, I want to visualize in the below format
code I have tried so far
def newline(p1, p2, color='black'):
ax = plt.gca()
fig, ax = plt.subplots(1,1,figsize=(5,5), dpi= 60)
ax.hlines(y=1, xmin=-20, xmax=200, color='black', alpha=0.7)
ax.hlines(y=1.1, xmin=-20, xmax=200, color='black', alpha=0.7)
plt.rcParams['xtick.bottom'] = plt.rcParams['xtick.labelbottom'] = True
plt.rcParams['xtick.top'] = plt.rcParams['xtick.labeltop'] = True
ax.yaxis.set_visible(False)
plt.box(False)
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
def newline(p1, p2, color='black'):
ax = plt.gca()
df = pd.read_excel('visual.xlsx', sheet_name='Sheet2')
prediction_list = df['prediction'].tolist()
originale_list = df['original'].tolist()
result_prediction = []
result_original = []
for i in range(len(prediction_list)):
temp = []
test = prediction_list[i].split('&')
for j in range(len(test)):
temp = []
temp.append(200 - int(test[j].split(':')[0]))
temp.append(int(test[j].split(':')[1]))
result_prediction.append(temp)
for i in range(len(originale_list)):
temp = []
test = originale_list[i].split('&')
for j in range(len(test)):
temp = []
temp.append(200 - int(test[j].split(':')[0]))
temp.append(int(test[j].split(':')[1]))
result_original.append(temp)
fig, ax = plt.subplots(1,1,figsize=(20,5), dpi= 60)
ax.hlines(y=1, xmin=200, xmax=-20, color='black', alpha=0.7)
ax.hlines(y=2, xmin=200, xmax=-20, color='black', alpha=0.7) -20')
for i in range(len(result_prediction)):
plt.plot(result_prediction[i], [2, 1], color='brown')
for i in range(len(result_original)):
plt.plot(result_original[i], [2, 1], color='green')
plt.rcParams['xtick.bottom'] = plt.rcParams['xtick.labelbottom'] = True
plt.rcParams['xtick.top'] = plt.rcParams['xtick.labeltop'] = True
ax.yaxis.set_visible(False)
plt.box(False)
plt.savefig('test.png')
plt.show()
That will be help you.
Thanks

matplotlib text is not on top of patches even with a higher zorder

I've plotted data for females on one axes, and males on another axes. Each plot was made with zorder=0, but with position=1 and position=2 respectively. I label the bars with text with zorder=1, but as you can see, the bars overlap the text. Is it because they are on separate axes? In which case, how can I have text in one axes be higher than the highest zorder in another axes?
def get_ages():
df = pd.read_csv('surveydata.csv', low_memory=False)
fems = df.loc[df['gender'] == 1]
males = df.loc[df['gender'] == 2]
fdata = fems['age'].value_counts()
mdata = males['age'].value_counts()
fdata.sort_index(inplace=True)
mdata.sort_index(inplace=True)
print(fdata)
print(mdata)
fdata2 = fdata[0:14]
mdata2 = mdata[0:14]
fdata2['>31'] = sum(fdata[14:])
mdata2['>31'] = sum(mdata[14:])
fig = plt.figure() # Create matplotlib figure
ax = fig.add_subplot(111) # Create matplotlib axes
ax2 = ax.twinx() # Create another axes that shares the same x-axis as ax.
fdata2.plot(kind='bar', figsize=(10, 5.7), width=.4, color='pink', position=0, ax=ax,zorder=0)
mdata2.plot(kind='bar', figsize=(10, 5.7), width=.4, color='lightskyblue', position=1, ax=ax2, zorder=0)
ax.set_title("Ages", fontsize=18)
ax.set_ylabel("Occurrence", fontsize=18)
ax.set_facecolor('snow')
ax.set_xlim(ax.patches[0].get_x() - 1, ax.patches[-1].get_x() + 1)
ax2.set_yticks([])
totals = []
for i in ax.patches:
totals.append(i.get_height())
total = sum(totals)
for i in ax.patches:
ax.text(i.get_x() , i.get_height() + .5,
str(round((i.get_height() / total) * 100, 2)) + '%', fontsize=8,
color='black', horizontalalignment='left', zorder=9)
totals = []
for i in ax2.patches:
totals.append(i.get_height())
total = sum(totals)
for i in ax2.patches:
t = ax2.text(i.get_x()+ i.get_width(), i.get_height() + .5,
str(round((i.get_height() / total) * 100, 1)) + '%', fontsize=8,
color='black', horizontalalignment='right', zorder=10)
for x in ax.texts: #Shifts text up and down in case they overlap.
bb2 = x.get_window_extent(ax.get_figure().canvas.get_renderer())
bb = t.get_window_extent(ax.get_figure().canvas.get_renderer())
while bb2.overlaps(bb):
t.set_y(a._y - .01)
bb2 = x.get_window_extent(ax.get_figure().canvas.get_renderer())
bb = t.get_window_extent(ax.get_figure().canvas.get_renderer())

If function for annotating from pandas

I'm scatter plotting values from pandas dataframe. I would like to annotate points only if the value is greater than 100. I have no idea how to go about it.
Here's the code I'm working with (it's terrible but I'm very new to this):
female_data = r'/home/jg/Desktop/hurricanedata_f.csv'
female_df = read_csv(female_data)
male_data = r'/home/jg/Desktop/hurricanedata_m.csv'
male_df = read_csv(male_data)
x = female_df['Year']
y = female_df['alldeaths']
z = female_df['Name']
y_mean = [np.mean(y) for i in x]
a = male_df['Year']
b = male_df['alldeaths']
b_mean = [np.mean(b) for i in b]
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.annotate('Agnes', xy=(1972,117))
ax1 = fig.add_subplot(1,1,1)
ax1.scatter(x,y, label = 'female', color = 'r')
ax2 = fig.add_subplot(1,1,1)
ax2.scatter(a,b, label = 'male')
ax3 = fig.add_subplot(1,1,1)
ax3.plot(x, y_mean, linestyle='--', color = 'r')
ax4 = fig.add_subplot(1,1,1)
ax4.plot(a, b_mean, linestyle='--', color = 'blue')
plt.title('Hurricanes')
plt.xlabel('Year')
plt.ylabel('Deaths')
plt.legend(loc='upper right')
plt.ylim([-5,300])
plt.xlim([1948,2020])
plt.show()
You can loop over all your data points and check if each is greater than 100. Then give those points an annotation.
import matplotlib.pyplot as plt
import numpy as np
import string
# Fake data
x = np.arange(10)
y = 10*np.random.rand(10) + 95
names = string.lowercase[:10] # first 10 lowercase letters
# Plot data
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.scatter(x,y)
# Annonate points with y values greater than 100
for xi, yi, iname in zip(x,y,names): # Loop over x and y values
if yi > 100: # Check if y is greater than 100
ax.annotate(iname, (xi, yi),size = 30) # Add an annoatation.
plt.show()

Categories