I am working on the file "Lectures/Lecture18 -- Diffusive energy balance model.ipynb".
The first task is:

4. Parameterizing the radiation terms

Let's go back to the complete budget with our heat transport parameterization
$$ C(\phi) \frac{\partial T_s}{\partial t} = \text{ASR}(\phi) - \text{OLR}(\phi) + \frac{D}{\cos\phi } \frac{\partial }{\partial \phi} \left(   \cos\phi  ~ \frac{\partial T_s}{\partial \phi} \right) $$
We want to express this as a closed equation for surface temperature $T_s$.
First, as usual, we can write the solar term as
$$ \text{ASR} = (1-\alpha) ~ Q $$
For now, we will assume that the planetary albedo is fixed (does not depend on temperature). Therefore the entire shortwave term $(1-\alpha) Q$ is a fixed source term in our budget. It varies in space and time but does not depend on $T_s$.
Note that the solar term is (at least in annual average) larger at equator than poles… and transport term acts to flatten out the temperatures.
Now, we almost have a model we can solve for T!  Just need to express the OLR in terms of temperature.
So…  what’s the link between OLR and temperature????
[ discuss ]
We spent a good chunk of the course looking at this question, and developed a model of a vertical column of air.
We are trying now to build a model of the equator-to-pole (or pole-to-pole) temperature structure.
We COULD use an array of column models, representing temperature as a function of height and latitude (and time).
But instead, we will keep things simple, one spatial dimension at a time.
Introduce the following simple parameterization:
$$ OLR = A + B T_s $$
With $T_s$ the zonal average surface temperature in ºC, A is a constant in W m$^{-2}$ and B is a constant in W m$^{-2}$ ºC$^{-1}$.
OLR versus surface temperature in NCEP Reanalysis data
Let's look at the data to find reasonable values for $A$ and $B$.
Can you write Python code for it?

import xarray as xr
## The NOAA ESRL server is shutdown! January 2019
ncep_url = "http://www.esrl.noaa.gov/psd/thredds/dodsC/Datasets/ncep.reanalysis.derived/"
ncep_Ts = xr.open_dataset( ncep_url + "surface_gauss/skt.sfc.mon.1981-2010.ltm.nc", decode_times=False)
#url = 'http://apdrc.soest.hawaii.edu:80/dods/public_data/Reanalysis_Data/NCEP/NCEP/clima/'
#ncep_Ts = xr.open_dataset(url + 'surface_gauss/skt')
lat_ncep = ncep_Ts.lat; lon_ncep = ncep_Ts.lon
print( ncep_Ts)

Ts_ncep_annual = ncep_Ts.skt.mean(dim=('lon','time'))

ncep_ulwrf = xr.open_dataset( ncep_url + "other_gauss/ulwrf.ntat.mon.1981-2010.ltm.nc", decode_times=False)
ncep_dswrf = xr.open_dataset( ncep_url + "other_gauss/dswrf.ntat.mon.1981-2010.ltm.nc", decode_times=False)
ncep_uswrf = xr.open_dataset( ncep_url + "other_gauss/uswrf.ntat.mon.1981-2010.ltm.nc", decode_times=False)
#ncep_ulwrf = xr.open_dataset(url + "other_gauss/ulwrf")
#ncep_dswrf = xr.open_dataset(url + "other_gauss/dswrf")
#ncep_uswrf = xr.open_dataset(url + "other_gauss/uswrf")
OLR_ncep_annual = ncep_ulwrf.ulwrf.mean(dim=('lon','time'))
ASR_ncep_annual = (ncep_dswrf.dswrf - ncep_uswrf.uswrf).mean(dim=('lon','time'))

from scipy.stats import linregress
slope, intercept, r_value, p_value, std_err = linregress(Ts_ncep_annual, OLR_ncep_annual)

print( 'Best fit is A = %0.0f W/m2 and B = %0.1f W/m2/degC' %(intercept, slope))


I am working on the file "Lectures/Lecture18 -- Diffusive energy balance model.ipynb".
The first task is:
Discuss these curves...
Suggestion of at least 3 different regimes with different slopes (cold, medium, warm).
Unbiased "best fit" is actually a poor fit over all the intermediate temperatures.
The astute reader will note that...   by taking the zonal average of the data before the regression, we are biasing this estimate toward cold temperatures.  [WHY?]
Let's take these reference values:
$$ A = 210 ~ \text{W m}^{-2}, ~~~ B = 2 ~ \text{W m}^{-2}~^\circ\text{C}^{-1} $$
Note that in the global average, recall $\overline{T_s} = 288 \text{ K} = 15^\circ\text{C}$
And so this parameterization gives
$$ \overline{\text{OLR}} = 210 + 15 \times 2 = 240 ~\text{W m}^{-2} $$
And the observed global mean is $\overline{\text{OLR}} = 239 ~\text{W m}^{-2} $
So this is consistent.

5. The one-dimensional diffusive energy balance model

Putting the above OLR parameterization into our budget equation gives
$$ C(\phi) \frac{\partial T_s}{\partial t} = (1-\alpha) ~ Q - \left( A + B~T_s \right) + \frac{D}{\cos\phi } \frac{\partial }{\partial \phi} \left(   \cos\phi  ~ \frac{\partial T_s}{\partial \phi} \right) $$
This is the equation for a very important and useful simple model of the climate system. It is typically referred to as the (one-dimensional) Energy Balance Model.
(although as we have seen over and over, EVERY climate model is actually an “energy balance model” of some kind)
Also for historical reasons this is often called the Budyko-Sellers model, after Budyko and Sellers who both (independently of each other) published influential papers on this subject in 1969.
Recap: parameters in this model are

C: heat capacity in J m$^{-2}$ ºC$^{-1}$
A: longwave emission at 0ºC in W m$^{-2}$
B: increase in emission per degree, in W m$^{-2}$ ºC$^{-1}$
D: horizontal (north-south) diffusivity of the climate system in W m$^{-2}$ ºC$^{-1}$

We also need to specify the albedo.
Tune albedo formula to match observations
Let's go back to the NCEP Reanalysis data to see how planetary albedo actually varies as a...
Can you write Python code for it?

days = np.linspace(1.,50.)/50 * const.days_per_year
Qann_ncep = climlab.solar.insolation.daily_insolation(lat_ncep, days ).mean(dim='day')
albedo_ncep = 1 - ASR_ncep_annual / Qann_ncep

albedo_ncep_global = np.average(albedo_ncep, weights=np.cos(np.deg2rad(lat_ncep)))

print( 'The annual, global mean planetary albedo is %0.3f' %albedo_ncep_global)
fig,ax = plt.subplots()
ax.plot(lat_ncep, albedo_ncep)
ax.grid();
ax.set_xlabel('Latitude')
ax.set_ylabel('Albedo');


I am working on the file "Lectures/Lecture18 -- Diffusive energy balance model.ipynb".
The first task is:
The upshot: compared to observations, this model has a much too large equator-to-pole temperature gradient, and not enough poleward heat transport!
Apparently we need to increase the diffusivity to get a better fit.

7. Effects of diffusivity in the annual mean EBM

In-class investigation:

Solve the annual-mean EBM (integrate out to equilibrium) over a range of different diffusivity parameters.
Make three plots:
Global-mean temperature as a function of $D$
Equator-to-pole temperature difference $\Delta T$ as a function of $D$
Maximum poleward heat transport $\mathcal{H}_{max}$ as a function of $D$

Choose a value of $D$ that gives a reasonable approximation to observations:
$\Delta T \approx 45$ ºC
$\mathcal{H}_{max} \approx 5.5$ PW

One possible way to do this:
Can you write Python code for it?

Darray = np.arange(0., 2.05, 0.05)

model_list = []
Tmean_list = []
deltaT_list = []
Hmax_list = []
for D in Darray:
    ebm = climlab.EBM_annual(A=210, B=2, a0=0.354, a2=0.25, D=D)
    ebm.integrate_years(20., verbose=False)
    Tmean = ebm.global_mean_temperature()
    deltaT = np.max(ebm.Ts) - np.min(ebm.Ts)
    energy_in = np.squeeze(ebm.ASR - ebm.OLR)
    Htrans = inferred_heat_transport(energy_in, ebm.lat)
    Hmax = np.max(Htrans)
    model_list.append(ebm)
    Tmean_list.append(Tmean)
    deltaT_list.append(deltaT)
    Hmax_list.append(Hmax)

color1 = 'b'
color2 = 'r'

fig = plt.figure(figsize=(8,6))
ax1 = fig.add_subplot(111)
ax1.plot(Darray, deltaT_list, color=color1)
ax1.plot(Darray, Tmean_list, 'b--')
ax1.set_xlabel('D (W m$^{-2}$ K$^{-1}$)', fontsize=14)
ax1.set_xticks(np.arange(Darray[0], Darray[-1], 0.2))
ax1.set_ylabel('$\Delta T$ (equator to pole)', fontsize=14,  color=color1)
for tl in ax1.get_yticklabels():
    tl.set_color(color1)
ax2 = ax1.twinx()
ax2.plot(Darray, Hmax_list, color=color2)
ax2.set_ylabel('Maximum poleward heat transport (PW)', fontsize=14, color=color2)
for tl in ax2.get_yticklabels():
    tl.set_color(color2)
ax1.set_title('Effect of diffusivity on temperature gradient and heat transport in the EBM', fontsize=16)
ax1.grid()

ax1.plot([0.6, 0.6], [0, 140], 'k-');


I am working on the file "Lectures/Lecture18 -- Diffusive energy balance model.ipynb".
The first task is:
We're going to plot the data and the best fit line, but also another line using these values:
Can you write Python code for it?

#  More standard values
A = 210.
B = 2.

fig, ax1 = plt.subplots(figsize=(8,6))
ax1.plot( Ts_ncep_annual, OLR_ncep_annual, 'o' , label='data')
ax1.plot( Ts_ncep_annual, intercept + slope * Ts_ncep_annual, 'k--', label='best fit')
ax1.plot( Ts_ncep_annual, A + B * Ts_ncep_annual, 'r--', label='B=2')
ax1.set_xlabel('Surface temperature (C)', fontsize=16)
ax1.set_ylabel('OLR (W m$^{-2}$)', fontsize=16)
ax1.set_title('OLR versus surface temperature from NCEP reanalysis', fontsize=18)
ax1.legend(loc='upper left')
ax1.grid()


I am working on the file "Lectures/Lecture18 -- Diffusive energy balance model.ipynb".
The first task is:
When $D=0$, every latitude is in radiative equilibrium and the heat transport is zero. As we have already seen, this gives an equator-to-pole temperature gradient much too high.
When $D$ is large, the model is very efficient at moving heat poleward. The heat transport is large and the temperture gradient is weak.
The real climate seems to lie in a sweet spot in between these limits.
It looks like our fitting criteria are met reasonably well with $D=0.6$ W m$^{-2}$ K$^{-1}$
Also, note that the global mean temperature (plotted in dashed blue) is completely insensitive to $D$. Look at the EBM equation and convince yourself that this must be true, since the transport term vanishes from the global average, and there is no non-linear temperature dependence in this model.

8. Summary: parameter values in the diffusive EBM

Our model is defined by the following equation
$$ C \frac{\partial T_s}{\partial t} = (1-\alpha) ~ Q - \left( A + B~T_s \right) + \frac{D}{\cos\phi } \frac{\partial }{\partial \phi} \left(   \cos\phi  ~ \frac{\partial T_s}{\partial \phi} \right) $$
with the albedo given by
$$ \alpha(\phi) = \alpha_0 + \alpha_2 P_2(\sin\phi) $$
We have chosen the following parameter values, which seems to give a reasonable fit to the observed annual mean temperature and energy budget:

$ A = 210 ~ \text{W m}^{-2}$
$ B = 2 ~ \text{W m}^{-2}~^\circ\text{C}^{-1} $
$ a_0 = 0.354$
$ a_2 = 0.25$
$ D = 0.6 ~ \text{W m}^{-2}~^\circ\text{C}^{-1} $

There is one parameter left to choose: the heat capacity $C$. We can't use the annual mean energy budget and temperatures to guide this choice.
[Why?]
We will instead look at seasonally varying models in the next set of notes.

[Back to ATM 623 notebook home](../index.ipynb)

Version information
Can you write Python code for it?

%load_ext version_information
%version_information numpy, scipy, matplotlib, xarray, climlab


I am working on the file "Lectures/Lecture19 -- Seasonal cycle and heat capacity.ipynb".
The first task is:

2. Analytical toy model of the seasonal cycle

What factors determine the above pattern of seasonal temperatures? How large is the winter-to-summer variation in temperature? What is its phasing relative to the seasonal variations in insolation?
We will start to examine this in a very simple zero-dimensional EBM.
Suppose the seasonal cycle of insolation at a point is
$$ Q = Q^* \sin\omega t + Q_0$$
where $\omega = 2\pi ~ \text{year}^{-1}$, $Q_0$ is the annual mean insolation, and $Q^*$ is the amplitude of the seasonal variations.
Here $\omega ~ t=0$ is spring equinox, $\omega~t = \pi/2$ is summer solstice, $\omega~t = \pi$ is fall equinox, and $ \omega ~t = 3 \pi/2$ is winter solstice.
Now suppose the temperature is governed by
$$ C \frac{d T}{d t} = Q - (A + B~T) $$
so that we have a simple model
$$ C \frac{d T}{d t} = Q^* \sin\omega t + Q_0 - (A + B~T) $$
We want to ask two questions:

What is the amplitude of the seasonal temperature variation?
When does the temperature maximum occur?

We will look for an oscillating solution
$$  T(t) = T_0 + T^* \sin(\omega t - \Phi) $$
where $\Phi$ is an unknown phase shift and $T^*$ is the unknown amplitude of seasonal temperature variations.
The annual mean:
Integrate over one year to find
$$ \overline{T} = T_0 $$
$$ Q_0 = A + B ~ \overline{T} $$
so that
$$T_0 = \frac{Q_0 - A}{B} $$
The seasonal problem
Now we need to solve for $T^*$ and $\Phi$.
Take the derivative
$$  \frac{d T}{dt} = T^* \omega \cos(\omega t - \Phi) $$
and plug into the model equation to get
\begin{align}
C~ T^ \omega \cos(\omega t - \Phi) &=  Q^ \sin\omega t + Q_0  \
                                    & - \left( A + B~(T_0 + T^ \sin(\omega t - \Phi) )\right)
\end{align*}
Subtracting out the annual mean leaves us with
$$ C~ T^ \omega \cos(\omega t - \Phi) =  Q^ \sin\omega t  - B ~ T^* \sin(\omega t - \Phi)  $$
Zero heat capacity: the radiative equilibrium solution
It's instructive to first look at the case with $C=0$, which means that the system is not capable of storing heat,...
Can you write Python code for it?

omega = 2*np.pi / const.seconds_per_year
omega

B = 2.
Hw = np.linspace(0., 100.)
Ctilde = const.cw * const.rho_w * Hw * omega / B
amp = 1./((Ctilde**2+1)*np.cos(np.arctan(Ctilde)))
Phi = np.arctan(Ctilde)

color1 = 'b'
color2 = 'r'

fig = plt.figure(figsize=(8,6))
ax1 = fig.add_subplot(111)
ax1.plot(Hw, amp, color=color1)
ax1.set_xlabel('water depth (m)', fontsize=14)
ax1.set_ylabel('Seasonal amplitude ($Q^* / B$)', fontsize=14,  color=color1)
for tl in ax1.get_yticklabels():
    tl.set_color(color1)
ax2 = ax1.twinx()
ax2.plot(Hw, np.rad2deg(Phi), color=color2)
ax2.set_ylabel('Seasonal phase shift (degrees)', fontsize=14, color=color2)
for tl in ax2.get_yticklabels():
    tl.set_color(color2)
ax1.set_title('Dependence of seasonal cycle phase and amplitude on water depth', fontsize=16)
ax1.grid()

ax1.plot([2.5, 2.5], [0, 1], 'k-');


I am working on the file "Lectures/Lecture19 -- Seasonal cycle and heat capacity.ipynb".
The first task is:
And plot the seasonal temperature cycle same as we did above:
Can you write Python code for it?

fig = plt.figure( figsize=(16,5) )
Tmax_highobl = 125; Tmin_highobl = -Tmax_highobl; delT_highobl = 10
clevels_highobl = np.arange(Tmin_highobl, Tmax_highobl+delT_highobl, delT_highobl)
for n in range(num_depths):
    ax = fig.add_subplot(1,num_depths,n+1)
    cax = ax.contourf( 4*np.arange(num_steps_per_year), lat, Tyear_highobl[:,:,n],
        levels=clevels_highobl, cmap=plt.cm.seismic, vmin=Tmin_highobl, vmax=Tmax_highobl )
    cbar1 = plt.colorbar(cax)
    ax.set_title('water depth = %.0f m' %models[n].param['water_depth'], fontsize=20 )
    ax.set_xlabel('Days of year', fontsize=14 )
    ax.set_ylabel('Latitude', fontsize=14 )


I am working on the file "Lectures/Lecture19 -- Seasonal cycle and heat capacity.ipynb".
The first task is:
Note that the temperature range is much larger than for the Earth-like case above (but same contour interval, 10 degC).
Why is the temperature so uniform in the north-south direction with 50 meters of water?
To see the reason, let's plot the annual mean insolation at 90º obliquity, alongside the present-day annual mean insolation:
Can you write Python code for it?

lat2 = np.linspace(-90, 90, 181)
days = np.linspace(1.,50.)/50 * const.days_per_year
Q_present = climlab.solar.insolation.daily_insolation( lat2, days )
Q_highobl = climlab.solar.insolation.daily_insolation( lat2, days, orb_highobl )
Q_present_ann = np.mean( Q_present, axis=1 )
Q_highobl_ann = np.mean( Q_highobl, axis=1 )

fig, ax = plt.subplots()
ax.plot( lat2, Q_present_ann, label='Earth' )
ax.plot( lat2, Q_highobl_ann, label='90deg obliquity' )
ax.grid()
ax.legend(loc='lower center')
ax.set_xlabel('Latitude', fontsize=14 )
ax.set_ylabel('W m$^{-2}$', fontsize=14 )
ax.set_title('Annual mean insolation for two different obliquities', fontsize=16)


I am working on the file "Lectures/Lecture19 -- Seasonal cycle and heat capacity.ipynb".
The first task is:
Repeat the same procedure to calculate and store temperature throughout one year, after letting the models run out to equilibrium.
Can you write Python code for it?

Tann_highobl = np.empty( [lat.size, num_depths] )
models_highobl = []

for n in range(num_depths):
    model = climlab.EBM_seasonal(water_depth=water_depths[n],
                                 orb=orb_highobl,
                                 **param)
    models_highobl.append(model)
    models_highobl[n].integrate_years(40., verbose=False )
    models_highobl[n].integrate_years(1., verbose=False)
    Tann_highobl[:,n] = np.squeeze(models_highobl[n].timeave['Ts'])

Tyear_highobl = np.empty([lat.size, num_steps_per_year, num_depths])
for n in range(num_depths):
    for m in range(num_steps_per_year):
        models_highobl[n].step_forward()
        Tyear_highobl[:,m,n] = np.squeeze(models_highobl[n].Ts)


I am working on the file "Lectures/Lecture19 -- Seasonal cycle and heat capacity.ipynb".
The first task is:
The blue curve in this figure is in phase with the insolation.

3. Exploring the amplitude of the seasonal cycle with an EBM

Something important is missing from this toy model: heat transport!
The amplitude of the seasonal cycle of insolation increases toward the poles, but the seasonal temperature variations are partly mitigated by heat transport from lower, warmer latitudes.
Our 1D diffusive EBM is the appropriate tool for exploring this further.
We are looking at the 1D (zonally averaged) energy balance model with diffusive heat transport. The equation is
$$ C \frac{\partial T_s}{\partial t} = (1-\alpha) ~ Q - \left( A + B~T_s \right) + \frac{D}{\cos\phi } \frac{\partial }{\partial \phi} \left(   \cos\phi  ~ \frac{\partial T_s}{\partial \phi} \right) $$
with the albedo given by
$$ \alpha(\phi) = \alpha_0 + \alpha_2 P_2(\sin\phi) $$
and we will use
climlab.EBM_seasonal
to solve this model numerically.
One handy feature of climlab process code: the function integrate_years() automatically calculates the time averaged temperature. So if we run it for exactly one year, we get the annual mean temperature (and many other diagnostics) saved in the dictionary timeave.
We will look at the seasonal cycle of temperature in three different models with different heat capacities (which we express through an equivalent depth of water in meters).
All other parameters will be as chosen in Lecture 16 (which focussed on tuning the EBM to the annual mean energy budget).
Can you write Python code for it?

#  for convenience, set up a dictionary with our reference parameters
param = {'A':210, 'B':2, 'a0':0.354, 'a2':0.25, 'D':0.6}
param

#  We can pass the entire dictionary as keyword arguments using the ** notation
model1 = climlab.EBM_seasonal(**param, name='Seasonal EBM')
print( model1)


I am working on the file "Lectures/Lecture19 -- Seasonal cycle and heat capacity.ipynb".
The first task is:
The blue line shows the amplitude of the seasonal cycle of temperature, expressed as a fraction of its maximum value $\frac{Q^*}{B}$ (the value that would occur if the system had zero heat capacity so that temperatures were always in radiative equilibrium with the instantaneous insolation).
The red line shows the phase lag (in degrees) of the temperature cycle relative to the insolation cycle.
The vertical black line indicates 2.5 meters of water, which is the heat capacity of the atmosphere and thus our effective lower bound on total column heat capacity.
The seasonal phase shift
Even for the driest surfaces the phase shift is about 45º and the amplitude is half of its theoretical maximum. For most wet surfaces the cycle is damped out and delayed further.
Of course we are already familiar with this phase shift from our day-to-day experience. Our calendar says that summer "begins" at the solstice and last until the equinox.
Can you write Python code for it?

fig, ax = plt.subplots()
years = np.linspace(0,2)
Harray = np.array([0., 2.5, 10., 50.])
for Hw in Harray:
    Ctilde = const.cw * const.rho_w * Hw * omega / B
    Phi = np.arctan(Ctilde)
    ax.plot(years, np.sin(2*np.pi*years - Phi)/np.cos(Phi)/(1+Ctilde**2), label=Hw)
ax.set_xlabel('Years', fontsize=14)
ax.set_ylabel('Seasonal amplitude ($Q^* / B$)', fontsize=14)
ax.set_title('Solution of toy seasonal model for several different water depths', fontsize=14)
ax.legend(); ax.grid()


I am working on the file "Lectures/Lecture19 -- Seasonal cycle and heat capacity.ipynb".
The first task is:
There is no automatic function in the climlab code to keep track of minimum and maximum temperatures (though we might add that in the future!)
Instead we'll step through one year "by hand" and save all the temperatures.
Can you write Python code for it?

num_steps_per_year = int(model1.time['num_steps_per_year'])
Tyear = np.empty((lat.size, num_steps_per_year, num_depths))
for n in range(num_depths):
    for m in range(num_steps_per_year):
        models[n].step_forward()
        Tyear[:,m,n] = np.squeeze(models[n].Ts)


I am working on the file "Lectures/Lecture19 -- Seasonal cycle and heat capacity.ipynb".
The first task is:
Though this is a bit misleading, because our model prescribes an increase in albedo from the equator to the pole. So the absorbed shortwave gradients look even more different.
If you are interested in how ice-albedo feedback might work on a high-obliquity planet with a cold equator, then I suggest you take a look at this paper:
Rose, Cronin and Bitz (2017): Ice Caps and Ice Belts: The Effects of Obliquity on Ice−Albedo Feedback, The Astrophysical Journal 846, doi:10.3847/1538-4357/aa8306
<div class="alert alert-success">

[Back to ATM 623 notebook home](../index.ipynb)

</div>

Version information
Can you write Python code for it?

%load_ext version_information
%version_information numpy, xarray, climlab


I am working on the file "Lectures/Lecture19 -- Seasonal cycle and heat capacity.ipynb".
The first task is:
Which one looks more realistic? Depends a bit on where you look. But overall, the observed seasonal cycle matches the 10 meter case best. The effective heat capacity governing the seasonal cycle of the zonal mean temperature is closer to 10 meters of water than to either 2 or 50 meters.
Making an animation of the EBM solutions
Let's animate the seasonal cycle of insolation and temperature in our models with the three different water depths
Can you write Python code for it?

def initial_figure(models):
    fig, axes = plt.subplots(1,len(models), figsize=(15,4))
    lines = []
    for n in range(len(models)):
        ax = axes[n]
        c1 = 'b'
        Tsline = ax.plot(lat, models[n].Ts, c1)[0]
        ax.set_title('water depth = %.0f m' %models[n].param['water_depth'], fontsize=20 )
        ax.set_xlabel('Latitude', fontsize=14 )
        if n is 0:
            ax.set_ylabel('Temperature', fontsize=14, color=c1 )
        ax.set_xlim([-90,90])
        ax.set_ylim([-60,60])
        for tl in ax.get_yticklabels():
            tl.set_color(c1)
        ax.grid()

        c2 = 'r'
        ax2 = ax.twinx()
        Qline = ax2.plot(lat, models[n].insolation, c2)[0]
        if n is 2:
            ax2.set_ylabel('Insolation (W m$^{-2}$)', color=c2, fontsize=14)
        for tl in ax2.get_yticklabels():
            tl.set_color(c2)
        ax2.set_xlim([-90,90])
        ax2.set_ylim([0,600])
        lines.append([Tsline, Qline])
    return fig, axes, lines

def animate(step, models, lines):
    for n, ebm in enumerate(models):
        ebm.step_forward()
        #  The rest of this is just updating the plot
        lines[n][0].set_ydata(ebm.Ts)
        lines[n][1].set_ydata(ebm.insolation)
    return lines

#  Plot initial data
fig, axes, lines = initial_figure(models)

#  Some imports needed to make and display animations
from IPython.display import HTML
from matplotlib import animation

num_steps = int(models[0].time['num_steps_per_year'])
ani = animation.FuncAnimation(fig, animate,
        frames=num_steps,
        interval=80,
        fargs=(models, lines),
        )

HTML(ani.to_html5_video())


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Alternatively, we can chose to import all symbols (functions and variables) in a module to the current namespace (so that we don't need to use the prefix "math." every time we use something from the math module:
Can you write Python code for it?

from math import *

x = cos(2 * pi)

print(x)


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
And using the function help we can get a description of each function (almost .. not all functions have docstrings, as they are technically called, but the vast majority of functions are documented this way).
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Assignment
The assignment operator in Python is =. Python is a dynamically typed language, so we do not need to specify the type of a variable when we create one.
Assigning a value to a new variable creates the variable:
Can you write Python code for it?

# variable assignments
x = 1.0
my_variable = 12.2


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Character encoding
The standard character encoding is ASCII, but we can use any other encoding, for example UTF-8. To specify that UTF-8 is used we include the special line
# -*- coding: UTF-8 -*-

at the top of the file.
Can you write Python code for it?

%%sh
cat ../../Scripts/hello-world-in-swedish.py

!python ../../Scripts/hello-world-in-swedish.py


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Classes
Classes are the key features of object-oriented programming. A class is a structure for representing an object and the operations that can be performed on the object.
In Python a class can contain attributes (variables) and methods (functions).
A class is defined almost like a function, but using the class keyword, and the class definition usually contains a number of class method definitions (a function in a class).

Each class method should have an argument self as its first argument. This object is a self-reference.

Some class method names have special meaning, for example:

__init__: The name of the method that is invoked when the object is first created.
__str__ : A method that is invoked when a simple string representation of the class is needed, as for example when printed.
There are many more, see http://docs.python.org/2/reference/datamodel.html#special-method-names
Can you write Python code for it?

class Point:
    """
    Simple class for representing a point in a Cartesian coordinate system.
    """

    def __init__(self, x, y):
        """
        Create a new Point at x, y.
        """
        self.x = x
        self.y = y

    def translate(self, dx, dy):
        """
        Translate the point by dx and dy in the x and y direction.
        """
        self.x += dx
        self.y += dy

    def __str__(self):
        return("Point at [%f, %f]" % (self.x, self.y))


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Complex variables cannot be cast to floats or integers. We need to use z.real or z.imag to extract the part of the complex number we want:
Can you write Python code for it?

y = bool(z.real)

print(z.real, " -> ", y, type(y))

y = bool(z.imag)

print(z.imag, " -> ", y, type(y))


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Control Flow
Conditional statements: if, elif, else
The Python syntax for conditional execution of code uses the keywords if, elif (else if), else:
Can you write Python code for it?

statement1 = False
statement2 = False

if statement1:
    print("statement1 is True")

elif statement2:
    print("statement2 is True")

else:
    print("statement1 and statement2 are False")


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Counter
Turns a sequenc of values into a defaultdict(int)-like object mappings keys to counts ( good for histograms )
Can you write Python code for it?

import collections as coll
c = coll.Counter([0,1,2,0])
print c

document = "This is a test document with a lot of different words but at least one duplicate".split(" ")
word_counts = coll.Counter(document)
print word_counts


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Dictionaries
Dictionaries are also like lists, except that each element is a key-value pair. The syntax for dictionaries is {key1 : value1, ...}:
Can you write Python code for it?

params = {"parameter1" : 1.0,
          "parameter2" : 2.0,
          "parameter3" : 3.0,}

print(type(params))
print(params)

print("parameter1 = " + str(params["parameter1"]))
print("parameter2 = " + str(params["parameter2"]))
print("parameter3 = " + str(params["parameter3"]))

params["parameter1"] = "A"
params["parameter2"] = "B"

# add a new entry
params["parameter4"] = "D"

print("parameter1 = " + str(params["parameter1"]))
print("parameter2 = " + str(params["parameter2"]))
print("parameter3 = " + str(params["parameter3"]))
print("parameter4 = " + str(params["parameter4"]))


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Elements in a list do not all have to be of the same type:
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Exceptions
In Python errors are managed with a special language construct called "Exceptions". When errors occur exceptions can be raised, which interrupts the normal program flow and fallback to somewhere else in the code where the closest try-except statement is defined.
To generate an exception we can use the raise statement, which takes an argument that must be an instance of the class BaseException or a class derived from it.
Can you write Python code for it?

raise Exception("description of the error")


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
For the first time, here we encounted a peculiar and unusual aspect of the Python programming language: Program blocks are defined by their indentation level.
Compare to the equivalent C code:
if (statement1)
{
    printf("statement1 is True\n");
}
else if (statement2)
{
    printf("statement2 is True\n");
}
else
{
    printf("statement1 and statement2 are False\n");
}

In C blocks are defined by the enclosing curly brakets { and }. And the level of indentation (white space before the code statements) does not matter (completely optional).
But in Python, the extent of a code block is defined by the indentation level (usually a tab or say four white spaces). This means that we have to be careful to indent our code correctly, or else we will get syntax errors.
Examples:
Can you write Python code for it?

statement1 = statement2 = True

if statement1:
    if statement2:
        print("both statement1 and statement2 are True")

# Bad indentation!
if statement1:
    if statement2:
    print("both statement1 and statement2 are True")  # this line is not properly indented

statement1 = False

if statement1:
    print("printed if statement1 is True")

    print("still inside the if block")

if statement1:
    print("printed if statement1 is True")

print("now outside the if block")


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Fundamental types
Can you write Python code for it?

# integers
x = 1
type(x)

# float
x = 1.0
type(x)

# boolean
b1 = True
b2 = False

type(b1)

# complex numbers: note the use of `j` to specify the imaginary part
x = 1.0 - 1.0j
type(x)

print(x)

print(x.real, x.imag)


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Heads up MATLAB users: Indexing start at 0!
We can extract a part of a string using the syntax [start:stop], which extracts characters between index start and stop -1 (the character at index stop is not included):
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Heads up MATLAB users: Indexing starts at 0!
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
If we assign a new value to a variable, its type can change.
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
If we explicitly list the name of the arguments in the function calls, they do not need to come in the same order as in the function definition. This is called keyword arguments, and is often very useful in functions that takes a lot of optional arguments.
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
If we make changes to the code in mymodule.py, we need to reload it using reload:
Can you write Python code for it?

reload(mymodule)  # works only in python 2


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
If we omit either (or both) of start or stop from [start:stop], the default is the beginning and the end of the string, respectively:
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Insert an element at an specific index using insert
Can you write Python code for it?

l.insert(0, "i")
l.insert(1, "n")
l.insert(2, "s")
l.insert(3, "e")
l.insert(4, "r")
l.insert(5, "t")

print(l)


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
List
Lists are very similar to strings, except that each element can be of any type.
The syntax for creating lists in Python is [...]:
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
List Comprehensions
Can you write Python code for it?

even_numbers = [x for x in range(5) if x %2 == 0]
squares = [x * x  for x in range(5)]
even_squared = [x*x for x in even_numbers]

print even_squared

square_dict = { x: x*x for x in range(5) }
print square_dict


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
List comprehensions: Creating lists using for loops:
A convenient and compact way to initialize lists:
Can you write Python code for it?

l1 = [x**2 for x in range(0,5)]

print(l1)


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Lists play a very important role in Python. For example they are used in loops and other flow control structures (discussed below). There are a number of convenient functions for generating lists of various types, for example the range function:
Can you write Python code for it?

start = 10
stop = 30
step = 2

range(start, stop, step)

# in python 3 range generates an interator, which can be converted to a list using 'list(...)'.
# It has no effect in python 2
list(range(start, stop, step))

list(range(-10, 10))

s

# convert a string to a list by type casting:
s2 = list(s)

s2

# sorting lists
s2.sort()

print(s2)


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Looking at what a module contains, and its documentation
Once a module is imported, we can list the symbols it provides using the dir function:
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Loops
In Python, loops can be programmed in a number of different ways. The most common is the for loop, which is used together with iterable objects, such as lists. The basic syntax is:
for loops:
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Note that calling class methods can modifiy the state of that particular class instance, but does not effect other class instances or any global variables.
That is one of the nice things about object-oriented design: code such as functions and related variables are grouped in separate and independent entities.
Modules
One of the most important concepts in good programming is to reuse code and avoid repetitions.
The idea is to write functions and classes with a well-defined purpose and scope, and reuse these instead of repeating similar code in different part of a program (modular programming). The result is usually that readability and maintainability of a program is greatly improved. What this means in practice is that our programs have fewer bugs, are easier to extend and debug/troubleshoot.
Python supports modular programming at different levels. Functions and classes are examples of tools for low-level modular programming. Python modules are a higher-level modular programming construct, where we can collect related variables, functions and classes in a module. A python module is defined in a python file (with file-ending .py), and it can be made accessible to other Python modules and programs using the import statement.
Consider the following example: the file mymodule.py contains simple example implementations of a variable, function and a class:
Can you write Python code for it?

%%file mymodule.py
"""
Example of a python module. Contains a variable called my_variable,
a function called my_function, and a class called MyClass.
"""

my_variable = 0

def my_function():
    """
    Example function
    """
    return my_variable

class MyClass:
    """
    Example class.
    """

    def __init__(self):
        self.variable = my_variable

    def set_variable(self, new_value):
        """
        Set self.variable to a new value
        """
        self.variable = new_value

    def get_variable(self):
        return self.variable


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Note that the print("done") statement is not part of the while loop body because of the difference in indentation.
Functions
A function in Python is defined using the keyword def, followed by a function name, a signature within parentheses (), and a colon :. The following code, with one additional level of indentation, is the function body.
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Note: The / operator always performs a floating point division in Python 3.x.
This is not true in Python 2.x, where the result of / is always an integer if the operands are integers.
to be more specific, 1/2 = 0.5 (float) in Python 3.x, and 1/2 = 0 (int) in Python 2.x (but 1.0/2 = 0.5 in Python 2.x).

The boolean operators are spelled out as the words and, not, or.
Can you write Python code for it?

True and False

not False

True or False


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Optionally, but highly recommended, we can define a so called "docstring", which is a description of the functions purpose and behaivor. The docstring should follow directly after the function definition, before the code in the function body.
Can you write Python code for it?

def func1(s):
    """
    Print a string 's' and tell how many characters it has
    """

    print(s + " has " + str(len(s)) + " characters")

help(func1)

func1("test")


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Other than these two optional lines in the beginning of a Python code file, no additional code is required for initializing a program.
Jupyter notebooks ( or old ipython notebooks)
This file - an IPython notebook -  does not follow the standard pattern with Python code in a text file. Instead, an IPython notebook is stored as a file in the JSON format. The advantage is that we can mix formatted text, Python code and code output. It requires the IPython notebook server to run it though, and therefore isn't a stand-alone Python program as described above. Other than that, there is no difference between the Python code that goes into a program file or an IPython notebook.
Modules
Most of the functionality in Python is provided by modules. The Python Standard Library is a large collection of modules that provides cross-platform implementations of common facilities such as access to the operating system, file I/O, string management, network communication, and much more.
References

The Python Language Reference: http://docs.python.org/2/reference/index.html
The Python Standard Library: http://docs.python.org/2/library/

To use a module in a Python program it first has to be imported. A module can be imported using the import statement. For example, to import the module math, which contains many standard mathematical functions, we can do:
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Remove first element with specific value using 'remove'
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
See help(list) for more details, or read the online documentation
Tuples
Tuples are like lists, except that they cannot be modified once created, that is they are immutable.
In Python, tuples are created using the syntax (..., ..., ...), or even ..., ...:
Can you write Python code for it?

point = (10, 20)

print(point, type(point))

point = 10, 20

print(point, type(point))


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
So use that to make you code easier to read
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Sorting
Can you write Python code for it?

x = [4,1,2,3]
y=sorted(x)
x.sort()
print "X="+str(x)
print "y="+str(y)


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
This includes the whole module and makes it available for use later in the program. For example, we can do:
Can you write Python code for it?

import math

x = math.cos(2 * math.pi)

print(x)


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
This technique is useful for example when we want to pass a simple function as an argument to another function, like this:
Can you write Python code for it?

# map is a built-in python function
map(lambda x: x**2, range(-3,4))

# in python 3 we can use `list(...)` to convert the iterator to an explicit list
list(map(lambda x: x**2, range(-3,4)))


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
To create a new instance of a class:
Can you write Python code for it?

p1 = Point(0, 0) # this will invoke the __init__ method in the Point class

print(p1)         # this will invoke the __str__ method


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
To get information about the error, we can access the Exception class instance that describes the exception by using for example:
except Exception as e:
Can you write Python code for it?

try:
    print("test")
    # generate an error: the variable test is not defined
    print(test)
except Exception as e:
    print("Caught an exception:" + str(e))


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
To invoke a class method in the class instance p:
Can you write Python code for it?

p2 = Point(1, 1)

p1.translate(0.25, 1.5)

print(p1)
print(p2)


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
To iterate over key-value pairs of a dictionary:
Can you write Python code for it?

for key, value in params.items():
    print(key + " = " + str(value))


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
Type casting
Can you write Python code for it?

x = 1.5

print(x, type(x))

x = int(x)

print(x, type(x))

z = complex(x)

print(z, type(z))

x = float(z)


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
We can also define the step size using the syntax [start:end:step] (the default value for step is 1, as we saw above):
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
We can also use the help function directly on modules: Try
help(math)

Some very useful modules form the Python standard library are os, sys, math, shutil, re, subprocess, multiprocessing, threading.
A complete lists of standard modules for Python 2 and Python 3 are available at http://docs.python.org/2/library/ and http://docs.python.org/3/library/, respectively.
Whitespacing formatting
Python uses indents and not bracing to delimit blocks of code
Makes code readable but it means you must be careful about your formatting
Can you write Python code for it?

for i in [1,2,3,4]:
    print i
print "done looping"


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
We can also use the isinstance method for testing types of variables:
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
We can index a character in a string using []:
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
We can modify lists by assigning new values to elements in the list. In technical jargon, lists are mutable.
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
We can return multiple values from a function using tuples (see above):
Can you write Python code for it?

def powers(x):
    """
    Return a few powers of x.
    """
    return x ** 2, x ** 3, x ** 4

powers(3)

x2, x3, x4 = powers(3)

print(x3)


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
We can use the same slicing techniques to manipulate lists as we could use on strings:
Can you write Python code for it?


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
White spacing is ignored inside parenteses and brackets:
Can you write Python code for it?

long_winded_computation = (1+2+ 3 + 4 +   5+ 6
                          + 7 + 8 + 9 + 10 + 11+

                          13 + 14 + 15)
long_winded_computation


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
You can create short anonymous fuctions or lambdas or even assign lambdas to variables but better to use a def
Can you write Python code for it?

apply_to_one(lambda x: x + 4 )

another_double = lambda x: 2 * x
def yet_another_double(x): return 2 * x


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
You need to recreate the the lazy generator to use it a second time or use a list
Can you write Python code for it?

### randomness

import random as rand
[rand.random() for _ in range(4)]

### regular expressions

### Object-oriented programming

### Functional Tools

### enumerate

### Zip and argument unpacking

### args and kwargs


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
built in magic commands start with
A good list of the commands are found in:
https://ipython.org/ipython-doc/3/interactive/magics.html
Can you write Python code for it?

%%sh
cat ../../Scripts/hello-world.py

!python ..\..\Scripts\hello-world.py


I am working on the file "Lectures/Lecture2-Jupyter_and_python/Lecture-2-Introduction-to-Python-Programming 2017.ipynb".
The first task is:
while loops:
Can you write Python code for it?

i = 0

while i < 5:
    print(i)

    i = i + 1

print("done")


I am working on the file "Lectures/Lecture20 -- Numerical methods for diffusion models.ipynb".
The first task is:
A smooth example
Suppose we have an initial $u$ field that has a local maximum in the interior.
The gaussian (bell curve) function is a convenient way to create such a field.
Can you write Python code for it?

def gaussian(x, mean, std):
    return np.exp(-(x-mean)**2/(2*std**2))/np.sqrt(2*np.pi*std**2)

K = 0.01
u = gaussian(x, 0.5, 0.08)
dudt = diffusion(u, deltax, K=K)
fig, ax = plt.subplots(1)
ax.plot(x, u, label='$u(x)$')
ax.plot(x, dudt, label='$du/dt$')
ax.legend()


I am working on the file "Lectures/Lecture20 -- Numerical methods for diffusion models.ipynb".
The first task is:
Contents

The one-dimensional diffusion equation
Discretizing the diffusion operator in space
Coding the discretized diffusion operator in numpy
Discretizing the time derivative
Stability analysis of the FTCS scheme
Numerical tests with a shorter timestep
The need for a more efficient method
Implicit time method
Your homework assignment

1. The one-dimensional diffusion equation

Suppose that a quantity $u(x)$ is mixed down-gradient by a diffusive process.
The diffusive flux is
$$ F = - K \frac{\partial u}{\partial x} $$
There will be local changes in $u$ wherever this flux is convergent or divergent:
$$ \frac{\partial u}{\partial t} = - \frac{\partial F}{\partial x} $$
Putting this together gives the classical diffusion equation in one dimension
$$ \frac{\partial u}{\partial t} = \frac{\partial}{\partial x} \left( K \frac{\partial u}{\partial x} \right) $$
For simplicity, we are going to limit ourselves to Cartesian geometry rather than meridional diffusion on a sphere.
We will also assume here that $K$ is a constant, so our governing equation is
$$ \frac{\partial u}{\partial t} = K \frac{\partial^2 u}{\partial x^2} $$
This equation represents a time-dependent diffusion process. It is an initial-boundary value problem. We want to integrate the model forward in time to model the changes in the field $u(x)$.

2. Discretizing the diffusion operator in space

Solving a differential equation on a computer always requires some approximation to represent the continuous function $u(x,t)$ and its derivatives in terms of discrete quantities (arrays of numbers).
We have already dealt with simple discretization of the time derivative back in Lecture 2. We used the forward Euler method to step all our of radiation models forward in time so far.
Some notation for discretization of $u(x,t)$
We will discretize time and space on grids
$$ x_j , ~~~ t^n $$
so that
$$ u_j^n = u(x_j, ~t^n) $$
Discretizing the diffusive flux
The governing equation can be written in terms of the...
Can you write Python code for it?

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import display, Math, Latex


I am working on the file "Lectures/Lecture20 -- Numerical methods for diffusion models.ipynb".
The first task is:
Here's one way to implement the finite difference, using array indexing.
Can you write Python code for it?


I am working on the file "Lectures/Lecture20 -- Numerical methods for diffusion models.ipynb".
The first task is:
Hopefully this makes sense. The diffusion is acting to smooth out $u$ by reducing the peak and increasing $u$ on the flanks of the gaussian bump.
Some non-smooth examples
Use a random number generator to create some noisy initial conditions.
Can you write Python code for it?

fig = plt.figure(figsize=(10,8))
for n in range(4):
    u = np.random.random(J)
    dudt = diffusion(u, deltax, K)
    ax = fig.add_subplot(2,2,n+1)
    ax.plot(x, u)
    ax.plot(x, dudt)


I am working on the file "Lectures/Lecture20 -- Numerical methods for diffusion models.ipynb".
The first task is:
Success! The graph now looks like a smoother (higher resolution) version of our first integration with the coarser grid.
But at a big cost:  our calculation required 4 times more timesteps to do the same integration.
The total increase in computational cost was actally a factor of 8 to get a factor of 2 increase in spatial resolution.

7. The need for a more efficient method

In practice the condition
$$ \Delta t \le \frac{\Delta x^2}{2 K} $$
is often too restrictive to be practical!
Consider our diffusive EBM. Suppose we want a spatial resolution of 1º latitude. Then we have 180 grid points from pole to pole, and our physical length scale is
$$ \Delta x \approx 10^5 \text{m} $$
We were using a diffusivity of $D = 0.6 ~ \text{W m}^{-2}~\text{K}^{-1}$ and a heat capacity of $C = 4 \times 10^7 ~ \text{J m}^{-2} ~\text{K}^{-1}$ (for 10 m of water, see Lecture 17).
Accounting for the spherical geometry in our EBM, this translates to
$$ K = \frac{2 \pi a^2 D}{C} = \frac{2 \pi ~ (6.4 \times 10^6 ~\text{m})^2 ~(0.6 ~ \text{W m}^{-2}~\text{K}^{-1})}{4 \times 10^7 ~ \text{J m}^{-2} ~\text{K}^{-1}} \approx 4 \times 10^{6} ~ \text{m}^2 ~ \text{s}^{-1} $$
Recall that this is the diffusivity associated with the large-scale motion of the atmosphere (mostly). If we take a typical velocity scale for a mid-latitude eddy, $V \approx 20~\text{m s}^{-1}$, and a typical length scale for that eddy, $L \approx 2000~\text{km}$, the diffusivity then scales as
$$ K = V~ L = 4 \times 10^{6} ~ \text{m}^2 ~ \text{s}^{-1} $$
Using these numbers the stability condition is roughly
$$ \Delta t \le 10^3 ~\text{s}$$
which is less than one hour!
And if we wanted to double the resolution to 0.5º, we would need a timestep of just a few minutes.
This can be a very onerous requirement for a model that would like to integrate out for many years.  We can do better, but we need a different time discretization!

8. Implicit time method

With numerical methods for partial differential equations, it often...
Can you write Python code for it?

%load_ext version_information
%version_information numpy, matplotlib


I am working on the file "Lectures/Lecture20 -- Numerical methods for diffusion models.ipynb".
The first task is:
The fluxes will be solved on the staggered grid with 21 points.
$u$ will be solved on the 20 point grid.
Can you write Python code for it?

xstag = np.linspace(0., 1., J+1)
x = xstag[:-1] + deltax/2
print( x)

u = np.zeros_like(x)


I am working on the file "Lectures/Lecture20 -- Numerical methods for diffusion models.ipynb".
The first task is:
The numerics were easy to implement, and the scheme seems to work very well! The results are physically sensible.
Now, suppose that you wanted to double the spatial resolution
Try setting $J=40$ and repeat the above procedure.
What happens?
Can you write Python code for it?

#  double the resolution
scaling_factor = 2
J = J1 * scaling_factor
deltax = 1./J
xstag = np.linspace(0., 1., J+1)
x = xstag[:-1] + deltax/2

u = gaussian(x, 0.5, 0.08)
for n in range(niter):
    u = step_forward(u, deltax, deltat1, K)
    plt.plot(x, u, label=n)
plt.legend()


I am working on the file "Lectures/Lecture20 -- Numerical methods for diffusion models.ipynb".
The first task is:
The time tendency of $u$ is just the convergence of this flux, which requires one more finite difference:
Can you write Python code for it?

def diffusion(u, deltax, K=1):
    #  compute flux
    F = diffusive_flux(u, deltax, K)
    #  take convergence of flux
    return -np.diff(F) / deltax


I am working on the file "Lectures/Lecture21 -- Ice albedo feedback in the EBM.ipynb".
The first task is:

2. Polar-amplified warming in the EBM

Add a small radiative forcing
The equivalent of doubling CO2 in this model is something like
$$ A \rightarrow A - \delta A $$
where $\delta A = 4$ W m$^{-2}$.
Can you write Python code for it?

deltaA = 4.

model2 = climlab.process_like(model1)
model2.subprocess['LW'].A = param['A'] - deltaA
model2.integrate_years(5, verbose=False)

plt.plot(model1.lat, model1.Ts)
plt.plot(model2.lat, model2.Ts)


I am working on the file "Lectures/Lecture21 -- Ice albedo feedback in the EBM.ipynb".
The first task is:
Because we provided a parameter ai for the icy albedo, our model now contains several sub-processes contained within the process called albedo. Together these implement the step-function formula above.
The process called iceline simply looks for grid cells with temperature below $T_f$.
Can you write Python code for it?

print( model1.param)

def ebm_plot( model, figsize=(8,12), show=True ):
    '''This function makes a plot of the current state of the model,
    including temperature, energy budget, and heat transport.'''
    templimits = -30,35
    radlimits = -340, 340
    htlimits = -7,7
    latlimits = -90,90
    lat_ticks = np.arange(-90,90,30)

    fig = plt.figure(figsize=figsize)

    ax1 = fig.add_subplot(3,1,1)
    ax1.plot(model.lat, model.Ts)
    ax1.set_xlim(latlimits)
    ax1.set_ylim(templimits)
    ax1.set_ylabel('Temperature (deg C)')
    ax1.set_xticks( lat_ticks )
    ax1.grid()

    ax2 = fig.add_subplot(3,1,2)
    ax2.plot(model.lat, model.ASR, 'k--', label='SW' )
    ax2.plot(model.lat, -model.OLR, 'r--', label='LW' )
    ax2.plot(model.lat, model.net_radiation, 'c-', label='net rad' )
    ax2.plot(model.lat, model.heat_transport_convergence, 'g--', label='dyn' )
    ax2.plot(model.lat, model.net_radiation.squeeze()
                        + model.heat_transport_convergence, 'b-', label='total' )
    ax2.set_xlim(latlimits)
    ax2.set_ylim(radlimits)
    ax2.set_ylabel('Energy budget (W m$^{-2}$)')
    ax2.set_xticks( lat_ticks )
    ax2.grid()
    ax2.legend()

    ax3 = fig.add_subplot(3,1,3)
    ax3.plot(model.lat_bounds, model.heat_transport)
    ax3.set_xlim(latlimits)
    ax3.set_ylim(htlimits)
    ax3.set_ylabel('Heat transport (PW)')
    ax3.set_xlabel('Latitude')
    ax3.set_xticks( lat_ticks )
    ax3.grid()

    return fig

model1.integrate_years(5)
f = ebm_plot(model1)

model1.icelat


I am working on the file "Lectures/Lecture21 -- Ice albedo feedback in the EBM.ipynb".
The first task is:
Contents

Interactive snow and ice line in the EBM
Polar-amplified warming in the EBM
Effects of diffusivity in the annual mean EBM with albedo feedback
Diffusive response to a point source of energy

1. Interactive snow and ice line in the EBM

The annual mean EBM
the equation is
\begin{align}
C(\phi) \frac{\partial T_s}{\partial t} = & ~(1-\alpha) ~ Q - \left( A + B~T_s \right) +  \
& \frac{D}{\cos\phi } \frac{\partial }{\partial \phi} \left(\cos\phi  ~ \frac{\partial T_s}{\partial \phi} \right)
\end{align}
Temperature-dependent ice line
Let the surface albedo be larger wherever the temperature is below some threshold $T_f$:
$$ \alpha\left(\phi, T(\phi) \right) = \left{\begin{array}{ccc}
\alpha_0 + \alpha_2 P_2(\sin\phi) & ~ & T(\phi) > T_f \
a_i & ~ & T(\phi) \le T_f \
\end{array} \right. $$
Can you write Python code for it?

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import climlab

#  for convenience, set up a dictionary with our reference parameters
param = {'A':210, 'B':2, 'a0':0.3, 'a2':0.078, 'ai':0.62, 'Tf':-10.}
model1 = climlab.EBM_annual(name='Annual EBM with ice line',
                            num_lat=180, D=0.55, **param )
print( model1)


I am working on the file "Lectures/Lecture21 -- Ice albedo feedback in the EBM.ipynb".
The first task is:
In the ice-free regime, there is no polar-amplified warming. A uniform radiative forcing produces a uniform warming.

3. Effects of diffusivity in the annual mean EBM with albedo feedback

In-class investigation:
We will repeat the exercise from Lecture 16, but this time with albedo feedback included in our model.

Solve the annual-mean EBM (integrate out to equilibrium) over a range of different diffusivity parameters.
Make three plots:
Global-mean temperature as a function of $D$
Equator-to-pole temperature difference $\Delta T$ as a function of $D$
Poleward heat transport across 35 degrees $\mathcal{H}_{max}$ as a function of $D$

Choose a value of $D$ that gives a reasonable approximation to observations:
$\Delta T \approx 45$ ºC

Use these parameter values:
Can you write Python code for it?


I am working on the file "Lectures/Lecture21 -- Ice albedo feedback in the EBM.ipynb".
The first task is:
One possible way to do this:
Can you write Python code for it?

Darray = np.arange(0., 2.05, 0.05)

model_list = []
Tmean_list = []
deltaT_list = []
Hmax_list = []
for D in Darray:
    ebm = climlab.EBM_annual(num_lat=360, D=D, **param )
    ebm.integrate_years(5., verbose=False)
    Tmean = ebm.global_mean_temperature()
    deltaT = np.max(ebm.Ts) - np.min(ebm.Ts)
    HT = np.squeeze(ebm.heat_transport)
    ind = np.where(ebm.lat_bounds==35.5)[0]
    Hmax = HT[ind]
    model_list.append(ebm)
    Tmean_list.append(Tmean)
    deltaT_list.append(deltaT)
    Hmax_list.append(Hmax)

color1 = 'b'
color2 = 'r'

fig = plt.figure(figsize=(8,6))
ax1 = fig.add_subplot(111)
ax1.plot(Darray, deltaT_list, color=color1, label='$\Delta T$')
ax1.plot(Darray, Tmean_list, '--', color=color1, label='$\overline{T}$')
ax1.set_xlabel('D (W m$^{-2}$ K$^{-1}$)', fontsize=14)
ax1.set_xticks(np.arange(Darray[0], Darray[-1], 0.2))
ax1.set_ylabel('Temperature ($^\circ$C)', fontsize=14,  color=color1)
for tl in ax1.get_yticklabels():
    tl.set_color(color1)
ax1.legend(loc='center right')
ax2 = ax1.twinx()
ax2.plot(Darray, Hmax_list, color=color2)
ax2.set_ylabel('Poleward heat transport across 35.5$^\circ$ (PW)', fontsize=14, color=color2)
for tl in ax2.get_yticklabels():
    tl.set_color(color2)
ax1.set_title('Effect of diffusivity on EBM with albedo feedback', fontsize=16)
ax1.grid()


I am working on the file "Lectures/Lecture21 -- Ice albedo feedback in the EBM.ipynb".
The first task is:
The warming effects of our point source are felt at all latitudes but the effects decay away from the heat source.
Some analysis will show that the length scale of the warming is proportional to
$$  \sqrt{\frac{D}{B}} $$
so increases with the diffusivity.
Now repeat this calculate with ice albedo feedback
Can you write Python code for it?

m3 = climlab.EBM_annual(num_lat=180, **param)
m3.integrate_years(5.)
m4 = climlab.process_like(m3)
point_source = climlab.process.energy_budget.ExternalEnergySource(state=m4.state, timestep=m4.timestep)
point_source.heating_rate['Ts'][ind] = 100.
m4.add_subprocess('point source', point_source)
m4.integrate_years(5.)

plt.plot(m4.lat, m4.Ts - m3.Ts)
plt.xlim(-90,90)
plt.grid()


I am working on the file "Lectures/Lecture22 -- Snowball Earth in the EBM.ipynb".
The first task is:

1. The Neoproterozoic Snowball Earth events

The Geologic Time Scale
First, some information on the nomenclature for Earth history:

Walker, J. and Geissman, J. (2009). Geologic time scale. Technical report, Geological Society of America.

Extensive evidence for large glaciers at sea level in the tropics
Evidently the climate was very cold at these times (635 Ma and 715 Ma)

Hoffman, P. F. and Li, Z.-X. (2009). A palaeogeographic context for Neoproterozoic glaciation. Palaeogeogr. Palaeoclimatol. Palaeoecol., 277:158–172.

Hoffman, P. F. and Schrag, D. P. (2002). The snowball Earth hypothesis: testing the limits of global change. Terra Nova, 14(3):129–155.

The Snowball Earth hypothesis
Various bizarre features in the geological record from 635 and 715 Ma ago indicate that the Earth underwent some very extreme environmental changes… at least twice. The Snowball Earth hypothesis postulates that:

The Earth was completely ice-covered (including the oceans)
The total glaciation endured for millions of years
CO$_2$ slowly accumulated in the atmosphere from volcanoes
Weathering of rocks (normally acting to reduce CO$_2$) extremely slow due to cold, dry climate
Eventually the extreme greenhouse effect is enough to melt back the ice
The Earth then enters a period of extremely hot climate.

The hypothesis rests on a phenomenon first discovered by climate modelers in the Budyko-Sellers EBM: runaway ice-albedo feedback or large ice cap instability.

2. Stability of the polar ice caps: the concept

For small perturbations, we can relate the cooling to the displacement of the ice edge as:
$$  \delta T = -\frac{dT}{d\phi} \bigg|_{\phi_i} \delta \phi  $$
Stability criterion:
$$ \frac{\delta a ~ S(\phi_i) ~ \cos\phi_i}{B} < -\frac{dT}{d\phi} \bigg|_{\phi_i} \delta \phi  $$
The LHS is largest at the...
Can you write Python code for it?

#  for convenience, set up a dictionary with our reference parameters
param = {'A':210, 'B':2, 'a0':0.3, 'a2':0.078, 'ai':0.62, 'Tf':-10., 'D':0.55}
model1 = climlab.EBM_annual(name='Annual Mean EBM with ice line', num_lat=180, **param )
print( model1)

model1.integrate_years(5)
Tequil = np.array(model1.Ts)
ALBequil = np.array(model1.albedo)
OLRequil = np.array(model1.OLR)
ASRequil = np.array(model1.ASR)


I am working on the file "Lectures/Lecture22 -- Snowball Earth in the EBM.ipynb".
The first task is:
A roasty 58ºC, and the poles are above 20ºC. A tiny increase in $S_0$ has led to a very drastic change in the climate.
Can you write Python code for it?

S0array_snowballmelt = np.linspace(1400., 1900., 50)
icelat_snowballmelt = np.empty_like(S0array_snowballmelt)
icelat_snowballmelt_cooling = np.empty_like(S0array_snowballmelt)

for n in range(S0array_snowballmelt.size):
    model2.subprocess['insolation'].S0 = S0array_snowballmelt[n]
    model2.integrate_years(10, verbose=False)
    icelat_snowballmelt[n] = np.max(model2.icelat)

for n in range(S0array_snowballmelt.size):
    model2.subprocess['insolation'].S0 = np.flipud(S0array_snowballmelt)[n]
    model2.integrate_years(10, verbose=False)
    icelat_snowballmelt_cooling[n] = np.max(model2.icelat)


I am working on the file "Lectures/Lecture22 -- Snowball Earth in the EBM.ipynb".
The first task is:
Contents

The Neoproterozoic Snowball Earth events
Stability of the polar ice caps: the concept
Annual-mean EBM with albedo feedback: adjustment to equilibrium
Global feedback analysis in the EBM
Here Comes the Sun! Where is the ice edge?
Can you write Python code for it?

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from climlab import constants as const
import climlab


I am working on the file "Lectures/Lecture22 -- Snowball Earth in the EBM.ipynb".
The first task is:
It's much larger because we've covered so much more surface area with ice!
The feedback calculation now looks like
$\lambda = - 2 + \frac{-109}{-40} = -2 + 2.7 = +0.7$ W m$^{-2}$ $^{\circ}$C$^{-1}$
What? Looks like the positive albedo feedback is so strong here that it has outweighed the negative longwave feedback. What will happen to the system now? Let's find out...
Can you write Python code for it?

plt.plot( lat, Tequil, 'k--', label='equil' )
plt.plot( lat, model1.Ts, 'k-', label='pert' )
plt.grid(); plt.xlim(-90,90); plt.legend()
for n in range(5):
    model1.integrate_years(years=1.0, verbose=False)
    plt.plot(lat, model1.Ts)


I am working on the file "Lectures/Lecture22 -- Snowball Earth in the EBM.ipynb".
The first task is:
Less shortwave means that there is a tendency for the climate to cool down even more! In other words, the shortwave feedback is positive.

4. Global feedback analysis in the EBM

Take the global mean of the EBM equation, the transport term drops out
$$ C \frac{\partial \langle T_s \rangle}{\partial t} = \langle (1-\alpha) ~ Q \rangle - ~A - B~\langle T_s \rangle $$
Way back in Lecture 3 we defined the net climate feedback parameter through a linear Taylor series expansion of the global energy budget:
$$ \lambda = \frac{\partial}{\partial \langle T_s \rangle} \bigg( \Delta F_{TOA} \bigg) $$
where $\Delta F_{TOA}$ is the change in the net downward radiative flux at the TOA associated with a change $\delta \langle T_s \rangle$ in the global average surface temperature.
Applying this to the RHS of our EBM equation gives
$$ \lambda = \lambda_{LW} + \lambda_{SW} $$
with longwave and shortwave contributions:
$$ \lambda_{LW} = -B $$
and
$$ \lambda_{SW} = \frac{\Delta \langle (1-\alpha) ~ Q \rangle}{\Delta \langle T_s \rangle} $$
The longwave feedback is a constant in our model, by contruction.
The shortwave feedback, on the other hand, is state-dependent. The feedback depends on the detailed displacement of the ice line for a given global temperature change.
Plugging in numbers from our example above gives
$\lambda = - 2 + \frac{-20.4}{-20} = -2 + 1 = -1$ W m$^{-2}$ $^{\circ}$C$^{-1}$
The feedback is negative, as we expect! The tendency to warm up from reduced OLR outweighs the tendency to cool down from reduced ASR. A negative net feedback means that the system will relax back towards the equilibrium.
Let's let the temperature evolve one year at a time and add extra lines to the graph:
Can you write Python code for it?


I am working on the file "Lectures/Lecture22 -- Snowball Earth in the EBM.ipynb".
The first task is:
Let's look at what happens if we perturb the temperature -- make it 20ºC colder everywhere!
Can you write Python code for it?

model1.Ts -= 20.
model1.compute_diagnostics()


I am working on the file "Lectures/Lecture22 -- Snowball Earth in the EBM.ipynb".
The first task is:
Look again at the change in absorbed shortwave:
Can you write Python code for it?

climlab.global_mean( model1.ASR - ASRequil )


I am working on the file "Lectures/Lecture22 -- Snowball Earth in the EBM.ipynb".
The first task is:
Now we will complete the plot of ice edge versus solar constant.
Can you write Python code for it?

fig = plt.figure( figsize=(10,6) )
ax = fig.add_subplot(111)
ax.plot(S0array, icelat_cooling, 'r-', label='cooling' )
ax.plot(S0array, icelat_warming, 'b-', label='warming' )
ax.plot(S0array3, icelat3, 'g-', label='warming' )
ax.plot(S0array_snowballmelt, icelat_snowballmelt, 'b-' )
ax.plot(S0array_snowballmelt, icelat_snowballmelt_cooling, 'r-' )
ax.set_ylim(-10,100)
ax.set_yticks((0,15,30,45,60,75,90))
ax.grid()
ax.set_ylabel('Ice edge latitude', fontsize=16)
ax.set_xlabel('Solar constant (W m$^{-2}$)', fontsize=16)
ax.plot( [const.S0, const.S0], [-10, 100], 'k--', label='present-day' )
ax.legend(loc='upper left')
ax.set_title('Solar constant versus ice edge latitude in the EBM with albedo feedback', fontsize=16);


I am working on the file "Lectures/Lecture22 -- Snowball Earth in the EBM.ipynb".
The first task is:
Something very different happened! The climate drifted towards an entirely different equilibrium state, in which the entire planet is cold and ice-covered.
We will refer to this as the SNOWBALL EARTH.
Note that the warmest spot on the planet is still the equator, but it is now about -33ºC rather than +28ºC!

5. Here Comes the Sun! Where is the ice edge?

The ice edge in our model is always where the temperature crosses $T_f = -10^\circ$C. The system is at equilibrium when the temperature is such that there is a balance between ASR, OLR, and heat transport convergence everywhere.
Suppose that sun was hotter or cooler at different times (in fact it was significantly cooler during early Earth history). That would mean that the solar constant $S_0 = 4Q$ was larger or smaller. We should expect that the temperature (and thus the ice edge) should increase and decrease as we change $S_0$.
$S_0$ during the Neoproterozoic Snowball Earth events is believed to be about 93% of its present-day value, or about 1270 W m$^{-2}$.
We are going to look at how the equilibrium ice edge depends on $S_0$, by integrating the model out to equilibrium for lots of different values of $S_0$. We will start by slowly decreasing $S_0$, and then slowly increasing $S_0$.
Can you write Python code for it?

model2 = climlab.EBM_annual(num_lat = 360, **param)

S0array = np.linspace(1400., 1200., 200)

model2.integrate_years(5)

print( model2.icelat)

icelat_cooling = np.empty_like(S0array)
icelat_warming = np.empty_like(S0array)

# First cool....
for n in range(S0array.size):
    model2.subprocess['insolation'].S0 = S0array[n]
    model2.integrate_years(10, verbose=False)
    icelat_cooling[n] = np.max(model2.icelat)
# Then warm...
for n in range(S0array.size):
    model2.subprocess['insolation'].S0 = np.flipud(S0array)[n]
    model2.integrate_years(10, verbose=False)
    icelat_warming[n] = np.max(model2.icelat)


I am working on the file "Lectures/Lecture22 -- Snowball Earth in the EBM.ipynb".
The first task is:
Suddenly the climate looks very very different again! The global mean temperature is
Can you write Python code for it?


I am working on the file "Lectures/Lecture22 -- Snowball Earth in the EBM.ipynb".
The first task is:
Temperature drifts back towards equilibrium, as we expected!
What if we cool the climate so much that the entire planet is ice covered?
Can you write Python code for it?

model1.Ts -= 40.
model1.compute_diagnostics()


I am working on the file "Lectures/Lecture22 -- Snowball Earth in the EBM.ipynb".
The first task is:
The upshot:

For extremely large $S_0$, the only possible climate is a hot Earth with no ice.
For extremely small $S_0$, the only possible climate is a cold Earth completely covered in ice.
For a large range of $S_0$ including the present-day value, more than one climate is possible!
Once we get into a Snowball Earth state, getting out again is rather difficult!

<div class="alert alert-success">
[Back to ATM 623 notebook home](../index.ipynb)
</div>

Version information
Can you write Python code for it?

%load_ext version_information
%version_information numpy, matplotlib, climlab


I am working on the file "Lectures/Lecture23 -- The surface energy balance.ipynb".
The first task is:
Annual mean surface energy budget
Can you write Python code for it?

#  Surface energy budget terms, all defined as positive up (from ocean to atmosphere)
surface_budget = {}

for (name, run) in runs.items():
    budget = xr.Dataset()
    budget['LHF'] = run.LHFLX
    budget['SHF'] = run.SHFLX
    budget['LWsfc'] = run.FLNS
    budget['LWsfc_clr'] = run.FLNSC
    budget['SWsfc'] = -run.FSNS
    budget['SWsfc_clr'] = -run.FSNSC
    budget['SnowFlux'] = ((run.PRECSC+run.PRECSL)
                           *const.rho_w*const.Lhfus)
    # net upward radiation from surface
    budget['NetRad'] = budget['LWsfc'] + budget['SWsfc']
    budget['NetRad_clr'] = budget['LWsfc_clr'] + budget['SWsfc_clr']
    # net upward surface heat flux
    budget['Net'] = (budget['NetRad'] + budget['LHF'] +
                     budget['SHF'] + budget['SnowFlux'])
    surface_budget[name] = budget


I am working on the file "Lectures/Lecture23 -- The surface energy balance.ipynb".
The first task is:
Contents

Energy exchange mechanisms at the Earth's surface
Surface energy budget in CESM simulations
Sensible and Latent Heat Fluxes in the boundary layer
Bowen ratio in CESM simulations

1. Energy exchange mechanisms at the Earth's surface

The surface of the Earth is the boundary between the atmosphere and the land, ocean, or ice. Understanding the energy fluxes across the surface are very important for three main reasons:

We are most interested in the climate at the surface because we live at the surface.
The surface energy budget determines how much energy is available to evaporate water and moisten the atmosphere.
Air-sea energy fluxes set the thermal structure of the oceans, which in turn act to redistribute energy around the planet, with many important consequences for climate.

The energy budget at the surface is more complex that the budget at the top of the atmosphere. At the TOA the only energy transfer mechanisms are radiative (shortwave and longwave). At the surface, in addition to radiation we need to consider fluxes of energy by conduction and by convection of heat and moisture through turbulent fluid motion.
Major terms in the surface energy budget
We will denote the net upward energy flux at the surface as $F_S$.
As we mentioned back in Lecture 15 on heat transport, there are four principal contributions to $F_S$:

Shortwave radiation
Longwave radiation
Sensible heat flux
Evaporation or latent heat flux

Wherever $F_S \ne 0$, there is a net flux of energy between the atmosphere and the surface below. This implies either that there is heat storage / release occuring below the surface (e.g. warming or cooling of water, melting of snow and ice), and/or there is horizontal heat transport by fluid motions occuring below the surface (ocean circulation, groundwater flow).
Minor terms in the surface energy budget
All of these terms are small globally but can be significant locally or seasonally.

Latent heat of fusion required for melting ice and snow
Conversion of the...
Can you write Python code for it?

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import xarray as xr
from climlab import constants as const

datapath = "http://thredds.atmos.albany.edu:8080/thredds/dodsC/cesm/"
topo = xr.open_dataset(datapath+'som_input/USGS-gtopo30_1.9x2.5_remap_c050602.nc', decode_times=False)

runlist = ['control', '2xCO2']
runs = {}
for run in runlist:
    runstr = 'som_' + run
    path = datapath + runstr + '/' + runstr + '.cam.h0.clim.nc'
    runs[run] = xr.open_dataset(path, decode_times=False)

lat = runs['control'].lat
lon = runs['control'].lon
lev = runs['control'].lev


I am working on the file "Lectures/Lecture23 -- The surface energy balance.ipynb".
The first task is:
On the difference plot, the blue colors indicate the actual Bowen ratio is smaller than the equilibrium Bowen ratio. This will typically occur for wet surfaces with undersaturated air.
The red colors indicate the actual Bowen ratio is larger than the equilibrium Bowen ratio. This typically occurs for dry surfaces where there is not enough water available to satisfy the energetic demand for evaporation.
<div class="alert alert-success">

[Back to ATM 623 notebook home](../index.ipynb)

</div>

Version information
Can you write Python code for it?

%load_ext version_information
%version_information numpy, matplotlib, xarray, climlab


I am working on the file "Lectures/Lecture23 -- The surface energy balance.ipynb".
The first task is:
Plot the annual mean net upward flux $F_S$ (control and anomaly after warming)
Can you write Python code for it?

fig, axes = plt.subplots(1,2, figsize=(16,5))
cax1 = axes[0].pcolormesh(lon, lat, surface_budget['control'].Net.mean(dim='time'),
                          cmap=plt.cm.seismic, vmin=-200., vmax=200. )
axes[0].set_title('Annual mean net surface heat flux (+ up) - CESM control')
cax2 = axes[1].pcolormesh(lon, lat, surface_budget['anom'].Net.mean(dim='time'),
                    cmap=plt.cm.seismic, vmin=-20., vmax=20. )
fig.colorbar(cax1, ax=axes[0]); fig.colorbar(cax2, ax=axes[1])
axes[1].set_title('Anomaly after CO2 doubling')
for ax in axes:
    ax.set_xlim(0, 360); ax.set_ylim(-90, 90); ax.contour( lon, lat, topo.LANDFRAC, [0.5], colors='k');


I am working on the file "Lectures/Lecture25 -- Water, water everywhere!.ipynb".
The first task is:

4. Conclusion

We have forced a climate change NOT by adding any kind of radiative forcing, but just by changing the efficiency of evaporation at the sea surface.
The climate system then find a new equilibrium in which the radiative fluxes, surface temperature, air-sea temperature difference, boundary layer relative humidity, and wind speeds all change simultaneously.
Reasoning our way through such a problem from first principles in practically impossible. This is particularly true because in this example, the dominant driver of the climate change is an increase in SW absorption due to a substantial decrease in low-level clouds across the subtropics and mid-latitudes.
A comprehensive theory to explain these cloud changes does not yet exist. Understanding changes in low-level cloudiness under climate change is enormously important -- because these clouds, which have an unambiguous cooling effect, are a key determinant of climate sensitivity. There is lots of work left to do.
Water is intimately involved in just about every aspect of the planetary energy budget. Here we have highlighted the role of water in:

Cooling of the surface by evaporation
Water vapor greenhouse effect
Poleward latent heat transport
Cloud formation

[Back to ATM 623 notebook home](../index.ipynb)

Version information
Can you write Python code for it?

%load_ext version_information
%version_information numpy, scipy, matplotlib, xarray, climlab


I am working on the file "Lectures/Lecture25 -- Water, water everywhere!.ipynb".
The first task is:
<div class="alert alert-warning">
Although this is a "simple" model, it has a 60 x 30 point grid and is **by far the most complex model** we have built so far in these notes. These runs will probably take 15 minutes or more to execute, depending on the speed of your computer.
</div>
Can you write Python code for it?

model.integrate_years(4.)

#  One more year to get annual-mean diagnostics
model.integrate_years(1.)

ticks = [-90, -60, -30, 0, 30, 60, 90]
fig, axes = plt.subplots(2,2,figsize=(14,10))
ax = axes[0,0]
ax.plot(model.lat, model.timeave['Ts'])
ax.set_title('Surface temperature (reference)')
ax.set_ylabel('K')

ax2 = axes[0,1]
field = (model.timeave['Tatm']).transpose()
cax = ax2.contourf(model.lat, model.lev, field)
ax2.invert_yaxis()
fig.colorbar(cax, ax=ax2)
ax2.set_title('Atmospheric temperature (reference)');
ax2.set_ylabel('hPa')

ax3 = axes[1,0]
ax3.plot(model.lat, model.timeave['LHF'], label='LHF')
ax3.plot(model.lat, model.timeave['SHF'], label='SHF')
ax3.set_title('Surface heat flux (reference)')
ax3.set_ylabel('W/m2')
ax3.legend();

ax4 = axes[1,1]
Rtoa = np.squeeze(model.timeave['ASR'] - model.timeave['OLR'])
ax4.plot(model.lat, inferred_heat_transport(Rtoa, model.lat))
ax4.set_title('Meridional heat transport (reference)');
ax4.set_ylabel('PW')

for ax in axes.flatten():
    ax.set_xlim(-90,90); ax.set_xticks(ticks)
    ax.set_xlabel('Latitude'); ax.grid();


I am working on the file "Lectures/Lecture25 -- Water, water everywhere!.ipynb".
The first task is:
Contents

Imagine a world with reduced efficiency of evaporation
Reduced evaporation experiment in a simple model with climlab
Reduced evaporation efficiency experiment in an aquaplanet GCM
Conclusion

1. Imagine a world with reduced efficiency of evaporation

Recall from last lecture that the bulk formula for surface evaporation (latent heat flux) is
$$ \text{LE} = L ~\rho ~ C_D ~ U \left( q_s - q_a \right) $$
which we approximated in terms of temperatures for a wet surface as
$$ \text{LE} \approx L ~\rho ~ C_D ~ U \left( (1-r) ~ q_s^ + r \frac{\partial q^}{\partial T} \left( T_s - T_a \right) \right)  $$
The drag coefficient $C_D$ determines the flux for a given set of temperatures, relative humidity, and wind speed.
Now suppose that the drag coefficient is reduced by a factor of two (for evaporation only, not for sensible heat flux). i.e. all else being equal, there will be half as much evaporation.
Reasoning through the effects of this perturbation (and calculating the effects in models) will give us some insight into several different roles played by water in the climate system.
In-class exercise:
What is the effect of the reduced evaporation efficiency on surface temperature?

Form small groups.
Each group should formulate a hypothesis about how and why the surface temperature will change when $C_D$ is reduced by a factor of 2.
Draw a sketch of the surface temperature anomaly as a function of latitude.
Be prepared to explain your sketch and your hypothesis.

2. Reduced evaporation experiment in a simple model with climlab

We can use climlab to construct a model for the zonal-average climate. The model will be on a pressure-latitude grid. It will include the following processes:

Seasonally varying insolation as function of latitude
RRTMG radiation, including water vapor dependence and prescribed clouds
Fixed relative humidity
Shortave absorption by ozone
Meridional heat transport, implemented as a horizontal down-gradient temperature diffusion at every...
Can you write Python code for it?

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import xarray as xr
import climlab
from climlab import constants as const

def inferred_heat_transport( energy_in, lat_deg ):
    '''Returns the inferred heat transport (in PW) by integrating the net energy imbalance from pole to pole.'''
    from scipy import integrate
    from climlab import constants as const
    lat_rad = np.deg2rad( lat_deg )
    return ( 1E-15 * 2 * np.math.pi * const.a**2 *
            integrate.cumtrapz( np.cos(lat_rad)*energy_in,
            x=lat_rad, initial=0. ) )

# A two-dimensional domain
num_lev = 50
state = climlab.column_state(num_lev=num_lev, num_lat=60, water_depth=10.)
lev = state.Tatm.domain.axes['lev'].points


I am working on the file "Lectures/Lecture25 -- Water, water everywhere!.ipynb".
The first task is:
Dashed lines are clear-sky radiation anomalies.
Looking at the TOA budget:

Reducing evaporation efficiency leads to very large increase in ASR, especially in mid-latitudes
This increase is almost entirely due to clouds!
Accompanied by a (mostly) clear-sky OLR increase, consistent with the warmer temperatures.

This is very suggestive of an important role for low-level cloud changes.  [Why?]
From the surface budget:

Notice that the decrease in evaporation is much weaker than we found in the simple model.
Here, the decreased evaporation efficiency is competing against the warmer temperatures which tend to strongly increase evaporation, all else being equal.
The surface (ocean) gains a lot of excess heat by solar radiation.
As noted from the TOA budget, this is due to changes in cloudiness.
The clear-sky SW anomaly is actually positive, consistent with a warmer, moister atmosphere (but this effect is small).
The LW anomaly is positive, indicating increased radiative cooling of the surface.
This is also largely a cloud effect, and consistent with a decrease in low-level cloudiness. [Why?]
As in the simple model, there is an increase in the sensible heat flux (though weaker).
According to bulk formula, should be driven by one or both of
increased wind speed
increased air-sea temperature difference

Vertical structure of relative humidity and cloud changes
Can you write Python code for it?

fig, (ax1,ax2) = plt.subplots(1,2,figsize=(12,5))
RH = (halfEvap.RELHUM - ctrl.RELHUM).mean(dim='lon'); CLOUD = (halfEvap.CLOUD - ctrl.CLOUD).mean(dim='lon')
contours = np.arange(-15, 16., 2.)
cax1 = ax1.contourf(lat, lev, RH, levels=contours, cmap='seismic'); fig.colorbar(cax1, ax=ax1); ax1.set_title('Relative Humidity (%)')
cax2 = ax2.contourf(lat, lev, 100*CLOUD, levels=contours, cmap='seismic'); ax2.set_title('Cloud fraction (%)')
for ax in [ax1, ax2]:
    ax.invert_yaxis(); ax.set_xlim(-90,90); ax.set_xticks(ticks);


I am working on the file "Lectures/Lecture25 -- Water, water everywhere!.ipynb".
The first task is:
Energy budget anomalies at TOA and surface
Can you write Python code for it?

fig, (ax1,ax2) = plt.subplots(1,2,figsize=(14,5))
ax1.plot(lat, zonanom.ASR, color='b', label='ASR')
ax1.plot(lat, zonanom.OLR, color='r', label='OLR')
ax1.plot(lat, zonanom.ASR_clr, color='b', linestyle='--')
ax1.plot(lat, zonanom.OLR_clr, color='r', linestyle='--')
ax1.set_title('TOA radiation anomalies')

ax2.plot(lat, zonanom.SWsfc, color='b', label='SW')
ax2.plot(lat, zonanom.SWsfc_clr, color='b', linestyle='--')
ax2.plot(lat, zonanom.LWsfc, color='g', label='LW')
ax2.plot(lat, zonanom.LWsfc_clr, color='g', linestyle='--')
ax2.plot(lat, zonanom.LHF, color='r', label='LHF')
ax2.plot(lat, zonanom.SHF, color='c', label='SHF')
ax2.plot(lat, zonanom.SfcNet, color='m', label='Net')
ax2.set_title('Surface energy budget anomalies')

for ax in [ax1, ax2]:
    ax.set_ylabel('W/m2'); ax.set_xlabel('Latitude')
    ax.set_xlim(-90,90); ax.set_xticks(ticks);
    ax.legend(); ax.grid();


I am working on the file "Lectures/Lecture25 -- Water, water everywhere!.ipynb".
The first task is:
Meridional heat transport anomalies
Can you write Python code for it?

HT = {}
HT['total'] = inferred_heat_transport(anom.Rtoa.mean(dim='lon'), lat)
HT['atm'] = inferred_heat_transport(anom.Fatmin.mean(dim='lon'), lat)
HT['latent'] = inferred_heat_transport(anom.EminusP.mean(dim='lon') * const.Lhvap, lat)
HT['dse'] = HT['atm'] - HT['latent']

fig, ax = plt.subplots()
ax.plot(lat, HT['total'], 'k-', label='total', linewidth=2)
ax.plot(lat, HT['dse'], 'b', label='dry')
ax.plot(lat, HT['latent'], 'r', label='latent')
ax.set_xlim(-90,90); ax.set_xticks(ticks); ax.grid()
ax.legend(loc='upper left'); ax.set_ylabel('PW'); ax.set_xlabel('Latitude')


I am working on the file "Lectures/Lecture25 -- Water, water everywhere!.ipynb".
The first task is:
The complete model, ready to use!
Can you write Python code for it?


I am working on the file "Lectures/Lecture25 -- Water, water everywhere!.ipynb".
The first task is:
This model predicts the following:

The surface temperature warms slightly in the tropics, and cools at high latitudes
The atmosphere gets colder everywhere!
There is a substantial reduction in surface latent heat flux, especially in the tropics where it is dominant.
There is also a substantial increase in sensible heat flux. This is consistent with the cooler air temperatures and warmer surface.
Colder tropical atmosphere leads to a decrease in the poleward heat tranpsort. This helps explain the high-latitude cooling.
Notice that the heat transport responds to the atmopsheric temperature gradient, which changes in the opposite direction of the surface temperature gradient.

Basically, this model predicts that by inhibiting evaporation in the tropics, we force the tropical surface to warm and the tropical atmosphere to cool. This cooling signal is then communicated globally by atmospheric heat transport. The result is small positive global surface temperature anomaly.
Discussion: what is this model missing?
We could list many things, but as we will see below, two key climate components that are not included in this model are

changes in relative humidity
cloud feedback

We will compare this result to an analogous experiment in a GCM.

3. Reduced evaporation efficiency experiment in an aquaplanet GCM

The model is the familiar CESM but in simplified "aquaplanet" setup. The surface is completely covered by a shallow slab ocean.
This model setup (with CAM4 model physics) is described in detail in this paper:

Rose, B. E. J., Armour, K. C., Battisti, D. S., Feldl, N., and Koll, D. D. B. (2014). The dependence of transient climate sensitivity and radiative feedbacks on the spatial pattern of ocean heat uptake. Geophys. Res. Lett., 41, doi:10.1002/2013GL058955

Here we will compare a control simulation with a perturbation simulation in which we have once again reduced the drag coefficient by a factor of 2.
Can you write Python code for it?

# Load the climatologies from the CAM4 aquaplanet runs
datapath = "http://ramadda.atmos.albany.edu:8080/repository/opendap/latest/Top/Users/BrianRose/CESM_runs/"
endstr = "/entry.das"
ctrl = xr.open_dataset(datapath + 'aquaplanet_som/QAqu_ctrl.cam.h0.clim.nc' + endstr, decode_times=False).mean(dim='time')
halfEvap = xr.open_dataset(datapath + 'aquaplanet_som/QAqu_halfEvap.cam.h0.clim.nc' + endstr, decode_times=False).mean(dim='time')

lat = ctrl.lat
lon = ctrl.lon
lev = ctrl.lev

TS_anom = halfEvap.TS - ctrl.TS
Tatm_anom = halfEvap['T'] - ctrl['T']


I am working on the file "Lectures/Lecture4-Matplotlib/Data Visualization.ipynb".
The first task is:
The are a number of packages that we could use to present the data.
In this case we will be exploring the use of matplotlib. Use '%matplotlib inline' line in your ipython notebook to activate the inline viewing of the plots
Can you write Python code for it?

%matplotlib inline
import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
plt.plot(np.arange(10))

#Plots in matplotlib reside in a figure object. Create a new figure object with
plt.figure()

fig = plt.figure()

ax1 = fig.add_subplot(2,2,1)
ax2 = fig.add_subplot(2,2,2)
ax3 = fig.add_subplot(2,2,3)
#Empty Matplotlib figure with three subplots
fig

plt.plot(randn(50).cumsum(),'k--')


I am working on the file "Lectures/Lecture4-Matplotlib/Data Visualization.ipynb".
The first task is:
k-- is a style option for black dashed lines
Can you write Python code for it?

_ = ax1.hist(randn(100), bins=20, color='k', alpha=0.3)
ax2.scatter(np.arange(30), np.arange(30) +3 * randn(30))

fig


I am working on the file "Lectures/Lecture4-Matplotlib/Data_Visualization.ipynb".
The first task is:
A density plot is similar to a histogram in that it describes the distribution of the underlying data, but rather than being a pure empirical representation, it is an estimate of the underlying "true" distribution. As a result, it is smoothed into a continuous line plot. We create them in Pandas using the plot method with kind='kde', where kde stands for kernel density estimate.
Can you write Python code for it?


I am working on the file "Lectures/Lecture4-Matplotlib/Data_Visualization.ipynb".
The first task is:
Another way of comparing the groups is to look at the survival rate, by adjusting for the number of people in each group.
Can you write Python code for it?

death_counts.div(death_counts.sum(1).astype(float), axis=0).plot(kind='barh', stacked=True, color=['black','gold'])


I am working on the file "Lectures/Lecture4-Matplotlib/Data_Visualization.ipynb".
The first task is:
As an illustration of the high-level nature of Pandas plots, we can split multiple series into subplots with a single argument for plot:
Can you write Python code for it?


I am working on the file "Lectures/Lecture4-Matplotlib/Data_Visualization.ipynb".
The first task is:
Bar plots
Bar plots are useful for displaying and comparing measurable quantities, such as counts or volumes. In Pandas, we just use the plot method with a kind='bar' argument.
For this series of examples, let's load up the Titanic dataset:
Can you write Python code for it?

titanic = pd.read_excel("data/titanic.xls", "titanic")
titanic.head()

titanic.groupby('pclass').survived.sum().plot(kind='bar')

titanic.groupby(['sex','pclass']).survived.sum().plot(kind='barh')

death_counts = pd.crosstab([titanic.pclass, titanic.sex], titanic.survived.astype(bool))
death_counts.plot(kind='bar', stacked=True, color=['black','gold'], grid=False)


I am working on the file "Lectures/Lecture4-Matplotlib/Data_Visualization.ipynb".
The first task is:
Exercise
Using the Titanic data, create kernel density estimate plots of the age distributions of survivors and victims.
Scatterplots
To look at how Pandas does scatterplots, let's reload the baseball sample dataset.
Can you write Python code for it?

baseball = pd.read_csv("data/baseball.csv")
baseball.head()


I am working on the file "Lectures/Lecture4-Matplotlib/Data_Visualization.ipynb".
The first task is:
Here, we had to normalize the histogram (normed=True), since the kernel density is normalized by definition (it is a probability distribution).
We will explore kernel density estimates more in the next section.
Boxplots
A different way of visualizing the distribution of data is the boxplot, which is a display of common quantiles; these are typically the quartiles and the lower and upper 5 percent values.
Can you write Python code for it?


I am working on the file "Lectures/Lecture4-Matplotlib/Data_Visualization.ipynb".
The first task is:
Histograms
Frequenfly it is useful to look at the distribution of data before you analyze it. Histograms are a sort of bar graph that displays relative frequencies of data values; hence, the y-axis is always some measure of frequency. This can either be raw counts of values or scaled proportions.
For example, we might want to see how the fares were distributed aboard the titanic:
Can you write Python code for it?


I am working on the file "Lectures/Lecture4-Matplotlib/Data_Visualization.ipynb".
The first task is:
If we would like a little more control, we can use matplotlib's subplots function directly, and manually assign plots to its axes:
Can you write Python code for it?

fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(12, 4))
for i,var in enumerate(['normal','gamma','poisson']):
    variables[var].cumsum(0).plot(ax=axes[i], title=var)
axes[0].set_ylabel('cumulative sum')


I am working on the file "Lectures/Lecture4-Matplotlib/Data_Visualization.ipynb".
The first task is:
Notice that by default a line plot is drawn, and a light grid is included. All of this can be changed, however:
Can you write Python code for it?


I am working on the file "Lectures/Lecture4-Matplotlib/Data_Visualization.ipynb".
The first task is:
Often, histograms and density plots are shown together:
Can you write Python code for it?

titanic.fare.hist(bins=doanes(titanic.fare.dropna()), normed=True, color='lightseagreen')
titanic.fare.dropna().plot(kind='kde', xlim=(0,600), style='r--')