3
\$\begingroup\$

I want to improve my code. Is it possible to get the plot without repeating the same instructions multiple lines?

The data comes from a Pandas' dataframe, but I am only plotting the last column (Total Acc.)

enter image description here

enter image description here

e=df['Total Acc'].round(4)*100

#The repetitions start:
row_awa = e.loc['AWA'] 
row_rem = e.loc['REM']
row_s1 = e.loc['S1'] 
row_s2 = e.loc['S2'] 
row_sws = e.loc['SWS'] 
row_stades = e.loc['stades'] 

#More repetitions
row_awa.plot()
row_rem.plot()
row_s1.plot()
row_s2.plot()
row_sws.plot()
row_stades.plot()


myLegend=plt.legend(bbox_to_anchor=(0., 1.2, 1., .102), prop ={'size':10}, loc=10, ncol=4,  #left, bottom, width, height
            title=r'TOTAL ACCURACY FOR MANY K-FOLD')                    #loc='center'
myLegend.get_title().set_fontsize('20')
\$\endgroup\$
3
\$\begingroup\$

To reduce the repetitions you could make use of lists by doing something like:

labels = ['AWA', 'REM', 'S1', 'S2', 'SWS', 'stades']

rows = [] 
for label in labels:
    rows.append(e.loc[label]) 

# or even shorter with list comprehension 
rows = [e.loc[label] for label in labels]

for row in rows:
    row.plot()

Edit: The labels list can also be used as first argument of the legend function to show the correct labels.

\$\endgroup\$
  • \$\begingroup\$ Only Option 2 works. But that is fine. Also, how can I add the labels in the legend? So that instead of "Total Acc" I get the correct labels? \$\endgroup\$ – Aizzaac Oct 17 '16 at 19:31
  • \$\begingroup\$ You could use a dictionary instead of a list and use the iteritems method of a dictionary but even more simple, probably you can use labels as the first argument of plt.legend. \$\endgroup\$ – Jan Kuiken Oct 17 '16 at 19:47
  • \$\begingroup\$ You might want to add that part to the answer, comments are not permanent and this did answer a part of OP's question. \$\endgroup\$ – Graipher Oct 18 '16 at 7:34
2
\$\begingroup\$

You simply need to slice your frame using the list of the zero level index of the data you're interested in. Drop the zero level index of that selection

import matplotlib.pyplot as plt
import pandas as pd

level0indexes = ['AWA', 'REM', 'S1', 'S2', 'SWS', 'stades']
cols = ['Total Acc']
slicedf = df.loc[level0indexes, cols].reset_index(level = 0,drop=True).round(4)*100
x = list(range(len(slicedf)))
plt.xticks(x,  slicedf.index.tolist())
plt.plot(slicedf.values.flatten(),label=cols[0])
plt.legend()

plt.show()

or even simpler, use pandas plot

import matplotlib.pyplot as plt
import pandas as pd

level0indexes = ['AWA', 'REM', 'S1', 'S2', 'SWS', 'stades']
cols = ['Total Acc']
slicedf = df.loc[level0indexes, cols].reset_index(level = 0,drop=True).round(4)*100
plt.figure();
slicedf.plot();
plt.show();

The second method will allow you to choose to plot more than one column, just add the extra column names to the cols list

\$\endgroup\$
1
\$\begingroup\$

You can simply use loc After unstacking.
no need for forloops.

In your code:

e=df['Total Acc'].round(4)*100
e.unstack().loc[['AWA', 'REM', 'S1', 'S2', 'SWS', 'stades']].T.plot()

PS. Some code I made to reproduce the concept:

import numpy as np
import pandas as pd 
# generate multiindex
idx = []
for letter in 'abcdefghij':
    for num in range(10):
        idx.append((letter,num))
# build dataframe        
data = pd.DataFrame(np.random.rand(100,10),
            index=pd.Index(idx))
# select 1 column, unstack, choose rows and plot.             
data[0].unstack().loc['a b d e g h'.split()].T.plot()
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.