Public
Edited
Oct 8, 2024
3 forks
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
createTimeSeries = ({
dateGroup = 'months',
timeColumn = 'time',
categoryColumn='family',
categoryLimit,
filterFn,
categoryFilterFn,
valueColumn='sampleSizeValue',
calcMethod='sumOfValueColumn',
excludeUnclassified = false
})=>{
var day = 1000*60*60*24
var month = 30 * day
function padStr(str){
return String(str).length < 2 ? `0${str}` : str
}

function getValue(row){
return valueColumn === 'count' ? 1 : row[valueColumn]
}
const calcMethods = {
sum: (categoryRows, totalSumOfValue, filteredTotalSumOfValue)=>{
return d3.sum(categoryRows.map(getValue))
},
percentageOfAll: (categoryRows, totalSumOfValue, filteredTotalSumOfValue)=>{
console.log(categoryRows)
return +((d3.sum(categoryRows.map(getValue))/totalSumOfValue)*100).toFixed(2)
},
percentageOfVisualized: (categoryRows, totalSumOfValue, filteredTotalSumOfValue) => {
return +((d3.sum(categoryRows.map(getValue))/filteredTotalSumOfValue)*100).toFixed(2)
}
}
const dateGroupFns = {
months:(d)=> `${d.getUTCFullYear()}-${padStr(d.getUTCMonth())}-01T00:00:00Z`,
years:d=>`${d.getUTCFullYear()}`,
seasonalMonths:d=>`2001-${padStr(d.getUTCMonth() + 1)}-15T00:00:00Z`
}
const resolutionsMap = {
months: day * 30,
years: day * 365,
seasonalMonths: day*30
}
const preFilter = false
const fixedData = rawData.map(d=>{
return {
...d,
[categoryColumn]: d[categoryColumn] || (
excludeUnclassified ? null : 'Unclassified at selected taxon level'
)
}
}).filter(d=>d[categoryColumn] !== null)
const dataToUse = preFilter
? (filterFn ? fixedData.filter(filterFn) : fixedData.slice())
: fixedData.slice()
const allByCategory = _.groupBy(dataToUse,d=>d[categoryColumn])
categoryFilterFn = categoryFilterFn || (()=>true)
const categories = Object.keys(allByCategory)
.map(cat=>({label:cat,records:allByCategory[cat]}))
.sort((a,b)=>b.records.length - a.records.length)
.filter(categoryFilterFn)
.slice(0,categoryLimit || -1)
.map(c=>c.label)


const byDate = _.groupBy(dataToUse,d=>dateGroupFns[dateGroup](d[timeColumn]));
if(dateGroup === 'seasonalMonths'){
const first = '2001-01-15T00:00:00Z'
const last = '2001-12-15T00:00:00Z'
if(!byDate[first]){
byDate[first] = []
}
if(!byDate[last]){
byDate[last] = []
}
}
const out = Object.keys(byDate).map(timeCode=>{
console.log('byCategory', _.groupBy(byDate[timeCode],d=>d[categoryColumn]))
const tot = d3.sum(byDate[timeCode].map(getValue))
const binData = preFilter
? byDate[timeCode]
: filterFn ? byDate[timeCode].filter(filterFn) : byDate[timeCode].slice()
const byCategory = _.groupBy(binData,d=>d[categoryColumn])

const filteredTot = d3.sum(categories.map(c=>(byCategory[c] || []).map(getValue)).flat(Infinity))
//return Object.keys(byCategory).filter(category=>categories.indexOf(category) >= 0).map(category=>{
return categories.map(category=>{
return {
time: new Date(timeCode), // dateGroup === 'seasonalMonths' ? new Date(timeCode).getUTCMonth() :
label: category,
a: byCategory[category],
sum: byCategory[category] ? d3.sum(byCategory[category].map(d=>d[valueColumn])) : 0,
tot,
filteredTot,
value: byCategory[category] ? (calcMethods[calcMethod](byCategory[category], tot, filteredTot ) || null) : null
}
})
}).flat(Infinity).sort((a,b)=>{
return +a.time-+b.time
})

out.byCategory = _.groupBy(out,r=>r.label)
out.interval = dateGroup.match(/month/i) ? 'months' : 'years'
return out

}
Insert cell
Insert cell
Insert cell
Insert cell
// import {StackedAreaChart} from "@d3/normalized-stacked-area-chart/2"
Insert cell
Insert cell
import {Swatches} from "@d3/color-legend"
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