{const width =750;const height =450;const svg = d3.create("svg").attr("width", width).attr("height", height).attr("viewBox",`0 0 ${width}${height}`);// Ocean background svg.append("rect").attr("width", width).attr("height", height).attr("fill","#e3f2fd").attr("rx",10);// Simplified North America outline svg.append("path").attr("d","M 100,80 L 150,60 L 200,70 L 280,80 L 320,100 L 350,120 L 380,150 L 360,180 L 370,220 L 390,250 L 380,280 L 360,320 L 340,350 L 300,370 L 250,380 L 200,370 L 160,340 L 140,300 L 120,250 L 100,200 L 90,150 Z").attr("fill","#a5d6a7").attr("stroke","#4caf50").attr("stroke-width",2);// Labels svg.append("text").attr("x",230).attr("y",230).attr("font-size",13).attr("fill","#2e7d32").attr("font-weight","bold").text("USA"); svg.append("text").attr("x",550).attr("y",100).attr("font-size",11).attr("fill","#1565c0").text("Atlantic Ocean"); svg.append("text").attr("x",450).attr("y",380).attr("font-size",11).attr("fill","#1565c0").text("Caribbean Sea"); svg.append("text").attr("x",200).attr("y",420).attr("font-size",11).attr("fill","#1565c0").text("Gulf of Mexico");// Latitude lines [100,180,260,340].forEach((y, i) => { svg.append("line").attr("x1",0).attr("y1", y).attr("x2",750).attr("y2", y).attr("stroke","#90caf9").attr("stroke-width",0.5).attr("stroke-dasharray","3,3"); svg.append("text").attr("x",720).attr("y", y -3).attr("font-size",9).attr("fill","#64b5f6").text(`${60- i *15}°N`); });// NYC marker svg.append("circle").attr("cx",380).attr("cy",160).attr("r",6).attr("fill","#f44336"); svg.append("text").attr("x",390).attr("y",155).attr("font-size",11).attr("font-weight","bold").attr("fill","#f44336").text("NYC");if (stormTypeMap ==="Atlantic Hurricanes"|| stormTypeMap ==="Both") {// Hurricane tracks (typical recurvature pattern)const hurricaneTracks = [ [{x:650,y:360}, {x:580,y:340}, {x:500,y:330}, {x:430,y:310}, {x:400,y:280}, {x:420,y:240}, {x:470,y:200}, {x:540,y:160}], [{x:700,y:380}, {x:620,y:370}, {x:540,y:360}, {x:460,y:340}, {x:380,y:320}, {x:340,y:290}, {x:350,y:250}, {x:380,y:210}], [{x:680,y:400}, {x:600,y:390}, {x:520,y:380}, {x:440,y:370}, {x:360,y:350}, {x:300,y:330}, {x:280,y:300}] ];const colors = ["#e74c3c","#c0392b","#e67e22"]; hurricaneTracks.forEach((track, i) => { svg.append("path").attr("d", d3.line().x(d => d.x).y(d => d.y).curve(d3.curveCatmullRom)(track)).attr("stroke", colors[i]).attr("stroke-width",3).attr("fill","none").attr("stroke-dasharray","8,3");// Start marker svg.append("circle").attr("cx", track[0].x).attr("cy", track[0].y).attr("r",5).attr("fill", colors[i]);// End marker svg.append("text").attr("x", track[track.length-1].x).attr("y", track[track.length-1].y).attr("font-size",16).text("🌀"); }); svg.append("rect").attr("x",520).attr("y",130).attr("width",180).attr("height",30).attr("fill","#ffebee").attr("rx",5); svg.append("text").attr("x",530).attr("y",150).attr("font-size",12).attr("fill","#c62828").text("🌀 Hurricane Tracks"); }if (stormTypeMap ==="Northeast Blizzards"|| stormTypeMap ==="Both") {// Blizzard tracks (Nor'easters tracking up the coast)const blizzardTracks = [ [{x:280,y:320}, {x:320,y:280}, {x:360,y:230}, {x:400,y:180}, {x:440,y:130}, {x:500,y:90}], [{x:260,y:340}, {x:300,y:300}, {x:340,y:250}, {x:380,y:200}, {x:420,y:150}, {x:470,y:110}], [{x:300,y:350}, {x:340,y:310}, {x:370,y:260}, {x:400,y:210}, {x:440,y:160}, {x:490,y:120}] ];const bcolors = ["#3498db","#2980b9","#1abc9c"]; blizzardTracks.forEach((track, i) => { svg.append("path").attr("d", d3.line().x(d => d.x).y(d => d.y).curve(d3.curveCatmullRom)(track)).attr("stroke", bcolors[i]).attr("stroke-width",3).attr("fill","none"); svg.append("circle").attr("cx", track[0].x).attr("cy", track[0].y).attr("r",5).attr("fill", bcolors[i]); svg.append("text").attr("x", track[track.length-1].x).attr("y", track[track.length-1].y).attr("font-size",16).text("🌨️"); }); svg.append("rect").attr("x",520).attr("y",170).attr("width",180).attr("height",30).attr("fill","#e3f2fd").attr("rx",5); svg.append("text").attr("x",530).attr("y",190).attr("font-size",12).attr("fill","#1565c0").text("🌨️ Blizzard Tracks"); }// Direction annotation svg.append("rect").attr("x",50).attr("y",400).attr("width",400).attr("height",35).attr("fill","white").attr("opacity",0.8).attr("rx",5); svg.append("text").attr("x",250).attr("y",422).attr("text-anchor","middle").attr("font-size",13).attr("font-weight","bold").text("Both storm types generally move from SW → NE in the mid-latitudes");return svg.node();}
31.1.1 💡 Key Observation
Despite forming in very different locations and for very different reasons, both hurricanes (once they curve north) and blizzards travel in the same general direction: from southwest to northeast across the mid-latitudes.
This is NOT a coincidence. Something is steering these storms.
32 Explain: The Global Wind Engine
32.1 🌬️ Why Does the Wind Blow the Way It Does?
To understand storm paths, we need to understand the global circulation of the atmosphere — the “engine” that steers weather systems around the planet.
32.2 Uneven Solar Heating: The Root Cause
The Sun doesn’t heat Earth evenly. The equator receives far more solar energy per unit area than the poles because of the angle at which sunlight hits the surface.
Code
{const width =750;const height =380;const svg = d3.create("svg").attr("width", width).attr("height", height).attr("viewBox",`0 0 ${width}${height}`); svg.append("rect").attr("width", width).attr("height", height).attr("fill","#1a1a2e").attr("rx",10);// Earth (circle)const cx =375, cy =200, r =140; svg.append("circle").attr("cx", cx).attr("cy", cy).attr("r", r).attr("fill","#2980b9");// Latitude bandsconst bands = [ {y1:-1,y2:-0.5,label:"60-90°N",color:"#74b9ff",energy:"Low"}, {y1:-0.5,y2:0,label:"30-60°N",color:"#a29bfe",energy:"Medium"}, {y1:0,y2:0.5,label:"0-30°N",color:"#fdcb6e",energy:"High"}, {y1:0.5,y2:1,label:"0-30°S",color:"#fdcb6e",energy:"High"} ]; bands.forEach(b => {const y1 = cy - b.y1* r;const y2 = cy - b.y2* r;const x1 = cx -Math.sqrt(r*r - (cy-y1)*(cy-y1)) || cx;const x2 = cx +Math.sqrt(r*r - (cy-y1)*(cy-y1)) || cx; svg.append("line").attr("x1", x1).attr("y1", y1).attr("x2", x2).attr("y2", y1).attr("stroke", b.color).attr("stroke-width",1).attr("stroke-dasharray","3,3"); });// Sun raysconst sunX =100;const rays = [ {y: cy -100,angle:30,label:"Spread out → less energy/area",color:"#74b9ff"}, {y: cy,angle:0,label:"Direct → maximum energy/area",color:"#f39c12"}, {y: cy +80,angle:-20,label:"Spread out → less energy/area",color:"#74b9ff"} ]; svg.append("circle").attr("cx",50).attr("cy", cy).attr("r",30).attr("fill","#f39c12"); svg.append("text").attr("x",50).attr("y", cy +5).attr("text-anchor","middle").attr("font-size",20).text("☀️"); rays.forEach(ray => { svg.append("line").attr("x1",90).attr("y1", ray.y).attr("x2", cx - r +20).attr("y2", ray.y+Math.tan(ray.angle*Math.PI/180) *200).attr("stroke", ray.color).attr("stroke-width",2); svg.append("text").attr("x", cx + r +20).attr("y", ray.y+5).attr("font-size",11).attr("fill", ray.color).text(ray.label); });// Energy bar chart on rightconst barData = [{lat:"Equator",energy:100}, {lat:"30°",energy:75}, {lat:"60°",energy:40}, {lat:"90°",energy:15}];const barX =620; barData.forEach((d, i) => {const barW = d.energy*0.8;const barY =100+ i *55; svg.append("rect").attr("x", barX).attr("y", barY).attr("width", barW).attr("height",30).attr("fill", d.energy>60?"#f39c12":"#74b9ff").attr("rx",4); svg.append("text").attr("x", barX -5).attr("y", barY +20).attr("text-anchor","end").attr("font-size",11).attr("fill","white").text(d.lat); svg.append("text").attr("x", barX + barW +5).attr("y", barY +20).attr("font-size",10).attr("fill","#dfe6e9").text(`${d.energy}%`); }); svg.append("text").attr("x",375).attr("y",370).attr("text-anchor","middle").attr("font-size",14).attr("fill","#dfe6e9").attr("font-weight","bold").text("Uneven heating creates a temperature gradient from equator to poles → drives atmospheric circulation");return svg.node();}
Without Coriolis: wind blows straight from H → L pressure
With Coriolis (NH): wind is deflected right → curves clockwise around High pressure, counter-clockwise around Low pressure
This is why tropical trade winds blow from the northeast (not straight south) and mid-latitude westerlies blow from the southwest (not straight north)
32.5 The Jet Stream: The Storm Highway
At the boundary between the Ferrel and Polar cells (~60°N, but it meanders), there is an extremely fast river of air flowing from west to east at high altitude: the jet stream.
Global circulation doesn’t just create wind patterns — it determines where on Earth gets rain and where stays dry.
33.2 Rising Air = Rain, Sinking Air = Dry
Code
precipPatternData = [ {lat:0,name:"Equator (ITCZ)",precip:2000,type:"Rising air → heavy rain",emoji:"🌧️"}, {lat:15,name:"15°N",precip:1200,type:"Transition",emoji:"🌤️"}, {lat:30,name:"30°N (Horse latitudes)",precip:300,type:"Sinking air → DESERTS",emoji:"🏜️"}, {lat:45,name:"45°N (Mid-latitudes)",precip:1000,type:"Frontal lifting → moderate rain",emoji:"🌦️"}, {lat:60,name:"60°N (Polar front)",precip:800,type:"Rising air → rain/snow",emoji:"🌨️"}, {lat:75,name:"75°N",precip:250,type:"Cold sinking air → dry",emoji:"❄️"}, {lat:90,name:"90°N (Pole)",precip:100,type:"Polar desert",emoji:"🧊"}]Plot.plot({title:"Average Annual Precipitation by Latitude",subtitle:"Rising air = wet; Sinking air = dry",width:700,height:380,x: {label:"Latitude (°N)",domain: [0,90]},y: {label:"Annual Precipitation (mm)",domain: [0,2200]},marks: [ Plot.barY(precipPatternData, {x:"lat",y:"precip",fill: d => d.precip>800?"#3498db": d.precip>400?"#f39c12":"#e74c3c",dx:-3,tip:true}), Plot.text(precipPatternData, {x:"lat",y: d => d.precip+80,text:"emoji",fontSize:20}), Plot.text(precipPatternData, {x:"lat",y: d => d.precip+150,text:"type",fontSize:10}) ]})
33.2.1 📝 Connecting Circulation to Precipitation
Why does the equator receive so much rainfall? (Hint: think about the Hadley Cell)
Why are the world’s great deserts located near 30°N/S? (Sahara, Arabian, Mojave…)
NYC is at ~41°N. What type of precipitation mechanism dominates there?
If global wind patterns shifted northward due to warming, how might precipitation patterns change for NYC?
34 Elaborate: Shifting Storm Paths
34.1 🌡️ Could Climate Change Move Storm Tracks?
If the temperature gradient between the equator and poles changes, the circulation cells — and the jet stream — could shift. What would that mean for storms?
{const width =700;const height =400;const svg = d3.create("svg").attr("width", width).attr("height", height).attr("viewBox",`0 0 ${width}${height}`); svg.append("rect").attr("width", width).attr("height", height).attr("fill","#f8f9fa").attr("rx",10); svg.append("text").attr("x",350).attr("y",30).attr("text-anchor","middle").attr("font-size",16).attr("font-weight","bold").text(`Storm Track Shift with ${warmingScenario}°C Warming`);// Latitude axis svg.append("line").attr("x1",60).attr("y1",360).attr("x2",660).attr("y2",360).attr("stroke","#2d3436").attr("stroke-width",2);const latLabels = ["20°N","30°N","40°N","50°N","60°N","70°N"]; latLabels.forEach((l, i) => {const x =80+ i *110; svg.append("text").attr("x", x).attr("y",380).attr("text-anchor","middle").attr("font-size",11).text(l); });// Current storm track density (bell curve around 40-45°N)const currentPeak =300;// x position for 40°Nconst shift = warmingScenario *25;// shift northward with warming// Historical curveconst points = d3.range(80,640,5).map(x => {const y =300*Math.exp(-0.5*Math.pow((x - currentPeak) /100,2));return {x, y}; }); svg.append("path").attr("d", d3.line().x(d => d.x).y(d =>350- d.y).curve(d3.curveBasis)(points)).attr("stroke","#3498db").attr("stroke-width",2).attr("fill","#3498db").attr("fill-opacity",0.15).attr("stroke-dasharray", warmingScenario >0?"5,3":"0");if (warmingScenario >0) {// Shifted curveconst shiftedPoints = d3.range(80,640,5).map(x => {const y =280*Math.exp(-0.5*Math.pow((x - currentPeak - shift) /120,2));return {x, y}; }); svg.append("path").attr("d", d3.line().x(d => d.x).y(d =>350- d.y).curve(d3.curveBasis)(shiftedPoints)).attr("stroke","#e74c3c").attr("stroke-width",3).attr("fill","#e74c3c").attr("fill-opacity",0.2); }// NYC line svg.append("line").attr("x1",310).attr("y1",50).attr("x2",310).attr("y2",355).attr("stroke","#2d3436").attr("stroke-width",1).attr("stroke-dasharray","3,3"); svg.append("text").attr("x",310).attr("y",45).attr("text-anchor","middle").attr("font-size",12).attr("font-weight","bold").text("NYC (41°N)");// Legend svg.append("line").attr("x1",450).attr("y1",70).attr("x2",500).attr("y2",70).attr("stroke","#3498db").attr("stroke-width",2).attr("stroke-dasharray", warmingScenario >0?"5,3":"0"); svg.append("text").attr("x",510).attr("y",74).attr("font-size",11).text("Historical track density");if (warmingScenario >0) { svg.append("line").attr("x1",450).attr("y1",90).attr("x2",500).attr("y2",90).attr("stroke","#e74c3c").attr("stroke-width",3); svg.append("text").attr("x",510).attr("y",94).attr("font-size",11).attr("fill","#e74c3c").text(`Projected (+${warmingScenario}°C)`); }// Impact noteif (warmingScenario >=2) { svg.append("rect").attr("x",100).attr("y",270).attr("width",500).attr("height",50).attr("fill","#fff3e0").attr("rx",8); svg.append("text").attr("x",350).attr("y",293).attr("text-anchor","middle").attr("font-size",13).attr("font-weight","bold").attr("fill","#e65100").text("⚠️ Storm tracks shift poleward — NYC may see fewer but potentially stronger storms"); }return svg.node();}
🌍 As the planet warms, the jet stream and storm tracks are projected to shift poleward — changing which regions get storms and how intense they are! 🌍
35 Elaborate: ENSO — The Pacific’s Weather Remote Control
35.1 🌊 El Niño–Southern Oscillation (ENSO)
ENSO is a cyclical shift in Pacific Ocean temperatures and wind patterns that reorganizes storm tracks, precipitation, and hurricane activity across the entire planet. It is the single most powerful short-term driver of global weather variability — and climate change is making it more extreme.
🌊
Neutral / Normal Conditions
Trade winds blow west along the equator, piling warm water in the western Pacific near Indonesia. Cold, nutrient-rich water upwells off Peru. The Walker Circulation runs normally.
ONI: −0.4 to +0.4°C
Equatorial Pacific cross-section — West (Indonesia) ← → East (South America). Drag the slider to animate.
Intensity:Moderate
📊 ONI (Oceanic Niño Index) — Monthly Record 1950–2025 | Click a bar to jump to that event
🔬 Step-by-step Mechanism
35.1.1 🔑 Key Connections: ENSO and Storm Paths
El Niño → fewer Atlantic hurricanes (increased wind shear) but more Eastern Pacific hurricanes
La Niña → more Atlantic hurricanes (reduced wind shear) — 2005, 2010, 2020 seasons were all La Niña years
El Niño → southern U.S. jet stream dips south, steering storms across the Gulf States into Florida
La Niña → jet stream shifts north, routing storms across the Pacific Northwest and Great Plains
ENSO cycles every 2–7 years and account for ~30% of year-to-year weather variability
Climate change is projected to make extreme El Niño and La Niña events more frequent as the Pacific Ocean warms
36 Evaluate: Storm Path Analysis
36.1 ✅ Assessment: Explaining Storm Trajectories
36.1.1 🧠 Check Your Understanding
Question 1: The prevailing westerlies that steer storms across the mid-latitudes are ultimately caused by:
Code
viewof q1_paths = Inputs.radio( ["The Moon's gravitational pull on the atmosphere","Uneven solar heating between the equator and poles, combined with Earth's rotation","Ocean currents pushing the air along","Volcanic eruptions changing the atmosphere"], {label:"Select the best answer:"})
Code
q1_paths ==="Uneven solar heating between the equator and poles, combined with Earth's rotation"?html`<div style="background: #d4edda; padding: 12px; border-radius: 8px; border-left: 4px solid #28a745;">✅ <strong>Correct!</strong> Uneven heating drives convection (the Hadley, Ferrel, and Polar cells). Earth's rotation (Coriolis effect) deflects these winds, creating the westerlies in the mid-latitudes.</div>`: q1_paths ?html`<div style="background: #f8d7da; padding: 12px; border-radius: 8px; border-left: 4px solid #dc3545;">❌ Think about what creates pressure differences globally, and what deflects the wind.</div>`:html``
Question 2: Why do both hurricanes (after recurvature) and Nor’easters travel from southwest to northeast?
Code
viewof q2_paths = Inputs.radio( ["They are pushed by ocean tides","They are both steered by the mid-latitude westerlies and jet stream","They generate their own westward momentum","The Coriolis effect pushes all storms to the northeast"], {label:"Select the best answer:"})
Code
q2_paths ==="They are both steered by the mid-latitude westerlies and jet stream"?html`<div style="background: #d4edda; padding: 12px; border-radius: 8px; border-left: 4px solid #28a745;">✅ <strong>Correct!</strong> Once a storm enters the mid-latitudes (30°–60°N), it gets picked up by the westerlies and jet stream, which steer it from southwest to northeast regardless of how it formed.</div>`: q2_paths ?html`<div style="background: #f8d7da; padding: 12px; border-radius: 8px; border-left: 4px solid #dc3545;">❌ Think about what moves air in the 30°–60° latitude band.</div>`:html``
Question 3: How might Arctic amplification change storm paths in the future?
Code
viewof q3_paths = Inputs.radio( ["Storms would stop entirely","The weakened temperature gradient could slow the jet stream and create more persistent, wavy patterns","Storms would reverse direction and move east to west","Arctic amplification has no effect on mid-latitude weather"], {label:"Select the best answer:"})
Code
q3_paths ==="The weakened temperature gradient could slow the jet stream and create more persistent, wavy patterns"?html`<div style="background: #d4edda; padding: 12px; border-radius: 8px; border-left: 4px solid #28a745;">✅ <strong>Excellent!</strong> The jet stream's speed depends on the temperature contrast between polar and tropical air. Arctic amplification reduces this contrast, potentially causing the jet to develop larger, slower-moving waves. This means storms can stall and produce prolonged extreme weather.</div>`: q3_paths ?html`<div style="background: #f8d7da; padding: 12px; border-radius: 8px; border-left: 4px solid #dc3545;">❌ Think about what drives the jet stream (temperature gradient) and what happens when the Arctic warms faster than the tropics.</div>`:html``