Public
Edited
Aug 9, 2024
Insert cell
Insert cell
Insert cell
viewof distances = aq
.fromCSV(await FileAttachment('example-wf-impact-ranges@1.csv').text())
.view({ height: 240 })
Insert cell
Insert cell
viewof speciesInfo = aq
.fromCSV(await FileAttachment('species-info.csv').text())
.view({height: 240})
Insert cell
Insert cell
viewof distancesAll = distances
.join(speciesInfo,["species"]).view()
Insert cell
Insert cell
viewof distancesTidy = distancesAll
.fold(['beh_NOAA-cont', 'beh_NOAA-int', 'beh_Wood', 'inj_pk-pts', 'inj_sel-pts-impulsive', 'inj_sel-pts-nonimpulsive','inj_sel-pts-both','beh_NOAA-both'], { as: ['criteria', 'distance'] }).derive({distanceKM: d => d.distance / 1000})
.filter(d => d.distance != null).view()
// .derive({distanceKM: d => d.distance / 1000})
Insert cell
Insert cell
Insert cell
distancesAll.groupby('hearing_group', 'attenuation')
.rollup({ meanDistance: op.mean('beh_NOAA-int'),
sdDistance: op.stdev('beh_NOAA-int') })
.derive({meanDist: d => op.round(d.meanDistance),
sdDist: d => op.round(d.sdDistance)})
.select(aq.not("meanDistance", "sdDistance"))
.orderby(aq.desc('hearing_group'))
.view()
Insert cell
Insert cell
Plot.plot({
title: "Behavioral disturbance distances",
subtitle: "Impact hammering only",
width:700,
y: {
grid: true, label: "Distance",
tickFormat: d => `${d/1000} km`,
},
fx: {label: null, domain: ["LF", "MF", "HF", "PW"]},
color: {legend: true, domain: ["0dB", "6dB", "10dB"]},
marks: [
Plot.ruleY([0]),
Plot.dot(distancesAll.filter(d => d.season === "Summer"),
Plot.dodgeX("middle",
{fx: "hearing_group",
y: "beh_NOAA-int",
fill: "attenuation",
r: 3.5,
channels: {
species: "species",
found: {value: "found", label: "Foundation"},
hammerID: {value: "hammerID", label: "Hammer ID"},
},
tip: {
format: {
species: true,
found: true,
y: (d) => `${d/1000}km`,
fx: false,
fill: false,
}
}}
),
)
]
})
Insert cell
Plot.plot({
title: "Behavioral disturbance distances",
subtitle: "Impact hammering only", width:500,
height: 350,
width: 600,
y: {grid: true, label: "Distance", tickFormat: d => `${d/1000} km`},
fx: {label: null},
color: {legend: true, scheme: "Tableau10"},
symbol: {legend: true},
marks: [
Plot.ruleY([0]),
Plot.dot(distancesAll.filter(
d => (d.attenuation === "10dB") & (d.season==="Summer")),
Plot.dodgeX("middle",
{fx: "hearing_group",
y: "beh_NOAA-int",
fill: "found",
r: 4,
channels: {
species: "species",
found: {value: "found", label: "Foundation"},
hammerID: {value: "hammerID", label: "Hammer ID"},
attenuation: {value: "attenuation", label: "Attenuation"},
},
tip: {
format: {
species: true,
found: true,
y: (d) => `${d/1000}km`,
fx: false,
fill: false,
symbol: false,
}
}}
),
)
]
})
Insert cell
speciesSummary = distancesTidy.filter(d=>
((d.criteria==="beh_NOAA-int") |
(d.criteria==="inj_sel-pts-impulsive")) &
(d.attenuation === "10dB") &
(d.season==="Summer") &
(d.scen === "reg")
)
Insert cell
test = speciesSummary.groupby(["species", "found"]).rollup({ meanDistance: op.mean('distance'),
sdDistance: op.stdev('distance')}).view()
Insert cell
speciesSummary.view(100)
Insert cell
viewof unique = distancesTidy.groupby(["species","attenuation","found", "season", "vibpen", "abundance", "hearing_group", "shortName", "criteria", "distance"]).rollup({"mean": op.mean("distance")}).view()
Insert cell
Plot.plot({
height: 600,
x: {axis: null},
marginLeft: 80,
y: {grid: true, label: "Distance", tickFormat: d => `${d/1000} km`},
marks: [
Plot.barX(unique.filter(d => (d.vibpen === "impact_only") & (d.distance < 17000)),
Plot.binY({x: "count"}, {y: "distance", fx: "season"})
)
]
})
Insert cell
Plot.plot({
marginLeft: 80,
width: 600,
height: 175,
color: {legend: true, scheme: "Blues", reverse: true},
x: {label: "Distance", tickFormat: d => `${d/1000} km`},
y: {axis: null},
fy: {label: null},
marks: [
Plot.ruleX([0]),
Plot.tickX(
unique,
{x: "distance", y: "season",
fy: "found", stroke: "season",
strokeOpacity: 0.3}
),
Plot.tickX(
unique,
Plot.groupY(
{x: "max"},
{x: "distance", y: "season",
fy: "found",
stroke: "black", strokeWidth: 2}
)
)
]
})
Insert cell
distancesTidy.view()
Insert cell
viewof tidyVibe = distancesTidy.filter(
d => (
(d.criteria === "beh_NOAA-both") |
(d.criteria === "inj_sel-pts-both")) &
(d.vibpen === "vib_and_impact") &
(d.attenuation === "10dB") &
(d.season === "Summer")
).view(100)
Insert cell
viewof tidyImpact = distancesTidy.filter(
d => ((d.criteria === "beh_NOAA-int") |
(d.criteria === "inj_sel-pts-impulsive")) &
(d.vibpen === "impact_only") &
(d.attenuation === "10dB") &
(d.season === "Summer")
).view()
Insert cell
tidyImpact.filter( d => d.species === "Fin whale").view()
Insert cell
Plot.plot({
y: {grid: true, label: null},
x: {label: "Distance", tickFormat: d => `${d/1000} km`},
marginLeft: 120,
height: 500,
width: 400,
color: {legend: true, scheme: "Tableau10"},
symbol: {legend: true},
marks: [
Plot.dot(tidyVibe, {x: "distance", y: "shortName",
fill: "found", r: 6, symbol: "hammerID", stroke: "black",
channels: {
shortName: {value: "shortName", label: "Species"},
species: {value: "species", label: "Species"},
found: {value: "found", label: "Foundation"},
instSch: {value: "instSch", label: "Inst. Sch."},
hammerID: {value: "hammerID", label: "Hammer ID"},
distance: {value: "distance", label: "Distance"}
},
tip: {
format: {
shortName: false,
species: true,
found: true,
instSch: true,
distance: (d) => `${d/1000} km`,
x: false,
fill: false,
y: false,
symbol: false,
}
},
})
]
})
Insert cell
function markPointInterval(data, {y, x, fill, text, fillText}){
const marks = [
//range
Plot.ruleY(data,
Plot.groupY({x1: "min", x2: "max"},
{y: y, x: x, stroke: fill, strokeWidth:2})
),
//quartiles IQR
Plot.ruleY(data,
Plot.groupY({x1: (D) => d3.quantile(D, 0.25),x2: (D) => d3.quantile(D, 0.75)},
{y: y, x: x, stroke: fill, strokeWidth:4.5})),
//mean dot
Plot.dot(data,
Plot.groupY({x: "mean"},
{y: y, x: x, fill: fill, r:9})),
//mean text
Plot.text(data,
Plot.groupY({x: "mean", text: d=> d3.mean(d).toFixed(1)},
{y: y, x: x, fill: fillText, text: text,
fontSize:8})),
]

return marks
}
Insert cell
plotFoundCompare(tidyVibe)
Insert cell
function plotFoundCompare(data) {
return Plot.plot({
width:500,
height:300,
y: {label:null, tickSize:0, label:null, axis:null},
x: {grid:true, tickSize:0, label: "Distance (km)"},
color: {scheme: "Tableau10"},
facet: {data: data, y: "found", label:null},
marginLeft:80,
marginBottom:40,
marks: [
//density plot
Plot.areaY(data,
Plot.binX({y: 'count'},{x: "distanceKM", fill: 'found', fillOpacity: 0.85, curve: 'basis', thresholds:40, stroke:'found', strokeWidth:2}
)),
//custom mark to create point interval
markPointInterval(data,
{y:0, x:"distanceKM", text: "distanceKM", fillText:"white", fill: 'black'}),
//jitter for each observation
Plot.dot(data, {x: d => d.distanceKM, y: d=> -10 + Math.random()*3, r:4,
fill: "found", dy:-10, stroke:"white", strokeWidth:0.5,
//customize tooltip on hover with channels and tip format
channels: {species: "species", found: "found", distance: "distanceKM"},
tip: {format: {fill: false, x: false, y: false, fy: false}}}),
]
})}
Insert cell
viewof medianByFoundation = tidyImpact.groupby('found')
.rollup({ medDistance: op.median('distanceKM'),
meanDistance: op.mean('distanceKM'),
})
// .derive({medDist: d => op.round(d.medDistance)})
// .select(aq.not("medDistance"))
.view()
Insert cell
distancesTidy
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
viewof table = Inputs.table(search)
Insert cell
tidyObjects = distancesTidy.objects()
Insert cell
Insert cell
import {aq, op} from "@uwdata/arquero"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more