Plot sub-bar charts on a dataframe groupby - python

Hi I am having some trouble plotting sub-bar charts after a dataframe groupby
Post groupby, the data is as per the below :
I tried the below to create a bar chart.
df_temp[df_temp.index =='ABC'].unstack().plot.bar(figsize=(10,2))
How can I plot a bar charts where the x-axis is the date and y-axis is the count and each row (ABC and EFG) is its own subplot (vertically stacked)
Example below
thanks for your help !

thanks to #r-beginnners
#remove the multi-level column
df.columns = df.columns.droplevel()
#plot the sub-plots
# if y-axis scale to be the same, use sharey=True
df.T.plot(subplots=True, layout=(2,1), kind='bar', sharey=True)

Related

Python & Pandas: Plotting a Pivot with multiple Indexes

Hi to all the experts,
I'm new to Python and Data Science and actually I'm learning with a real world example to get into Data Science.
I loaded already a CSV and did some work on the data. That's ok. I have the following dataframe:
dataframe
Then, I created a Pivot from the dataframe:
pivot = pd.pivot_table(
data=df,
index=['Category', 'month', 'year'],
values='Amount',
aggfunc='sum',
margins=True)
Now, I have the following dataframe:
new dataframe
Now, I want to plot the following (line chart or bar chart):
X: Month
Y: Amount
But, I want that for explicit Category like "Business" to see, how the amount changed over the periods.
Whats the best way, to plot a clear, beautiful chart with matplotlib?
Thanks in Advance.
Many Greetings
Leon
You can use the below code to build the graphs. I think the stacked bar graphs would be a good way to see the Amount in each month.
Code
## Add AFTER you have created your pivot table
dfg = pivot.reset_index().set_index(['Month', 'Category']).sort_index(level=[0,1])
fig, ax = plt.subplots(figsize=(6,4))
dfg['Amount'].unstack().plot.bar(stacked=True, ax=ax, legend = False)
ax.set_xticklabels(sorted(df.Month.unique()), rotation=0)
ax.set_title('My Graph')
fig.legend(loc="upper right", bbox_to_anchor=(1.1, 0.9))
plt.show()
Stacked Bar graph
Unstacked Bar graph
Change stacked = True to stacked = False to see the bars next to each other, if you are not a fan of stacked bars
Line Graphs
You can also use line graphs, but not my personal preference.
Replace the plot.bar line in above code to
dfg['Amount'].unstack().plot(kind='line', marker='o', ax=ax, legend = False)

plotting whit subplots in a loop python [duplicate]

Case:
I receive a dataframe with (say 50) columns.
I extract the necessary columns from that dataframe using a condition.
So we have a list of selected columns of our dataframe now. (Say this variable is sel_cols)
I need a bar chart for each of these columns value_counts().
And I need to arrange all these bar charts in 3 columns, and varying number of rows based on number of columns selected in sel_cols.
So, if say 8 columns were selected, I want the figure to have 3 columns and 3 rows, with last subplot empty or just 8 subplots in 3x3 matrix if that is possible.
I could generate each chart separately using following code:
for col in sel_cols:
df[col].value_counts().plot(kind='bar)
plt.show()
plt.show() inside the loop so that each chart is shown and not just the last one.
I also tried appending these charts to a list this way:
charts = []
for col in sel_cols:
charts.append(df[col].value_counts().plot(kind='bar))
I could convert this list into an numpy array through reshape() but then it will have to be perfectly divisible into that shape. So 8 chart objects will not be reshaped into 3x3 array.
Then I tried creating the subplots first in this way:
row = len(sel_cols)//3
fig, axes = plt.subplots(nrows=row,ncols=3)
This way I would get the subplots, but I get two problems:
I end up with extra subplots in the 3 columns which will go unplotted (8 columns example).
I do not know how to plot under each subplots through a loop.
I tried this:
for row in axes:
for chart, col in zip(row,sel_cols):
chart = data[col].value_counts().plot(kind='bar')
But this only plots the last subplot with the last column. All other subplots stays blank.
How to do this with minimal lines of code, possibly without any need for human verification of the final subplots placements?
You may use this sample dataframe:
pd.DataFrame({'A':['Y','N','N','Y','Y','N','N','Y','N'],
'B':['E','E','E','E','F','F','F','F','E'],
'C':[1,1,0,0,1,1,0,0,1],
'D':['P','Q','R','S','P','Q','R','P','Q'],
'E':['E','E','E','E','F','F','G','G','G'],
'F':[1,1,0,0,1,1,0,0,1],
'G':['N','N','N','N','Y','N','N','Y','N'],
'H':['G','G','G','E','F','F','G','F','E'],
'I':[1,1,0,0,1,1,0,0,1],
'J':['Y','N','N','Y','Y','N','N','Y','N'],
'K':['E','E','E','E','F','F','F','F','E'],
'L':[1,1,0,0,1,1,0,0,1],
})
Selected columns are: sel_cols = ['A','B','D','E','G','H','J','K']
Total 8 columns.
Expected output is bar charts for value_counts() of each of these columns arranged in subplots in a figure with 3 columns. Rows to be decided based on number of columns selected, here 8 so 3 rows.
Given OP's sample data:
df = pd.DataFrame({'A':['Y','N','N','Y','Y','N','N','Y','N'],'B':['E','E','E','E','F','F','F','F','E'],'C':[1,1,0,0,1,1,0,0,1],'D':['P','Q','R','S','P','Q','R','P','Q'],'E':['E','E','E','E','F','F','G','G','G'],'F':[1,1,0,0,1,1,0,0,1],'G':['N','N','N','N','Y','N','N','Y','N'],'H':['G','G','G','E','F','F','G','F','E'],'I':[1,1,0,0,1,1,0,0,1],'J':['Y','N','N','Y','Y','N','N','Y','N'],'K':['E','E','E','E','F','F','F','F','E'],'L':[1,1,0,0,1,1,0,0,1]})
sel_cols = list('ABDEGHJK')
data = df[sel_cols].apply(pd.value_counts)
We can plot the columns of data in several ways (in order of simplicity):
DataFrame.plot with subplots param
seaborn.catplot
Loop through plt.subplots
1. DataFrame.plot with subplots param
Set subplots=True with the desired layout dimensions. Unused subplots will be auto-disabled:
data.plot.bar(subplots=True, layout=(3, 3), figsize=(8, 6),
sharex=False, sharey=True, legend=False)
plt.tight_layout()
2. seaborn.catplot
melt the data into long-form (i.e., 1 variable per column, 1 observation per row) and pass it to seaborn.catplot:
import seaborn as sns
melted = data.melt(var_name='var', value_name='count', ignore_index=False).reset_index()
sns.catplot(data=melted, kind='bar', x='index', y='count',
col='var', col_wrap=3, sharex=False)
3. Loop through plt.subplots
zip the columns and axes to iterate in pairs. Use the ax param to place each column onto its corresponding subplot.
If the grid size is larger than the number of columns (e.g., 3*3 > 8), disable the leftover axes with set_axis_off:
fig, axes = plt.subplots(3, 3, figsize=(8, 8), constrained_layout=True, sharey=True)
# plot each col onto one ax
for col, ax in zip(data.columns, axes.flat):
data[col].plot.bar(ax=ax, rot=0)
ax.set_title(col)
# disable leftover axes
for ax in axes.flat[data.columns.size:]:
ax.set_axis_off()
Alternative to the answer by tdy, I tried to do it without seaborn using Matplotlib and a for loop.
Figured it might be better for some who want specific control over subplots with formatting and other parameters, then this is another way:
fig = plt.figure(1,figsize=(16,12))
for i, col in enumerate(sel_cols,1):
fig.add_subplot(3,4,i,)
data[col].value_counts().plot(kind='bar',ax=plt.gca())
plt.title(col)
plt.tight_layout()
plt.show(1)
plt.subplot activates a subplot, while plt.gca() points to the active subplot.

Plot bar chart in multiple subplot rows with Pandas

I have a simple long-form dataset I would like to generate bar charts from. The dataframe looks like this:
data = {'Year':[2019,2019,2019,2020,2020,2020,2021,2021,2021],
'Month_diff':[0,1,2,0,1,2,0,1,2],
'data': [12,10,13,16,12,18,19,45,34]}
df = pd.DataFrame(data)
I would like to plot a bar chart that has 3 rows, each for 2019, 2020 and 2021. X axis being month_diff and data goes on Y axis.
How do I do this?
If the data was in different columns, then I could have just used this code:
df.plot(x="X", y=["A", "B", "C"], kind="bar")
But my data is in a single column and ideally, I'd like to have different row for each year.
1. seaborn.catplot
The simplest option for a long-form dataframe is the seaborn.catplot wrapper, as Johan said:
import seaborn as sns
sns.catplot(data=df, x='Month_diff', y='data', row='Year',
kind='bar', height=2, aspect=4)
2. pivot + DataFrame.plot
Without seaborn:
pivot from long-form to wide-form (1 year per column)
use DataFrame.plot with subplots=True to put each year into its own subplot (and optionally sharey=True)
(df.pivot(index='Month_diff', columns='Year', values='data')
.plot.bar(subplots=True, sharey=True, legend=False))
plt.tight_layout()
Note that if you prefer a single grouped bar chart (which you alluded to at the end), you can just leave out the subplots param:
df.pivot(index='Month_diff', columns='Year', values='data').plot.bar()
3. DataFrame.groupby + subplots
You can also iterate the df.groupby('Year') object:
Create a subplots grid of axes based on the number of groups (years)
Plot each group (year) onto its own subplot row
groups = df.groupby('Year')
fig, axs = plt.subplots(nrows=len(groups), ncols=1, sharex=True, sharey=True)
for (name, group), ax in zip(groups, axs):
group.plot.bar(x='Month_diff', y='data', legend=False, ax=ax)
ax.set_title(name)
fig.supylabel('data')
plt.tight_layout()

Show first and last label in pandas plot

I have a DataFrame with 361 columns. I want to plot it but showing only the first and last columns in the legend. For instance:
d = {'col1':[1,2],'col2':[3,4],'col3':[5,6],'col4':[7,8]}
df = pd.DataFrame(data=d)
If I plot through df.plot() all the legends will be displayed, but I only want 'col1' and 'col4' in my legend with the proper color code (I am using a colormap) and legend title.
One way to do this is to plot each column separately through matplotlib without using legends and then plot two more empty plots with only the labels (example below), but I wonder if there is a direct way to do it with pandas.
for columns in df:
plt.plot(df[columns])
plt.plot([],[],label=df.columns[0])
plt.plot([],[],label=df.columns[-1])
plt.legend()
plt.show()
Let's try extracting the handlers/labels from the axis and defining new legend:
ax = df.plot()
handlers, labels = ax.get_legend_handles_labels()
new_handlers, new_labels = [], []
for h,l in zip(handlers, labels):
if l in ['col1','col4']:
new_handlers.append(h)
new_labels.append(l)
ax.legend(new_handlers, new_labels)
Output:
You can try to split your df into two dfs which the second one will contain only the columns of interest and then plot both dfs showing only the second legend.

how to plot a pie chart from a dataframe using crosstab function in python

i am trying to plot a pie chart using crosstab function from 2 columns in a dataframe where until now i am able to plot a bar chart using the below statement.
sample of the dataframe:
pd.crosstab(df['event_location'],df['event_type']).iplot(kind="bar", bins=20, theme="white", title="Event type over Location",xTitle='location', yTitle='Number of person')
my question is how to convert this bar chart into a pie chart ?
I guess you are trying to display the number of occurrences for every event type. This simple code will help you plot pie charts per location.
import matplotlib.pyplot as plt
ct = pd.crosstab(df['event_location'],df['event_type'])
ct.plot.pie(subplots=True)
plt.legend(title='XYZ')
plt.show()

Categories

Resources