A line graph for non-numeric data - python

I have a dataset with mostly non numeric forms. I would love to create a visualization for them but I am having an error message.
My data set looks like this
|plant_name|Customer_name|Job site|Delivery.Date|DeliveryQuantity|
|SN13|John|Sweden|01.01.2019|6|
|SN14|Ruth|France|01.04.2018|4|
|SN15|Jane|Serbia|01.01.2019|2|
|SN11|Rome|Denmark|01.04.2018|10|
|SN14|John|Sweden|03.04.2018|5|
|SN15|John|Sweden|04.09.2019|7|
|
I need to create a lineplot to show how many times John made a purchase using Delivery Date as my timeline (x-axis)
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
pd.set_option("display.max_rows", 5)
hr_data = pd.read_excel("D:\data\Days_Calculation.xlsx", parse_dates = True)
x = hr_data['DeliveryDate']
y = hr_data ['Customer_name']
sns.lineplot(x,y)
Error: No numeric types to aggregate
My expected result show be a line graph like this
John's marker will present on the timeline (Delivery Date) on "01.01.2019", "03.04.2018" and "04.09.2019"
Another instance
To plot string vs float for example Total number of quantity (DeliveryQuantity) vs Customer Name .How can one approach this
how do one format the axes distance of a plot (not label)

Why not make Delivery Date a timestamp object instead of a string?
hr_data["Delivery.Date"] = pd.to_datetime(hr_data["Delivery.Date"])
Now you got plot options.
Working with John.
john_data = hr_data[hr_data["Customer_name"]=="John"]
sns.countplot(john_data["Delivery.Date"])

Generally speaking you have to aggregate something when working with categorical data. Whether you will be counting names in a column or adding number of orders, or ranking some categories this is still numeric data.
plot_data = hr_data.pivot_table(index='DeliveryDate', columns='Customer_name', values='DeliveryQuantity', aggfunc='sum')
plt.xticks(LISTOFVALUESFORXRANGE)
plot_data.plot(legend=False)

Related

How to specify date bin ranges for Seaborn displot

Problem statement
I am creating a distribution plot of flood events per N year periods starting in 1870. I am using Pandas and Seaborn. I need help with...
specifying the date range of each bin when using sns.displot, and
clearly representing my bin size specifications along the x axis.
To clarify this problem, here is the data that I am working with, what I have tried, and a description of the desired output.
The Data
The data I am using is available from the U.S. Weather service.
import pandas as pd
import bs4
import urllib.request
link = "https://water.weather.gov/ahps2/crests.php?wfo=jan&gage=jacm6&crest_type=historic"
webpage=str(urllib.request.urlopen(link).read())
soup = bs4.BeautifulSoup(webpage)
tbl = soup.find('div', class_='water_information')
vals = tbl.get_text().split(r'\n')
tcdf = pd.Series(vals).str.extractall(r'\((?P<Rank>\d+)\)\s(?P<Stage>\d+.\d+)\sft\son\s(?P<Date>\d{2}\/\d{2}\/\d{4})')\
.reset_index(drop=True)
tcdf['Stage'] = tcdf.Stage.astype(float)
total_crests_events = len(tcdf)
tcdf['Rank'] = tcdf.Rank.astype(int)
tcdf['Date'] = pd.to_datetime(tcdf.Date)
What works
I am able to plot the data with Seaborn's displot, and I can manipulate the number of bins with the bins command.
The second image is closer to my desired output. However, I do not think that it's clear where the bins start and end. For example, the first two bins (reading left to right) clearly start before and end after 1880, but the precise years are not clear.
import seaborn as sns
# fig. 1: data distribution using default bin parameters
sns.displot(data=tcdf,x="Date")
# fig. 2: data distribution using 40 bins
sns.displot(data=tcdf,x="Date",bins=40)
What fails
I tried specifying date ranges using the bins input. The approach is loosely based on a previous SO thread.
my_bins = pd.date_range(start='1870',end='2025',freq='5YS')
sns.displot(data=tcdf,x="Date",bins=my_bins)
This attempt, however, produced a TypeError
TypeError: Cannot cast array data from dtype('O') to dtype('float64') according to the rule 'safe'
This is a long question, so I imagine that some clarification might be necessary. Please do not hesitate to ask questions in the comments.
Thanks in advance.
Seaborn internally converts its input data to numbers so that it can do math on them, and it uses matplotlib's "unit conversion" machinery to do that. So the easiest way to pass bins that will work is to use matplotlib's date converter:
sns.displot(data=tcdf, x="Date", bins=mpl.dates.date2num(my_bins))

Removing zero values from pivot table somehow creates another problem

I have an assignment from my Python class to mine a set of data consisting CO2 emissions from (almost) all the countries in the world from 1960 to 2011. One of the task i've been working on is to produce a line graph that represents the growth of CO2 production in a specific country, and i'd like to avoid inserting zeros into the graph. Here is the code i've been using.
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sn
import numpy as np
# Creating DataFrame
Data = pd.read_excel('CO2 Sorted Data.xlsx')
df = pd.DataFrame(Data, columns=['Year','CountryName','Region','IncomeType','CO2Emission','CO2EmCMT'])
df.replace(0,np.nan,inplace=True)
print(df)
# Creating the Pivot Table
pvt = df.pivot_table(index=['Year'],columns=['CountryName'],values='CO2Emission',aggfunc='sum')
# Creating the Graph
pvt2 = pvt.reindex()
CO2Country = input('Input Country Name = ')
remove_zero=pvt2[CO2Country]
rz1=[i for i in remove_zero if i !=0]
plt.plot(rz1,c='red')
plt.title('CO2 Emission of ' +CO2Country +' (1960-2011)', fontsize=10)
plt.xlabel('Year',fontsize=10)
plt.ylabel('CO2 Emission (kiloton)')
plt.grid(True)
plt.show
If i input Aruba for example, output would look like this.
Line Graph of Aruba
However, the x-axis only shows the 'number' of years on the data requested, not the year itself. I have no clue on what triggers this other than changing the zeroes to NaN, but that doesn't make any sense in my mind. How can i make the x-axis show the true year, as in 1986-2011?
Here is a glimpse of the data:
To get the output in proper year format, you must enumerate the data first.
So: data = list(enumerate(rz1, start=1960))
There are to ways to go about plotting this new data, one is by converting the data into a np Array and transposing, the other is by using the zip function. They both have the same output.
data = list(zip(*b))
or
data = np.array(data).transpose()
The final code(in the creating the graph section) is:
# Creating the Graph
pvt2 = pvt.reindex()
CO2Country = 'Aruba'
remove_zero=pvt2[CO2Country]
rz1=[i for i in remove_zero if i !=0]
data = list(enumerate(rz1, start=1960))
# data= np.array(data).transpose()
data= list(zip(*data))
plt.plot(data[0], data[1],c='red')
s/n: call plt.show(), not plt.show
I don't know about the pivoting thing, but the following works fine:
co2.Year = pd.to_datetime(co2.Year)
aruba = df[df.CountryName = "Aruba"].set_index("Year")
aruba.CO2Emission.plot()

plot matplotlib aggregated data python

I need plot of aggregrated data
import pandas as pd
basic_data= pd.read_csv('WHO-COVID-19-global-data _2.csv',parse_dates= ['Date_reported'] )
cum_daily_cases = basic_data.groupby('Date_reported')[['New_cases']].sum()
import pylab
x = cum_daily_cases['Date_reported']
y = cum_daily_cases['New_cases']
pylab.plot(x,y)
pylab.show()
Error: 'Date_reported'
Input: Date_reported, Country_code, Country, WHO_region, New_cases, Cumulative_cases, New_deaths, Cumulative_deaths 2020-01-03,AF,Afghanistan,EMRO,0,0,0,0
Output: the total quantity of "New cases" showed on the plot per day.
What should I do to run this plot? link to dataset
The column names contain a leading space (can be easily seen by checking basic_data.dtypes). Fix that by adding the following line immediately after basic_data was read:
basic_data.columns = [s.strip() for s in basic_data.columns]
In addition, your x variable should be the index after groupby-sum, not a column Date_reported. Correction:
x = cum_daily_cases.index
The plot should show as expected.

How to create histogram from grouped data

I'm trying to create histogram from grouped data in pandas.
So far I was able to create standard line plot. But I can't figure out how to do the same to get histogram (bar chart). I would like to get 2 age histograms of persons who survived Titanic crush and who didn't - to see if there is a difference in age distribution.
Source data:
https://www.udacity.com/api/nodes/5454512672/supplemental_media/titanic-datacsv/download
So far my code:
import pandas as pn
titanic = pn.DataFrame.from_csv('titanic_data.csv')
SurvivedAge= titanic.groupby(['Survived','Age']).size()
SurvivedAge=SurvivedAge.reset_index()
SurvivedAge.columns=['Survived', 'Age', 'Num']
SurvivedAge.index=(SurvivedAge['Survived'])
del SurvivedAge['Survived']
SurvivedAget=SurvivedAge.reset_index().pivot('Age', 'Survived','Num')
SurvivedAget.plot()
when I'm trying to plot a histogram from this data set I'm getting strange results.
SurvivedAget.hist()
I would be grateful for help with that.
You can:
titanic = pd.read_csv('titanic_data.csv')
survival_by_age = titanic.groupby(['Age', 'Survived']).size().unstack('Survived')
survival_by_age.columns = ['No', 'Yes']
survival_by_age.plot.bar(title='Survival by Age')
to get:
which you can further tweak. You could also consolidate the fractional ages so you can use integer indices, or bin the data into say 5yr age spans to get more user-friendly output. And then there is seaborn with a various types of distribution plots.

Pandas scatter_matrix - plot categorical variables

I am looking at the famous Titanic dataset from the Kaggle competition found here: http://www.kaggle.com/c/titanic-gettingStarted/data
I have loaded and processed the data using:
# import required libraries
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
# load the data from the file
df = pd.read_csv('./data/train.csv')
# import the scatter_matrix functionality
from pandas.tools.plotting import scatter_matrix
# define colors list, to be used to plot survived either red (=0) or green (=1)
colors=['red','green']
# make a scatter plot
scatter_matrix(df,figsize=[20,20],marker='x',c=df.Survived.apply(lambda x:colors[x]))
df.info()
How can I add the categorical columns like Sex and Embarked to the plot?
You need to transform the categorical variables into numbers to plot them.
Example (assuming that the column 'Sex' is holding the gender data, with 'M' for males & 'F' for females)
df['Sex_int'] = np.nan
df.loc[df['Sex'] == 'M', 'Sex_int'] = 0
df.loc[df['Sex'] == 'F', 'Sex_int'] = 1
Now all females are represented by 0 & males by 1. Unknown genders (if there are any) will be ignored.
The rest of your code should process the updated dataframe nicely.
after googling and remembering something like the .map() function I fixed it in the following way:
colors=['red','green'] # color codes for survived : 0=red or 1=green
# create mapping Series for gender so it can be plotted
gender = Series([0,1],index=['male','female'])
df['gender']=df.Sex.map(gender)
# create mapping Series for Embarked so it can be plotted
embarked = Series([0,1,2,3],index=df.Embarked.unique())
df['embarked']=df.Embarked.map(embarked)
# add survived also back to the df
df['survived']=target
now I can plot it again...and drop the added columns afterwards.
thanks everyone for responding.....
Here is my solution:
# convert string column to category
df.Sex = df.Sex.astype('category')
# create additional column for its codes
df['Sex_code'] = df_clean.Sex.cat.codes

Categories