Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
260 views
in Technique[技术] by (71.8m points)

python - How to create a min-max plot by month with fill_between

I have to show month names as xticks and while I plot the figure and pass x as month names it plots it wrong . I also have to overlay a scatter plot over the line graph.

I cannot paste the full code here as it is an MOOC assignment and I am just looking for what am I doing wrong here.

plt.figure(figsize=(8,5))

plt.plot(mint['Mean'],linewidth= 1, label = 'Minumum')
plt.plot(maxt['Mean'],linewidth = 1, label = 'Maximum')

plt.scatter(broken_low,mint15.iloc[broken_low]['Mean'],alpha = 0.75)
plt.scatter(broken_high,maxt15.iloc[broken_high]['Mean'],alpha = .75)

Dataset link here :

https://drive.google.com/file/d/1qJnnHDK_0ghmHQl4OuyKDr-0K5ETo7Td/view?usp=sharing

Here is an idea of what it looks like

It should look like this with area between the lines filled and x axis as months and y axis as degree Celsius

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Update Using Data from OP

  • The issue with the first method is that it requires the x-axis to be a datetime format.
  • The data in the question is being grouped and plotted against a string, which is a combination of the month and day
  • The x-axis represents 365 days, leap years have been removed.
    • Place ticks at the appropriate location for the beginning of each month
    • Add a label to the tick
  • This appears to be from coursera: Applied Data Science with Python Specialization
import pandas as pd
import matplotlib.pyplot as plot
import calendar

# load the data
url = 'https://raw.githubusercontent.com/trenton3983/stack_overflow/master/data/so_data/2020-07-17_62929123/temperature.csv'
df = pd.read_csv(url, parse_dates=['Date'])

# remove leap day
df = df[~((df.Date.dt.month == 2) & (df.Date.dt.day == 29))]

# add a year column
df['Year'] = df.Date.dt.year

# add a month-day column to use for groupby
df['Month-Day'] = df.Date.dt.month.astype('str') + '-' + df.Date.dt.day.astype('str')

# select 2015 data
df_15 = df[df.Year == 2015].copy().reset_index()

# select data before 2015
df_14 = df[df.Year < 2015].copy().reset_index()

# filter data to either max or min and groupby month-day
max_14 = df_14[df_14.Element == 'TMAX'].groupby(['Month-Day']).agg({'Data_Value': max}).reset_index().rename(columns={'Data_Value': 'Daily_Max'})
min_14 = df_14[df_14.Element == 'TMIN'].groupby(['Month-Day']).agg({'Data_Value': min}).reset_index().rename(columns={'Data_Value': 'Daily_Min'})
max_15 = df_15[df_15.Element == 'TMAX'].groupby(['Month-Day']).agg({'Data_Value': max}).reset_index().rename(columns={'Data_Value': 'Daily_Max'})
min_15 = df_15[df_15.Element == 'TMIN'].groupby(['Month-Day']).agg({'Data_Value': max}).reset_index().rename(columns={'Data_Value': 'Daily_Min'})

# select max values from 2015 that are greater than the recorded max
higher_14 = max_15[max_15 > max_14]

# select min values from 2015 that are less than the recorded min
lower_14 = min_15[min_15 < min_14]

# plot the min and max lines
ax = max_14.plot(label='Max Recorded', color='tab:red', figsize=(12, 8))
min_14.plot(ax=ax, label='Min Recorded', color='tab:blue')

# add the fill, between min and max
plt.fill_between(max_14.index, max_14.Daily_Max, min_14.Daily_Min, alpha=0.10, color='tab:orange')

# add points greater than max or less than min
plt.scatter(higher_14.index, higher_14.Daily_Max, label='2015 Max > Record', alpha=0.75, color='tab:red')
plt.scatter(lower_14.index, lower_14.Daily_Min, label='2015 Min < Record', alpha=0.75, color='tab:blue')

# set plot xlim
plt.xlim(-5, 370)

# tick locations
ticks=[-5, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 370]

# tick labels
labels = list(calendar.month_abbr)  # list of months
labels.extend(['Jan', ''])

# add the custom ticks and labels
plt.xticks(ticks=ticks, labels=labels)

# plot cosmetics
plt.legend()
plt.xlabel('Day of Year: 0-365 Displaying Start of Month')
plt.ylabel('Temperature °C')
plt.title('Daily Max and Min: 2009 - 2014
Recorded Max < 2015 Temperatures < Recorded Min')
plt.tight_layout()
plt.show()

enter image description here

Original Answer

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

# plot styling parameters
plt.style.use('seaborn')
plt.rcParams['figure.figsize'] = (16.0, 10.0)
plt.rcParams["patch.force_edgecolor"] = True

# locate the Month and format the label
months = mdates.MonthLocator()  # every month
months_fmt = mdates.DateFormatter('%b')

# plot the data
fig, ax = plt.subplots()
ax.plot(max_15.index, 'rolling', data=max_15, label='max rolling mean')
ax.scatter(x=max_15.index, y='v', data=max_15, alpha=0.75, label='MAX')

ax.plot(min_15.index, 'rolling', data=min_15, label='min rolling mean')
ax.scatter(x=min_15.index, y='v', data=min_15, alpha=0.75, label='MIN')
ax.legend()

# format the ticks
ax.xaxis.set_major_locator(months)
ax.xaxis.set_major_formatter(months_fmt)

enter image description here

Reproducible Data

import pandas as pd

# download data into dataframe, it's in a wide format
pdx_19 = pd.read_csv('http://www.weather.gov/source/pqr/climate/webdata/Portland_dailyclimatedata.csv', header=6)

# clean and label data
pdx_19.drop(columns=['AVG or Total'], inplace=True)
pdx_19.columns = list(pdx_19.columns[:3]) + [f'v_{day}' for day in pdx_19.columns[3:]]
pdx_19.rename(columns={'Unnamed: 2': 'TYPE'}, inplace=True)
pdx_19 = pdx_19[pdx_19.TYPE.isin(['TX', 'TN', 'PR'])]

# convert to long format
pdx = pd.wide_to_long(pdx_19, stubnames='v', sep='_', i=['YR', 'MO', 'TYPE'], j='day').reset_index()

# additional cleaning
pdx.TYPE = pdx.TYPE.map({'TX': 'MAX', 'TN': 'MIN', 'PR': 'PRE'})
pdx.rename(columns={'YR': 'year', 'MO': 'month'}, inplace=True)
pdx = pdx[pdx.v != '-'].copy()
pdx['date'] = pd.to_datetime(pdx[['year', 'month', 'day']])
pdx.drop(columns=['year', 'month', 'day'], inplace=True)
pdx.v.replace({'M': np.nan, 'T': np.nan}, inplace=True)
pdx.v = pdx.v.astype('float')

# select on 2015
pdx_2015 = pdx[pdx.date.dt.year == 2015].reset_index(drop=True).set_index('date')

# select only MAX temps
max_15 = pdx_2015[pdx_2015.TYPE == 'MAX'].copy()

# select only MIN temps
min_15 = pdx_2015[pdx_2015.TYPE == 'MIN'].copy()

# calculate rolling mean
max_15['rolling'] = max_15.v.rolling(7).mean()
min_15['rolling'] = min_15.v.rolling(7).mean()

max_15

           TYPE     v    rolling
date                            
2015-01-01  MAX  39.0        NaN
2015-01-02  MAX  41.0        NaN
2015-01-03  MAX  41.0        NaN
2015-01-04  MAX  53.0        NaN
2015-01-05  MAX  57.0        NaN
2015-01-06  MAX  47.0        NaN
2015-01-07  MAX  51.0  47.000000
2015-01-08  MAX  45.0  47.857143
2015-01-09  MAX  50.0  49.142857
2015-01-10  MAX  42.0  49.285714

min_15

           TYPE     v    rolling
date                            
2015-01-01  MIN  24.0        NaN
2015-01-02  MIN  26.0        NaN
2015-01-03  MIN  35.0        NaN
2015-01-04  MIN  38.0        NaN
2015-01-05  MIN  42.0        NaN
2015-01-06  MIN  38.0        NaN
2015-01-07  MIN  34.0  33.857143
2015-01-08  MIN  35.0  35.428571
2015-01-09  MIN  37.0  37.000000
2015-01-10  MIN  36.0  37.142857

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...