We use cookies

We use cookies and other tracking technologies to improve your browsing experience on our website, to show you personalized content and targeted ads, to analyze our website traffic, and to understand where our visitors are coming from.

Tanya Shapiro
  • Home
  • About
  • Talks
  • Blog
  • Projects

US Tornado Outbreaks

Observable
interactive
TidyTuesday
Part of the TidyTuesday series. Project exploring tornado outbreaks reported across the United States. Data source NOAA.

Where do tornado outbreaks usually occur?

Density map tracking tornado outbreaks countrywide from 1950 - 2022. This visual shows hotspots of tornado outbreaks over the past 70 years, drawing focus to what meteorologists commonly refer to as Tornado Alley: a region in the central United States known for its higher frequency and severity of tornadoes due to the collision of contrasting air masses and favorable atmospheric conditions.

viewof form = Inputs.form({
  bins: Inputs.range([0, 50], {label: "Bins", step: 1, value:11}),
  minYear: Inputs.range([1950, 2022], {label: "Min Year", step: 1, value:1950}),
  maxYear: Inputs.range([1950, 2022], {label: "Max Year", step: 1, value:2022}),
})
form = Object {bins: 11, minYear: 1950, maxYear: 2022}
tornados = FileAttachment("data/tornados.csv").csv({typed: true});
usGeo = d3.json('https://raw.githubusercontent.com/codeforgermany/click_that_hood/main/public/data/united-states.geojson');

function getColor(palette) {
 return  palette === "YlOrRd" ? d3.schemeYlOrRd[5][2] :   
   palette === "YlGnBu" ? d3.schemeYlGnBu[5][2] : 
   palette === "BuPu" ? d3.schemeBuPu[5][2] : 
   palette === "Reds" ? d3.schemeReds[5][2] : 
     "black";
}
tornados = Array(68693) [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, …]
usGeo = Object {type: "FeatureCollection", features: Array(49)}
getColor = ƒ(palette)
cities = [
  { name: "Houston", lat: 29.7604, lon: -95.3698, color:'black'},
  { name: "Tampa", lat: 27.9506, lon: -82.4572, color:'black'},
  {name: "Denver", lat: 39.7392,lon: -104.9903, color:'black'},
  {name: "Oklahoma City", lat:35.4676, lon:-97.5164, color:'white'},
  {name: "Jackson", lat:32.2988, lon:-90.1848, color:'black'},
  {name:"Dallas", lat:32.7767, lon:-96.7970, color:'black'},
  {name:"Tulia", lat:34.5359, lon:-101.7585, color:'black'},
  {name:"Great Bend", lat:38.3645, lon:-98.7648, color:'black'}
];
cities = Array(8) [Object, Object, Object, Object, Object, Object, Object, Object]
Plot = import("https://esm.sh/@observablehq/plot")
Plot = Module {Area: class, Arrow: class, BarX: class, BarY: class, Cell: class, Contour: class, Density: class, Dot: class, Frame: class, Geo: class, Hexgrid: class, Image: class, Line: class, Link: class, Mark: class, Raster: class, Rect: class, RuleX: class, RuleY: class, Text: class, …}
main_map = Plot.plot({
  width:1000,
  marginTop:50,
  projection: "albers",
  color: {scheme: 'YlOrRd'},
  style: {background:"transparent"},
  marks: [
    Plot.geo(usGeo, {fill:"#DDD"}),
    Plot.density(filtered, {x: "slon", y: "slat", bandwidth: form.bins, fill: "density", opacity:.4}),
    Plot.geo(usGeo, {fill:"transparent", stroke:"#FFF", opacity:0.6}),
    Plot.dot(cities, {x:"lon", y:"lat", text:"name", fill:"black", r:2}),
    Plot.text(cities, {x:"lon", y:"lat",  text:"name", fontSize:12, dx: -10, dy:10, fill:"black"})

  ]
})
HoustonTampaDenverOklahoma CityJacksonDallasTuliaGreat Bend

Outbreaks by Decade

Have the outbreak patterns remained consistent countrywide or do they vary? Beginning, appears outbreaks are more concentrated in mid central territory spanning between Texas and Nebraska. Later decades, south east grows in frequency of tornado outbreaks too (Mississippi, Alabama, and Florida most notable).

decade_map = Plot.plot({
  width:1200,
  projection: "albers",
  color: {scheme: 'YlOrRd'},
  style: {backgroundColor:'transparent'},
  facet: {data:filtered, y:"row_index", x:"col_index", label:null},
  marks: [
    Plot.geo(usGeo, {fill:"#DDD"}),
    Plot.density(filtered, {x: "slon", y: "slat", bandwidth: 5, fill: "density", opacity:.4}),
    Plot.geo(usGeo, {fill:"transparent", stroke:"#FFF", opacity:0.6}),
    Plot.text(decades, {y: d=> 52, x: d=> -98, 
                        text: "decade",
                        fx:"col_index", fy:"row_index", fontWeight:"bold", fontSize:14})
  ]
})
1231231950s1980s2010s1960s1990s2020s1970s2000s

When do tornado outbreaks usually occur?

April, May, and June appear to be peak season for tornadoes. The highest count of tornadoes occurred in April 2011, also known as the 2011 Super Outbreak. It is considered one of the largest, deadliest, and most intense tornado outbreaks in American history. The outbreak lasted for four days, from April 25 to April 28, and affected multiple states across the southeastern and central United States.

Plot.plot({
  color: {scheme: 'YlOrRd'},
   style: {background:"transparent"},
   marginBottom:100,
  x: {label:null},
  y: {label: null},
  width:1200,
  height:450,
  marks: [
    Plot.cell(calendar, {y:"month", x:"year", fill:"tornados",  inset: 0.2, stroke:"#DDD", strokeWidth:0.2}),
    Plot.text(calendar, {x:"year", y:"month", fontSize:11,
                         text: d=> d.tornados>250 ? d.tornados : '', 
                         fill: d=> d.tornados>350 ? "white" : "black"}),
    Plot.axisY({tickSize:0, fontSize:12,
                ticks:d3.range(1, 13),
                text:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]}
                ),
    Plot.axisX({tickSize:0, fontSize:12,
                text:["1992","'93","'94","'95","'96","'97","'98","'99","2000","'01","'02",
                     "'03","'04","'05","'06","'07","'08","'09","'10","'11","'12","'13","'14","'15","'16",
                     "'17","'18","'19","'20","'21","'22"]})
  ]
})
3993133943103763102895422925092682953172524602912703063217573262672863812912725102642591992'93'94'95'96'97'98'992000'01'02'03'04'05'06'07'08'09'10'11'12'13'14'15'16'17'18'19'20'21'22⚠️3 warnings. Please check the console.
Plot.plot({
  width:1200,
  y: {tickSize:0, grid:true},
  x: {tickSize:0, label:"Year"},
  style: {backgroundColor:'transparent'},
  marks: [
    Plot.areaY(tornados, Plot.groupX({y:"count"}, {x:"yr",opacity:0.5, fill:getColor('YlOrRd')})),
    Plot.line(tornados, Plot.groupX({y:"count"}, {x:"yr", strokeWidth:2, stroke:getColor('YlOrRd')})),
    Plot.ruleY([0]),
    Plot.axisX({label: null, fontSize:12,tickSize:0, tickFormat: d3.format("d")}),
    Plot.axisY({fontSize:12})

  ]
})
19501955196019651970197519801985199019952000200520102015202002004006008001,0001,2001,4001,6001,800↑ Frequency
db = DuckDBClient.of({ 
    tornados: await FileAttachment("data/tornados.csv").csv(),
})
db = DuckDBClient {}
filtered = db.sql`SELECT t. *
  ,floor(yr::int/10)*10 as decade
  ,CASE WHEN floor(yr::int/10)*10<=1970 THEN 1 
  WHEN floor(yr::int/10)*10<=2000 THEN 2
  ELSE 3 END AS row_index
  ,CASE 
  WHEN floor(yr::int/10)*10 IN (1950,1980, 2010) THEN 1
  WHEN floor(yr::int/10)*10 IN (1960,1990, 2020) THEN 2
  WHEN floor(yr::int/10)*10 IN (1970,2000) THEN 3
  ELSE 4 end as col_index
FROM tornados t
WHERE yr>=${form.minYear} and yr<=${form.maxYear}`
filtered = Array(68693) [Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, …]
decades = db.sql`SELECT 
distinct SUBSTRING(cast(floor(yr::int/10)*10 as char),1,4) || 's' as decade
  ,CASE WHEN floor(yr::int/10)*10<=1970 THEN 1 
  WHEN floor(yr::int/10)*10<=2000 THEN 2
  ELSE 3 END AS row_index
  ,CASE 
  WHEN floor(yr::int/10)*10 IN (1950,1980, 2010) THEN 1
  WHEN floor(yr::int/10)*10 IN (1960,1990, 2020) THEN 2
  WHEN floor(yr::int/10)*10 IN (1970,2000) THEN 3
  ELSE 4 end as col_index
  from tornados`
decades = Array(8) [Row, Row, Row, Row, Row, Row, Row, Row, schema: Array(3)]
calendar = db.sql`SELECT 
  year as year
  , month as month
  , COALESCE(tornados,0) as tornados
FROM 
  (SELECT distinct mo as month from tornados) m
CROSS JOIN 
  (SELECT distinct yr as year from tornados where yr>=1992) y
LEFT JOIN
  (SELECT yr, mo, count(*) as tornados from tornados group by 1,2) t on t.yr=y.year and m.month = t.mo
ORDER BY year, month`
calendar = Array(372) [Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, Row, …]
 
    Created with Quarto
    Copyright © 2023 Tanya Shapiro. All rights reserved.
Cookie Preferences