360info-tracker-ocean-temperatures.pages.dev Open in urlscan Pro
188.114.96.3  Public Scan

Submitted URL: https://360info-tracker-ocean-temperatures.pages.dev/
Effective URL: https://360info-tracker-ocean-temperatures.pages.dev/vis-monthly/
Submission: On July 15 via automatic, source certstream-suspicious — Scanned from NL

Form analysis 3 forms found in the DOM

<form class="oi-ec050e"><select class="oi-ec050e-input" name="input">
    <option value="0">Arabian Sea</option>
    <option value="1">Arctic Ocean</option>
    <option value="2">Atlantic Ocean</option>
    <option value="3">Bay of Bengal and Andaman Sea</option>
    <option value="4">Global (excl. polar regions)</option>
    <option value="5">Global 85s To 85n</option>
    <option value="6">Indian Ocean</option>
    <option value="7">Iod East</option>
    <option value="8">Iod West</option>
    <option value="9">Mediterranean Sea</option>
    <option value="10">Nino1</option>
    <option value="11">Nino2</option>
    <option value="12">Nino3</option>
    <option value="13">Nino3 4</option>
    <option value="14">Nino4</option>
    <option value="15">North Atlantic</option>
    <option value="16">North Pacific</option>
    <option value="17">Pacific Ocean</option>
    <option value="18">South Atlantic</option>
    <option value="19">South Pacific</option>
    <option value="20">Southern Ocean</option>
  </select></form>

<form class="oi-ec050e"><select class="oi-ec050e-input" name="input">
    <option value="0">Yearly average</option>
    <option value="1">January</option>
    <option value="2">February</option>
    <option value="3">March</option>
    <option value="4">April</option>
    <option value="5">May</option>
    <option value="6" selected="">June</option>
    <option value="7">July</option>
    <option value="8">August</option>
    <option value="9">September</option>
    <option value="10">October</option>
    <option value="11">November</option>
    <option value="12">December</option>
  </select></form>

<form class="oi-ec050e oi-ec050e-checkbox">
  <div>
    <label><input type="checkbox" name="input" value="0" checked="">Compare to the 1986–2015 baseline</label>
  </div>
</form>

Text Content

OCEAN TEMPERATURES

James Goldie, 360info

Data: NOAA PSL

GET THIS MAP

Click to copy this into your story

import { aq, op } from "@uwdata/arquero"
Plot = import("https://esm.run/@observablehq/plot")

dataPath = "https://raw.githubusercontent.com/" +
  "360-info/tracker-ocean-temperatures/main/data/" +
  "monthly-all.csv"

// get the latest monthly data
allData = aq.loadCSV(dataPath, {
  parse: {
    temperature: Number,
    date: op.parse_date
  }
})

  import {aq as aq, op as op} from "@uwdata/arquero"


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, …}
dataPath =
"https://raw.githubusercontent.com/360-info/tracker-ocean-temperatures/main/data/monthly-all.csv"
allData = Table: 3 cols x 10815 rows {_names: Array(3), _data: Object, _total:
10815, _nrows: 10815, _mask: null, _group: null, _order: null, _params:
undefined, _index: null, _partitions: null}

function regionFormatter(str) {  
    return str
      .replaceAll("_", " ")
      .replace(/\w\S*/g,  
        function (txt) {  
            return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();  
        })
      .replaceAll("60s To 60n", "(excl. polar regions)")
      .replaceAll("Of", "of")
      .replaceAll("And ", "and ")
}

// get a map of unique region names in the data for the dropdown menu
// (remove a few that we don't want to show in this version)
allRegions = allData
  .select("region")
  .dedupe()
  .array("region")

allRegionsMap = new Map(allRegions.map(d => [regionFormatter(d), d]))

regionFormatter = ƒ(str)
allRegions = Array(21) ["arabian_sea", "arctic_ocean", "atlantic_ocean",
"bay_of_bengal_and_andaman_sea", "global_60s_to_60n", "global_85s_to_85n",
"indian_ocean", "iod_east", "iod_west", "mediterranean_sea", "nino1", "nino2",
"nino3", "nino3_4", "nino4", "north_atlantic", "north_pacific", "pacific_ocean",
"south_atlantic", "south_pacific", …]
allRegionsMap = Map(21) {"Arabian Sea" => "arabian_sea", "Arctic Ocean" =>
"arctic_ocean", "Atlantic Ocean" => "atlantic_ocean", "Bay of Bengal and Andaman
Sea" => "bay_of_bengal_and_andaman_sea", "Global (excl. polar regions)" =>
"global_60s_to_60n", "Global 85s To 85n" => "global_85s_to_85n", "Indian Ocean"
=> "indian_ocean", "Iod East" => "iod_east", "Iod West" => "iod_west",
"Mediterranean Sea" => "mediterranean_sea", "Nino1" => "nino1", "Nino2" =>
"nino2", "Nino3" => "nino3", "Nino3 4" => "nino3_4", "Nino4" => "nino4", "North
Atlantic" => "north_atlantic", "North Pacific" => "north_pacific", "Pacific
Ocean" => "pacific_ocean", "South Atlantic" => "south_atlantic", "South Pacific"
=> "south_pacific", …}

viewof selectedRegion = Inputs.select(allRegionsMap)

calendarMonths = [
  "January", "February", "March", "April", "May", "June", "July", "August",
  "September", "October", "November", "December"]
possibleMonths = new Map([
  ["Yearly average", 0], ...calendarMonths.map((d, i) => [d, i + 1])])

previousMonth = (new Date()).getMonth()
defaultMonth = (previousMonth) == 0 ? 12 : previousMonth
viewof selectedPeriod = Inputs.select(possibleMonths, {
  value: defaultMonth
})

// this feels overwrought
selectedPeriodLabel = selectedPeriod >= 1 ?
  calendarMonths[selectedPeriod - 1] :
  "Yearly average"

viewof showAnomalies = Inputs.checkbox(
  new Map([["Compare to the 1986–2015 baseline", "anomalies"]]), {
    value: ["anomalies"]
  })

Arabian SeaArctic OceanAtlantic OceanBay of Bengal and Andaman SeaGlobal (excl.
polar regions)Global 85s To 85nIndian OceanIod EastIod WestMediterranean
SeaNino1Nino2Nino3Nino3 4Nino4North AtlanticNorth PacificPacific OceanSouth
AtlanticSouth PacificSouthern Ocean
selectedRegion = "arabian_sea"
calendarMonths = Array(12) ["January", "February", "March", "April", "May",
"June", "July", "August", "September", "October", "November", "December"]
possibleMonths = Map(13) {"Yearly average" => 0, "January" => 1, "February" =>
2, "March" => 3, "April" => 4, "May" => 5, "June" => 6, "July" => 7, "August" =>
8, "September" => 9, "October" => 10, "November" => 11, "December" => 12}
previousMonth = 6
defaultMonth = 6
Yearly
averageJanuaryFebruaryMarchAprilMayJuneJulyAugustSeptemberOctoberNovemberDecember
selectedPeriod = 6
selectedPeriodLabel = "June"
Compare to the 1986–2015 baseline
showAnomalies = Array(1) ["anomalies"]

baselineStart = 1986
baselineEnd = 2015

// extract month and year, then filter on user selections
regionData = allData
  .params({
    selectedPeriod: selectedPeriod,
    selectedRegion: selectedRegion,
    baselineStart: baselineStart,
    baselineEnd: baselineEnd
  })
  .filter(d => d.region == selectedRegion)
  .derive({
    month: d => op.month(d.date) + 1,
    year: d => op.year(d.date)
  })
  .groupby("month")
  .derive({
    baselineYearTemp: d =>
      (d.year >= baselineStart && d.year <= baselineEnd) ?
        d.temperature : null
  })
  .derive({
    anomaly: d => d.temperature - op.mean(d.baselineYearTemp)
  })
  .derive({
    anomalySign: d => d.anomaly >= 0
  })
  .ungroup()

filteredData = regionData.filter(d => selectedPeriod == d.month)

// separately calculate annual data if that's selected
// (drop incomplete years, and calculate a baseline if the data allows)
annualTemps = regionData
  .params({
    baselineStart: baselineStart,
    baselineEnd: baselineEnd
  })
  .groupby("year")
  .derive({
    ob_number: op.row_number()
  })
  .rollup({
    temperature: op.mean("temperature"),
    n_obs: d => op.max(d.ob_number),
  })
  .ungroup()
  .filter(d => d.n_obs == 12)
  .derive({
    date: d => op.parse_date(d.year + "-07-01T00:00:00Z"),
    baselineYearTemp: d =>
      (d.year >= baselineStart && d.year <= baselineEnd) ?
        d.temperature : null
  })
  .derive({
    anomaly: d => d.temperature - op.mean(d.baselineYearTemp)
  })
  .derive({
    anomalySign: d => d.anomaly >= 0
  })

baselineStart = 1986
baselineEnd = 2015
regionData = Table: 8 cols x 515 rows (10815 backing) {_names: Array(8), _data:
Object, _total: 10815, _nrows: 515, _mask: s, _group: null, _order: null,
_params: Object, _index: null, _partitions: null}
filteredData = Table: 8 cols x 43 rows (10815 backing) {_names: Array(8), _data:
Object, _total: 10815, _nrows: 43, _mask: s, _group: null, _order: null,
_params: Object, _index: null, _partitions: null}
annualTemps = Table: 7 cols x 42 rows (45 backing) {_names: Array(7), _data:
Object, _total: 45, _nrows: 42, _mask: s, _group: null, _order: null, _params:
Object, _index: null, _partitions: null}

selectedSeries = selectedPeriod == 0 ? annualTemps : filteredData

// some options for conditionally showing parts of the chart:
// - whether to show original temps or anomalies
// - the window size to use for smoothing
// showTemps = showAnomalies.includes("anomalies")

// window size in _years_
windowSize = 15

Plot.plot({
  marks: [
    // if original temps: show line and smoother
    showAnomalies.includes("anomalies") ? null :
      Plot.lineY(selectedSeries, {
        x: "date",
        y: showAnomalies.includes("anomalies") ? "anomaly" : "temperature",
        stroke: "lightgrey",
        strokeWidth: 1,
        tip: true,
        title: d => `${selectedPeriodLabel} ${d.year}\n${d3.format("-.2f")(d.temperature)} °C\n\n${d3.format("+.2f")(d.anomaly)} °C compared to\n1986-2015 baseline`,
        ariaDescription: d => `For ${selectedPeriodLabel} ${d.year}, the temperature was ${d3.format("-.2f")(d.temperature)} °C, or ${d3.format("+.2f")(d.anomaly)} °C compared to the 1986-2015 baseline.`
      }),
    showAnomalies.includes("anomalies") ? null :
      Plot.lineY(selectedSeries, Plot.windowY(windowSize, {
        x: "date",
        y: showAnomalies.includes("anomalies") ? "anomaly" : "temperature",
        stroke: "black",
        tip: true,
        title: d => `${selectedPeriodLabel} ${d.year}\n${d3.format("-.2f")(d.temperature)} °C\n\n${d3.format("+.2f")(d.anomaly)} °C compared to\n1986-2015 baseline`,
        ariaDescription: d => `For ${selectedPeriodLabel} ${d.year}, the temperature was ${d3.format("-.2f")(d.temperature)} °C, or ${d3.format("+.2f")(d.anomaly)} °C compared to the 1986-2015 baseline.`
      })),
    // if anomalies: show bars, shaded by sign
    showAnomalies.includes("anomalies") ? Plot.ruleY([0]) : null,
    showAnomalies.includes("anomalies") ?
      Plot.rectY(selectedSeries, {
        x: "date",
        y: "anomaly",
        fill: "anomalySign",
        interval: d3.utcYear,
        tip: true,
        title: d => `${selectedPeriodLabel} ${d.year}\n${d3.format("-.2f")(d.temperature)} °C\n\n${d3.format("+.2f")(d.anomaly)} °C compared to\n1986-2015 baseline`,
        ariaDescription: d => `For ${selectedPeriodLabel} ${d.year}, the temperature was ${d3.format("-.2f")(d.temperature)} °C, or ${d3.format("+.2f")(d.anomaly)} °C compared to the 1986-2015 baseline.`
      }) : null
  ],
  y: {
    label: showAnomalies.includes("anomalies") ?
      "Temperature (compared to " + baselineStart + "–" + baselineEnd +
        " baseline)" :
      "Temperature",
    labelArrow: "none",
    tickFormat: (d) => showAnomalies.includes("anomalies") ?
      `${d3.format("+.1f")(d)} °C` :
      `${d3.format("-.1f")(d)} °C`
  },
  x: {
    label: "Year",
    labelArrow: "none"
  },
  color: {
    domain: [true, false],
    range: ["#d73027", "#4575b4"]
  },
  marginLeft: 62,
  marginBottom: 40,
  style: {
    fontSize: 14
  }
})

selectedSeries = Table: 8 cols x 43 rows (10815 backing) {_names: Array(8),
_data: Object, _total: 10815, _nrows: 43, _mask: s, _group: null, _order: null,
_params: Object, _index: null, _partitions: null}
windowSize = 15
−0.8 °C−0.6 °C−0.4 °C−0.2 °C+0.0 °C+0.2 °C+0.4 °C+0.6 °C+0.8 °CTemperature
(compared to 1986–2015 baseline)198519901995200020052010201520202025Year

micro = require("micromodal@0.4.10")
micro.init({
  awaitOpenAnimation: true,
  awaitCloseAnimation: true
});

micro = Object {init: ƒ(e), show: ƒ(e, t), close: ƒ(e)}
undefined


USE + REMIX

These charts, as well as the analyses that underpin them, are available under a
Creative Commons Attribution 4.0 licence.

The data comes from NOAA PSL and Fay & McKinley (2014). Please acknowledge
360info and our data sources when you use these charts and data.

EMBED THIS CHART IN YOUR ARTICLE

Copy and paste the following code:

<div style="position:relative; padding-bottom: 99%"> <iframe allow="fullscreen; clipboard-write self https://aug2023.360info-tracker-ocean-temperatures.pages.dev" allowfullscreen="true" src="https://aug2023.360info-tracker-ocean-temperatures.pages.dev/vis-monthly/" title="Interactive: ocean temperatures" style="width:100%; height:100%; position: absolute; top: 0; left: 0; border:none; background-color: white;" scrolling="no"></iframe>> </div>

This content is subject to 360info’s Terms of Use.

GET THE DATA AND CODE

Visit the GitHub repository to:

 * Download the live data
 * Recreate or remix the chart


ABOUT THIS OCEAN TEMPERATURE TRACKER

This chart tracks the average temperatures at the sea surface. The dataset we
use is OISST v2, created by National Oceanic and Atmospheric Administration’s
Physical Sciences Laboratory.

OISST updates both daily and monthly (we show the monthly updates here). The
dataset blends sea surface temperature observations from satellites, ships,
buoys and Argo floats (small submersibles that patrol the oceans, dipping below
the surface periodically to measure the deep ocean). These observations are
compared using their strengths and weaknesses to fill out the Earth’s surface.

In this chart, you can choose which month of the year to focus on (or to look at
the yearly average), as well as which ocean or sea to focus on. In this version,
we have observations for the major oceans, as well as the Mediterranean Sea, the
Bay of Bengal and Andaman Sea and the global average (both excluding polar
regions and running up to 85°). We also have several climate monitoring regions
used to measure phenomena like the El Niño Southern Oscillation (ENSO) and the
Indian Ocean Dipole.

In order to choose the ocean regions, we rely on the RECCAP2-ocean project,
which uses ocean “masks” published by Fay & McKinley (2014) under Creative
Commons Attribution 3.0 (CC BY 3.0). These regions are slightly different to
those used by NOAA, so you may see small differences reported when comparing
against other datasets.

We also use a slightly more recent “baseline” (1986-2015) than some other
dataets, as this dataset begins in the early 1980s. The baseline chosen affects
the actual numbers reported but not the trends you see. You can see the actual
temperatures by hovering over the bars or by tapping the checkbox to toggle them
on.