Climate Sensitivity: The Last 1000 Years

Adjust Climate Properties

Annotate Plots:

Reconstructed and Simulated Temperatures

Simulated using reconstructed forcing by Crowley et al (2000)

Resconstructed temperatures from multiple proxy records by Mann et al (2008)

Reconstructed Climate Forcing

Causes of Climate Change Over the Past 1000 Years, Thomas J. Crowley, Science 289, 270 (2000);DOI: 10.1126/science.289.5477.270


This is a very simple model of climate response to forcing during the period 1000-1998. There are three major climate shifts to analyze: the Medieval Warm Period (roughly 1100-1400), the Little Ice Age (1500-1850), and the Modern Warming in the 20th Century.

Both reconstructed forcing and temperatures were provided by the NOAA National Climatic Data Center. Climate forcing due to volcanic eruptions, changes in solar output, greenhouse gases, and tropospheric aerosol were derived by Crowley (2000). Global mean temperatures over this period were reconstructed from multiple proxies as reported by Mann et al (2008).

The model simply adjusts the temperature upward or downward according to the prescribed forcing for each year, with a relaxation time toward an equilibrium temperature according to the user-specified climate sensitivity. Total forcing in each year is the sum of forcing due to volvanic aerosol, solar output, greenhouse gases, and tropospheric aerosol (all in Watts per square meter), derived from the reconstructions of Crowley (2000) and displayed in the “Forcing” tab to the right.

In each year beginning in AD 1000, an equilibrium temperature is computed from the forcing using the climate sensitivity (in degrees per Watt/m2) as:

temp.eq <- total.forcing[i] * sensitivity 

Simulated temperature is then adjusted toward the equilibrium temperature according to the user-specified timescale as:

temp[i+1] <- temp[i] + (temp.eq - temp[i]) / timescale

The program that does the calculation is very simple, and the code that controls this website is surprisingly simple too! It is all written in the programming language R. You can read all about it on the “Website Code” tab to the right.


Crowley, T. J., 2000. Causes of Climate Change Over the Past 1000 Years. Science 289, 270. DOI: 10.1126/science.289.5477.270

Mann, M. E., Z. Zhang, M. K. Hughes, R. S. Bradley, S. K. Miller, S. Rutherford, and F. Ni, 2008. Proxy-based reconstructions of hemispheric and global surface temperature variations over the past two millennia. Proceedings of the National Academy of Sciences 105(36), 13252-13257, doi:10.1073/pnas.0805721105

How this website works (including all the code!)

This website is controlled using the R package “shiny.” There are four important components:

  • The user interface (ui.R) that controls the sliders and passes inputs to the model
  • The “server” (server.R) that responds to user interface events in the web browser;
  • A program to read the reconstructed forcing and temperature data, predict the temperatures from the forcing, and graph the resulting comparison (compare.R)
  • A program to plot the reconstructed forcing data straight from the file (plot.forcing.R)

Scroll down or click links in the list above to read all about it!

This is the user interface that actually controls this website



# Define UI for slider demo application

  #  Application title
  headerPanel("Climate Sensitivity: The Last 1000 Years"),

  # Sidebar with sliders that adjust climate sensitivity
    h4('Adjust Climate Properties'),  

      sliderInput("sensitivity", "Sensitivity (degrees per Watt/m2)", 
                  min = 0.5, max = 1.5, value = 0.8, step=0.01),
      sliderInput("timescale", "Climate adjustment time (years)", 
              min = 10, max = 200, value = 30, step=5)),

  # Main panel consists of a tabset displays model output or model description
      tabPanel("Climate Response", 
               h3("Reconstructed and Simulated Temperature Since the Year 1000"),
               h4("Resconstructed from multiple proxy records 
                  by Mann et al (2008)"),
               h4("Simulated  using reconstructed forcing by 
                  Crowley et al (2000)"),
               tags$style(type="text/css", ".tab-content { overflow: visible; }")), 
               h3("Reconstructed Climate Forcing"),
               p('Causes of Climate Change Over the Past 1000 Years, Thomas J. Crowley,
                  Science 289, 270 (2000);DOI: 10.1126/science.289.5477.270'),
               tags$style(type="text/css", ".tab-content { overflow: visible; }")), 
      tabPanel("Website Code",

Here is the server module



# Source required R scripts

shinyServer(function(input, output) {

  # Draw an annotated diagram of the model output
  output$climate <- renderPlot(
    compare(sensitivity=input$sensitivity, timescale=input$timescale), height=600)

  # Make a simple line plot of temperature vs height
  output$forcing <- renderPlot(plot.forcing(),height=800)

This is the program that predicts temperatures from forcing and plots the comparison


compare <- function(sensitivity=0.81, timescale=30) {

  # Read climate forcing and reconstructed temperatures from files, 
  # then simulated temperatures from focring data and compare to 
  # reconstructed temperatuers in a single graph

  # Read Croweley (2000) forcing from a file
  forcing <- read.table(skip=52, 

  # Adjust volcanic forcing for daytime only and Earth's albedo
  forcing$volcanic <- forcing$volcanic /4 * 0.7

  # Add all the forcing terms together
  total.forcing <- forcing$solar + forcing$volcanic + forcing$GHG + forcing$trop

  # Predict the temperatures from the forcing
  temp <- replicate(999,0)

  for (i in 1:998) {
    temp.eq <- total.forcing[i] * sensitivity 
    temp[i+1] <- temp[i] + (temp.eq - temp[i]) / timescale
  # Subtract mean from predicted temperatures to get anomalies
  predicted.temp <- temp - mean(temp)

  # Read Mann et al (2008) reconstructed temperatres from a file
  mann <- read.table('Data/mann2008.temp.txt', header=T)$temp

  # Subtract mean reconstruced temperatuers to get anomalies
  mann <- mann - mean(mann)
  mann <- mann[1:999]

  # Plot the predicetd and reconstructed temperatures on the same set of axes
  orig.par <- par(no.readonly=T)  
  plot(1000:1998, mann, col='lightgray', ylim=c(-.5, .7),
       ylab='Temperature Deviation from Mean (Celsius)',
  lines(1000:1998, predicted.temp, col='red', lwd=5)
         col=c('red','darkgray'), lwd=c(5,1), lty=c(1,NA), pch=c(NA,1))  


This is the program that displays the reconstructed climate forcing from the file


plot.forcing <- function(forcing){

  forcing <- read.forcing()

  # Set plot parameters: stack of three plots, large text, nice margins
  orig.par <- par(no.readonly=TRUE)  # Remember changable parameters to reset later
  par (mfrow=c(3,1), cex=1.5, mar=c(3,2,2,1))

  plot(forcing$year, forcing$volcanic, typ='l',col='red',lwd=3, cex.axis=1.2,
       main='Volcanic Forcing')

  plot(forcing$year, forcing$solar, typ='l', col='gold', lwd=3, cex.axis=1.2,
       main='Solar Forcing')

  plot(forcing$year, forcing$GHG, typ='l', col='red',lwd=3, ylim=c(-1,2.5), cex.axis=1.2,
       xlab='Year',main='GHG and Tropospheric Aerosol Forcing')
  lines(forcing$year, forcing$trop, typ='l', col='blue', lwd=3)
  legend('topleft', c('Greenhouse gases','Tropospheric Aerosol'), lwd=c(3,3),
         col=c('red','blue'), cex=1.3)

  # Restore original plot parameters