Set dataframe to series or show nth label - python

Whenever I plot a dataset to a bar plot, the x axis labels overload with labels. How can I change the datatype of the x axis from the dataframe or how can I display every nth label?
Here is my code:
# Import statements for the packages to be used.
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline
# Loading the data and having a look at the first few lines
df = pd.read_csv('tmdb-movies.csv')
df.head()
# Replace 0 with NaN (Not a Number)
df['budget'].replace(0, np.NAN, inplace=True)
df['runtime'].replace(0, np.NAN, inplace=True)
# Drop all rows with null values (NaN)
df.dropna(axis=0, inplace=True)
# Drop all columns not required for investigation
df = df.drop(['id', 'imdb_id', 'revenue', 'cast', 'homepage', 'director', 'tagline',
'keywords', 'overview', 'genres', 'production_companies', 'vote_count', 'vote_average',
'release_date', 'budget_adj', 'revenue_adj'], axis=1)
budget_grp = df.groupby(['budget'])
budget_grp['popularity'].agg(['median', 'mean'])
# Setting mean popularity to variable budget_pop.
budget_pop = budget_grp['popularity'].mean()
# Bar plot with x as budget and y as average popularity.
budget_pop.plot(kind='bar' ,x='budget', y='popularity', figsize=(20,10), xlabel='Budget in
Dollars', ylabel='Average Popularity', rot=0, legend=True)
I have tried enumerate but don't know where to fit that in. I have also tried creating a function to find nth and I have tried changing my dataframe to integer but they always error.
Follow-up to answer below:

You can use custom xticks:
df = pd.DataFrame(data={'x':np.arange(1,1001,1), 'y':np.random.randint(1,1000,1000)})
ax = df.plot(kind='bar' ,x='x', y='y', figsize=(20,10))
min_value_in_x = 1
max_value_in_x = 1000
x_ticks = np.arange(min_value_in_x, max_value_in_x, 100)
ax.set(xticks=x_ticks, xticklabels=x_ticks)
plt.show()

Related

Plotly Distplot subplots

I am trying to write a for loop that for distplot subplots.
I have a dataframe with many columns of different lengths. (not including the NaN values)
fig = make_subplots(
rows=len(assets), cols=1,
y_title = 'Hourly Price Distribution')
i=1
for col in df_all.columns:
fig = ff.create_distplot([[df_all[[col]].dropna()]], col)
fig.append()
i+=1
fig.show()
I am trying to run a for loop for subplots for distplots and get the following error:
PlotlyError: Oops! Your data lists or ndarrays should be the same length.
UPDATE:
This is an example below:
df = pd.DataFrame({'2012': np.random.randn(20),
'2013': np.random.randn(20)+1})
df['2012'].iloc[0] = np.nan
fig = ff.create_distplot([df[c].dropna() for c in df.columns],
df.columns,show_hist=False,show_rug=False)
fig.show()
I would like to plot each distribution in a different subplot.
Thank you.
Update: Distribution plots
Calculating the correct values is probably both quicker and more elegant using numpy. But I often build parts of my graphs using one plotly approach(figure factory, plotly express) and then use them with other elements of the plotly library (plotly.graph_objects) to get what I want. The complete snippet below shows you how to do just that in order to build a go based subplot with elements from ff.create_distplot. I'd be happy to give further explanations if the following suggestion suits your needs.
Plot
Complete code
import numpy as np
import pandas as pd
import plotly.express as px
import plotly.figure_factory as ff
from plotly.subplots import make_subplots
import plotly.graph_objects as go
df = pd.DataFrame({'2012': np.random.randn(20),
'2013': np.random.randn(20)+1})
df['2012'].iloc[0] = np.nan
df = df.reset_index()
dfm = pd.melt(df, id_vars=['index'], value_vars=df.columns[1:])
dfm = dfm.dropna()
dfm.rename(columns={'variable':'year'}, inplace = True)
cols = dfm.year.unique()
nrows = len(cols)
fig = make_subplots(rows=nrows, cols=1)
for r, col in enumerate(cols, 1):
dfs = dfm[dfm['year']==col]
fx1 = ff.create_distplot([dfs['value'].values], ['distplot'],curve_type='kde')
fig.add_trace(go.Scatter(
x= fx1.data[1]['x'],
y =fx1.data[1]['y'],
), row = r, col = 1)
fig.show()
First suggestion
You should:
1. Restructure your data with pd.melt(df, id_vars=['index'], value_vars=df.columns[1:]),
2. and the use the occuring column 'variable' to build subplots for each year through the facet_row argument to get this:
In the complete snippet below you'll see that I've changed 'variable' to 'year' in order to make the plot more intuitive. There's one particularly convenient side-effect with this approach, namely that running dfm.dropna() will remove the na value for 2012 only. If you were to do the same thing on your original dataframe, the corresponding value in the same row for 2013 would also be removed.
import numpy as np
import pandas as pd
import plotly.express as px
df = pd.DataFrame({'2012': np.random.randn(20),
'2013': np.random.randn(20)+1})
df['2012'].iloc[0] = np.nan
df = df.reset_index()
dfm = pd.melt(df, id_vars=['index'], value_vars=df.columns[1:])
dfm = dfm.dropna()
dfm.rename(columns={'variable':'year'}, inplace = True)
fig = px.histogram(dfm, x="value",
facet_row = 'year')
fig.show()

How to plot two bar graphs side by side with columns from different dataframes in pandas

I want to plot two bar graphs side by side using matplotlib/seaborn for two countries Covid-19 confirmed cases: Italy and India for comparison. However after trying many methods I couldn't achieve the problem. Confirmed cases of both countries are coming from two different data frames.
Data source
I want to plot 'Dates' column on x-axis and 'Confirmed cases count' on y-axis.
Attaching images of my code for reference.
P.S: I am new to data visualization and pandas too.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.read_csv('https://raw.githubusercontent.com/datasets/covid-
19/master/data/countries-aggregated.csv', parse_dates = ['Date'])
df.head(5)
ind_cnfd = df[['Date', 'Country', 'Confirmed']]
ind_cnfd = ind_cnfd[ind_cnfd['Country']=='India']
italy_cnfd = df[['Date', 'Country', 'Confirmed']]
italy_cnfd = italy_cnfd[italy_cnfd['Country'] == 'Italy']
Expected output kind of this:
With dates on x-axis and confirmed cases on y-axis
Here's an example of what you can put together using matplotlib with seaborn. Feel free to play around with the axes settings, spacing, and so on by looking through matplotlib/seaborn documentation. Take note that I only did import matplotlib.pyplot as plt if you want to run any of this code from your notebook. I didn't use seaborn by the way.
You can optionally display the confirmed cases on a log-based y scale with the line: plt.yscale('log')
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df = pd.read_csv('https://raw.githubusercontent.com/datasets/covid-19/master/data/countries-aggregated.csv',
parse_dates = ['Date'])
# select the Date, Country, Confirmed features from country, with reset of index
ind_cnfd = df[df.Country == 'India']
ind_cnfd = ind_cnfd[['Date', 'Confirmed']].reset_index(drop = True)
ind_cnfd = ind_cnfd.rename(columns = {'Confirmed': 'Confirmed Cases in India'})
italy_cnfd = df[df.Country == 'Italy']
italy_cnfd = italy_cnfd[['Date', 'Confirmed']].reset_index(drop = True)
italy_cnfd = italy_cnfd.rename(columns = {'Confirmed': 'Confirmed Cases in Italy'})
# combine dataframes together, turn the date column into the index
df_cnfd = pd.concat([ind_cnfd.drop(columns = 'Date'), italy_cnfd], axis = 1)
df_cnfd['Date'] = df_cnfd['Date'].dt.date
df_cnfd.set_index('Date', inplace=True)
# make a grouped bar plot time series
ax = df_cnfd.plot.bar()
# show every other tick label
for label in ax.xaxis.get_ticklabels()[::2]:
label.set_visible(False)
# add titles, axis labels
plt.suptitle("Confirmed COVID-19 Cases over Time", fontsize = 15)
plt.xlabel("Dates")
plt.ylabel("Number of Confirmed Cases")
plt.tight_layout()
# plt.yscale('log')
plt.show()

Bar plot and coloured categorical variable

I have a dataframe with 3 variables:
data= [["2019/oct",10,"Approved"],["2019/oct",20,"Approved"],["2019/oct",30,"Approved"],["2019/oct",40,"Approved"],["2019/nov",20,"Under evaluation"],["2019/dec",30,"Aproved"]]
df = pd.DataFrame(data, columns=['Period', 'Observations', 'Result'])
I want a barplot grouped by the Period column, showing all the values ​​contained in the Observations column and colored with the Result column.
How can I do this?
I tried the sns.barplot, but it joined the values in Observations column in just one bar(mean of the values).
sns.barplot(x='Period',y='Observations',hue='Result',data=df,ci=None)
Plot output
Assuming that you want one bar for each row, you can do as follows:
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
result_cat = df["Result"].astype("category")
result_codes = result_cat.cat.codes.values
cmap = plt.cm.Dark2(range(df["Result"].unique().shape[0]))
patches = []
for code in result_cat.cat.codes.unique():
cat = result_cat.cat.categories[code]
patches.append(mpatches.Patch(color=cmap[code], label=cat))
df.plot.bar(x='Period',
y='Observations',
color=cmap[result_codes],
legend=False)
plt.ylabel("Observations")
plt.legend(handles=patches)
If you would like it grouped by the months, and then stacked, please use the following (note I updated your code to make sure one month had more than one status), but not sure I completely understood your question correctly:
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
data= [["2019/oct",10,"Approved"],["2019/oct",20,"Approved"],["2019/oct",30,"Approved"],["2019/oct",40,"Under evaluation"],["2019/nov",20,"Under evaluation"],["2019/dec",30,"Aproved"]]
df = pd.DataFrame(data, columns=['Period', 'Observations', 'Result'])
df.groupby(['Period', 'Result'])['Observations'].sum().unstack('Result').plot(kind='bar', stacked=True)

Seaborn Plot including different distributions of the same data

I wish to create a seaborn pointplot to display the full data distribution in a column, alongside the distribution of the lowest 25% of values, and the distribution of the highest 25% of values, and all side by side (on the x axis).
My attempt so far provides me with the values, but they are displayed on the same part of the x-axis only and not spread out from left to right on the graph, and with no obvious way to label the points from x-ticks (which I would prefer , rather than via a legend).
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib notebook
df = sns.load_dataset('tips')
df1 = df[(df.total_bill < df.total_bill.quantile(.25))]
df2 = df[(df.total_bill > df.total_bill.quantile(.75))]
sns.pointplot(y=df['total_bill'], data=df, color='red')
sns.pointplot(y=df1['total_bill'], data=df1, color='green')
sns.pointplot(y=df2['total_bill'], data=df2, color='blue')
You could .join() the new distributions to your existing df and then .plot() using wide format:
lower, upper = df.total_bill.quantile([.25, .75]).values.tolist()
df = df.join(df.loc[df.total_bill < lower, 'total_bill'], rsuffix='_lower')
df = df.join(df.loc[df.total_bill > upper, 'total_bill'], rsuffix='_upper')
sns.pointplot(data=df.loc[:, [c for c in df.columns if c.startswith('total')]])
to get:
If you wanted to add groups, you could simply use .unstack() to get to long format:
df = df.loc[:, ['total_bill', 'total_bill_upper', 'total_bill_lower']].unstack().reset_index().drop('level_1', axis=1).dropna()
df.columns = ['grp', 'val']
to get:
sns.pointplot(x='grp', y='val', hue='grp', data=df)
I would think along the lines of adding a "group" and then plot as a single DataFrame.
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib notebook
df = sns.load_dataset('tips')
df = df.append(df)
df.loc[(df.total_bill < df.total_bill.quantile(.25)),'group'] = 'L'
df.loc[(df.total_bill > df.total_bill.quantile(.75)),'group'] = 'H'
df = df.reset_index(drop=True)
df.loc[len(df)/2:,'group'] = 'all'
sns.pointplot(data = df,
y='total_bill',
x='group',
hue='group',
linestyles='')

pandas boxplot: swap box placement for comparison

tmpdf.boxplot(['original','new'], by = 'by column', ax = ax, sym = '')
gets me a plot like this
I want to compare "original" with "new", how can I arrange to put the two "0" boxes in one panel and the two "1" boxes in another panel? And of course swap the labelling with that.
Thanks
Here is a sample dataset to demonstrate.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# simulate some artificial data
# ==========================================
np.random.seed(0)
df = pd.DataFrame(np.random.rand(10,2), columns=['original', 'new'] )
df['by column'] = pd.Series([0,0,0,0,1,1,1,1,1,1])
# your original plot
ax = df.boxplot(['original', 'new'], by='by column', figsize=(12,6))
To get desired output, use groupby explicitly out of boxplot, so that we iterate over all subgroups, and plot a boxplot for each.
ax = df[['original', 'new']].groupby(df['by column']).boxplot(figsize=(12,6))

Categories

Resources