If you are running on Binder, use the Voilà button! or you can change your url from /notebooks/2-voila.ipynb
to /voila/render/2-voila.ipynb
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import ipywidgets as widgets
from matplotlib import rcParams
rcParams["font.size"] = 14
co2_data_source = "./data/monthly_in_situ_co2_mlo.csv"
co2_data_full = pd.read_csv(
co2_data_source, skiprows=np.arange(0, 56), na_values="-99.99"
)
co2_data_full.columns = [
"year", "month", "date (int)", "date", "observed co2", "seasonally adjusted",
"fit", "seasonally adjusted fit", "co2 filled", "seasonally adjusted filled"
]
co2_data = co2_data_full.dropna()
def get_data_between(data=co2_data, date_range=None, data_type="seasonally adjusted"):
"""
A function to fetch data between year_min and year_max
"""
if date_range is None:
date_range = data["date"].min(), data["date"].max()
# find the data between the minimimum and maximum years
indices = (data["date"] >= date_range[0]) & (data["date"] <= date_range[1])
return data["date"][indices], data[data_type][indices]
def plot_co2_data(data=co2_data, date_range=None, data_type="seasonally adjusted", ax=None):
"""
A function that we can use to plot data between year_min and year_max
"""
# create a figure if one isn't supplied
if ax is None:
fig, ax = plt.subplots(1, 1, figsize=(8, 5))
dates, data_between = get_data_between(data, date_range, data_type)
# plot data
ax.plot(dates, data_between, '.', ms=8)
ax.grid()
ax.set_xlabel(f"Year")
ax.set_ylabel(f"CO$_2$ [ppm]")
return ax
def add_line(dates, slope, intercept, ax=None, label=None):
"""
A function to add a line to a plot
"""
# create a figure if one isn't supplied
if ax is None:
fig, ax = plt.subplots(1, 1, figsize=(8, 5))
y = slope * (dates - co2_data["date"].min()) + intercept
ax.plot(dates, y, label=label)
def plot_fit_co2_data(slope, intercept, year_min=1958, year_max=2020, data_type="seasonally adjusted"):
"""
This function creates an interactive widget where we can fit a curve to data
"""
fig, ax = plt.subplots(1, 1, figsize=(8, 5))
plot_co2_data(co2_data, [year_min, year_max], data_type, ax=ax)
add_line(np.r_[year_min, year_max], slope, intercept, ax=ax)
return ax
def predict_co2(slope, intercept, prediction_date):
"""
based on an estimated slope, and intercept use a linear
model to predict CO2 concentration
"""
return slope * (prediction_date-co2_data["date"].min()) + intercept
def linear_model_co2(
data_type="seasonally adjusted", years=np.r_[1958, 2020],
slope=1, intercept=300, year_predict=2030, show_prediction=False
):
"""
Generate a plot with the co2 data, our linear model and the prediction
"""
fig, ax = plt.subplots(1, 1, figsize=(8, 5))
plot_co2_data(co2_data, years, data_type, ax=ax)
add_line(years, slope, intercept, ax=ax)
if show_prediction is True:
prediction = predict_co2(slope, intercept, year_predict)
ax.plot(year_predict, prediction, 'C1o')
ax.text(
year_predict - 1, prediction,
f"{prediction:1.2f} ppm", ha="right", va="center"
)
Q1: Within small enough regions, the data follow an approximately linear trend, so a linear model has some predictive power. Out to which year would you trust the model built with the data from 1958 - 1963? Where does it start to break down?
Q2: How far out would you trust our predictions with data from 2015 - 2020? Would you trust our model to predict CO$_2$ in the year 2050?
Q3: How might you approach building a model to fit all of our data?
# Parameter choices for the sidgets
year_max = 2050 # maximum value for the sliders
years_initial = [1958, 1963] # years we focus on initially
year_predict_initial = 2030
# construct our widget
w = widgets.interactive(
linear_model_co2,
data_type=widgets.ToggleButtons(
options=["observed co2", "seasonally adjusted"], value="seasonally adjusted"
),
years=widgets.IntRangeSlider(
min=co2_data["date"].min(), max=year_max, value=years_initial
),
slope=widgets.FloatSlider(
min=0, max=5, step=0.1, value=2
),
intercept=widgets.FloatSlider(
min=co2_data["observed co2"].min() - 5,
max=co2_data["observed co2"].min() + 20,
step=0.25
),
year_predict=widgets.IntSlider(
min=co2_data["date"].min(), max=year_max, value=year_predict_initial
),
show_prediction=widgets.Checkbox(
value=False
)
)
w