Public
Edited
Mar 23
Paused
1 fork
12 stars
Topographic MappingBubble mapChoroplethAccess to Family planningMD Counties Total Cases MapTendance de la production des déchets en Union Européenne
Andy's Walgreens COVID-19 Tracker Tracker
Election Maps for Incomplete ResultsA better U.S. house election results map?1983 Mayoral Election, Dot density mapsMastodon 🐘Cheat sheet bertinBertin.js: regular squaresWaterlinesNeumorphism Contour Density MapCartographic DoodlesStars and constellationsPlot: Grid choroplethHello Polygon MorphingMapping with pie chartsU.S. Geographic DataHow big are countries... like really!AttitudeB&W ChoroplethWeb Mercator Tile VisibilityMARTINI: Real-Time RTIN Terrain Mesh"Magnifying-Glass" projectionsTissot's indicatrixAntipodal mapMapping gridded data with a Voronoi diagramA Map of Every BuildingUrbano Monti’s Planisphere (1587)Bivariate choroplethDIY HillshadeMapbox Map MakerWorld tourHillshaderSimplified Earth with curved shapesHexbin mapInner glowNicolosi vs. StereographicData-driven projections: Darwin's worldSatellite ground track visualizerDirection to shoreHello, OpenLayers!U.S. airports VoronoiHello, NYC Geosearch API!Mapbox Fly-ToSpilhaus shoreline mapWalmart’s growthHow well does population density predict U.S. voting outcomes?Drawing maps from geodata with D3 & ObservableHexgrid maps with d3-hexgridTissot's indicatrixWorld airports VoronoiSwiss Elevation Line GraphsVector tilesVersor draggingOrthographicSolar TerminatorStreaming ShapefilesFake GlobesPeirce Quincuncial🍃 LeafletU.S.G.S. World Earthquake MapUsing Mapbox GL JSUsing Google Maps
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
variantsUS.slice(-20)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
cdcWastewaterURL = "https://www.cdc.gov/wcms/vizdata/NCEZID_DIDRI/NWSSRegionalLevel.json"
Insert cell
Insert cell
cdcWasteWaterData
X
date
Y
wastewater
Color
region
Size
Facet X
Facet Y
Mark
line
Type Chart, then Shift-Enter. Ctrl-space for more options.

Insert cell
Plot.plot({
width,
color: { legend: true },
x: { grid: true },
y: { grid: true },
title: "COVID-19 Wastewater Viral Activity Level",
caption: "Source: https://www.cdc.gov/nwss/rv/COVID19-nationaltrend.html",
marks: [
Plot.lineY(cdcWasteWaterData.filter(d=>d.date_period==="All Results"), {
x: "date",
y: "wastewater",
stroke: "region",
tip: true
})
]
})
Insert cell
cdcWasteWaterDataRaw = d3.json(cdcWastewaterURL)
Insert cell
cdcWasteWaterData = cdcWasteWaterDataRaw.flatMap(d=>{
let date = new Date(d.Week_Ending_Date);
let date_period = d.Data_Collection_Period;
let keys = ["Midwest","National","Northeast","South","West",];
return keys.map(region=>({
date,
region,
date_period,
wastewater:Number(d[region+"_WVAL"]),
}));
}).filter(d=>d.date_period==="All Results")
Insert cell
allData.filter(d=>d.State === "Texas").slice(-10)

Insert cell
Insert cell
checkForNewColumns()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
lastTimestamp = allData.slice().reverse().find(d=>d.State === "Florida" && (d["test_number_pos"])).Date


Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
lastDate = new Date(lastTimestamp)
Insert cell
Insert cell
Insert cell
//stateData = d3.csv("https://grep.lvab.workers.dev/?h=1&u=https://labvegas.com/data/covid19/walgreens/dashboard-Tracker_Aggregation.csv&s="+(stateSelected ? "^" + stateSelected : ""), d3.autoType)
Insert cell
stateData.slice(-10)
Insert cell
Insert cell
Insert cell
stateDataTotals = getStateDataTotals(stateData)
Insert cell
stateDataTotals.slice(-20)
Insert cell
viewof stateDataTable = Inputs.table(stateDataTotals)
Insert cell
Insert cell
allDataTotals = getStateDataTotals(allData)
Insert cell
Insert cell
Insert cell
lastVariantDate = Math.min(lastTimestamp, allBA4.reduce((o,r)=>{o = Math.max(o,r.Date); return o},0))
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
tests.slice(-20)
Insert cell
multiStatesSelected = regionSelected !== "0" ? regionToStates[regionSelected] : false
Insert cell
variants = getVariantsMult(allBA4.filter(r => multiStatesSelected ? multiStatesSelected[r.State] : r.State === stateSelected))
Insert cell
variants.slice(-20)
Insert cell
//plotVariants(variantsAllStates.filter(d=>d.Date>new Date(2022, 2, 22)),"Cases scaled",[new Date(2022, 2, 22), Date.now()])
Insert cell
getVariants = function(data, keys = ["Other","BA.1","BA.2","BA.4+BA.5"] ) {
//const keys = ["Other","BA.1","BA.2","BA.4+BA.5","BA.1+BA.4+BA.5"];
//const keys = ["Other","BA.1+BA.4+BA.5","BA.2"];
let byStateDate = {};
let v = data.flatMap((r,i) => {
let a = [];
let peak = variantPeaks[r.State]["BA.4+BA.5 Cases"];
keys.forEach(k => {
let p = r[k + " Proportion"];
let p7 = r[k + " Proportion 7day"];
let p9 = r[k + " Proportion 9day"];
let cases = casesByDateAndState[r.State][r.Date];

let logRatio = Math.log2(p)-Math.log2(1-p);
let d = {
Date:r.Date,
State:r.State,
Variants: k,
Samples: r[k],
Samples3day: r[k +" 3day"],
Samples7day: r[k +" 7day"],
Samples9day: r[k +" 9day"],
Proportion: p,
Proportion7day: p7,
Proportion9day: p9,
LogRatio: logRatio,
Cases: r[k + " Cases"],
"Cases scaled": r[k + " Cases"]/peak,
Days: r.Days,
};
a.push(d);
byStateDate[k] = byStateDate[k] || {};
byStateDate[k][r.State] = byStateDate[k][r.State] || {};
byStateDate[k][r.State][r.Date] = d;
let period = 7;
let lastWeek = byStateDate[k][r.State][r.Date - period*24*60*60*1000];
if (lastWeek && p && p < 1) {
let lastP = lastWeek.Proportion;
if (lastP && lastP < 1){
let relativeGrowth = Math.pow(p/(1-p) / (lastP/(1-lastP)),1/period) - 1;
d.RelativeGrowth = relativeGrowth;
}
let twoWeeksAgo = byStateDate[k][r.State][r.Date - 2*period*24*60*60*1000];
if (twoWeeksAgo) {
let lastP2 = twoWeeksAgo.Proportion;
if (lastP2 && lastP2 < 1){
let relativeGrowth2weeks = Math.pow(p/(1-p) / (lastP2/(1-lastP2)),1/2/period) - 1;
d.RelativeGrowth2weeks = relativeGrowth2weeks;
let relativeGrowth2 = Math.pow(lastP/(1-lastP) / (lastP2/(1-lastP2)),1/period) - 1;
d.RelativeGrowthChange = (d.RelativeGrowth - relativeGrowth2)/period;
}
}

}
});
a.push({
Date:r.Date,
State:r.State,
Variants: "All",
Cases: r.Positives,
});
return a;
});
return v;
}
Insert cell
testBA4filtered = allBA4.filter(d=>testStates[d.State])
Insert cell
testVariants = getVariantsMult(testBA4filtered)

Insert cell
testVariants.slice(-20)
Insert cell
testDataTotals.slice(-5)[0]
Insert cell
testDataTotals = getStateDataTotals(testBA4filtered)
Insert cell
testStates = ({California:0,Texas:1,Utah:0,"North Carolina":0,Alaska:1,})
Insert cell
Select a data source…
Type Chart, then Shift-Enter. Ctrl-space for more options.

Insert cell
stateTable("Test",testAllDataTotals,testVariants)
Insert cell
testAllData.slice(-20)
Insert cell
testAllData = allData.filter(d=>testStates[d.State])
Insert cell
{
let o = testAllDataTotals.slice(-1)[0];
let o2 = {};
let keys = ["State","3day_mvPreOmiBA2_nmrtr","3day_mvPreOmiBA11_nmrtr"];
keys.forEach(k=>o2[k] = o[k]);
return o2;
}
Insert cell
testAllDataTotals = getStateDataTotals(testAllData)
Insert cell
getVariantsMult = function(data) {
let a = [];
let m = {};
data.forEach((r,i) => {
const keys = ["Other","BA.1","BA.2","BA.4+BA.5"];
//const keys = ["BA.4+BA.5","BA.1","BA.2","Other"];
//const keys = ["BA.1+BA.4+BA.5","BA.2","Other"];
let peak = variantPeaks[r.State]["BA.1 Cases"];

keys.forEach(k => {
let p = r[k + " Proportion"];
let cases = casesByDateAndState[r.State][r.Date];
if (!m[r.Date]) {
m[r.Date] = {
};
}

if (!m[r.Date][k]) {
m[r.Date][k] = {
Date:r.Date,
State:r.State,
Variants: k,
Samples: r[k] || 0,
TotalSamples: p ? Math.round(r[k]/p) : 0,
Samples3day: r[k +" 3day"] || 0,
Samples9day: r[k +" 9day"] || 0,
Samples7day: r[k +" 7day"] || 0,
Samples1day: r[k +" 1day"] || 0,
Proportion: p,
Cases: r[k + " Cases"] || 0,
"Cases scaled": (r[k + " Cases"]||0)/peak,
Days: r.Days,
StateCount: 1,
}
}
else {
let o = m[r.Date][k];
o.State += ", " + r.State;
o.Samples += r[k] || 0;
o.TotalSamples += p ? Math.round(r[k]/p) : 0;
o.Samples3day += r[k +" 3day"] || 0;
o.Samples7day += r[k +" 7day"] || 0;
o.Samples9day += r[k +" 9day"] || 0;
o.Samples1day += r[k +" 1day"] || 0;
o.Proportion = o.Samples/o.TotalSamples;
o.Cases += r[k + " Cases"] || 0;
o["Cases scaled"] = o.Cases/peak;
o.Days += r.Days;
o.StateCount++;
}
if (r.Date == 1687305600000-5*1000*24*60*60) {
//console.log("debug ",m[r.Date][k],r);
}
});
if (r.Date < firstPlotDate) {
return ;
}
if (!m[r.Date].All) {
m[r.Date].All = {
Date:r.Date,
State:r.State,
Variants: "All",
Cases: r.Positives
}
}
else {
m[r.Date].All.Cases += r.Positives;
}
let keysToTotal = {
"Samples":"",
"Samples1day":" 1day",
"Samples3day":" 3day",
"Samples7day":" 7day",
"Samples9day":" 9day",
};
keys.forEach(k => {
Object.entries(keysToTotal).forEach( entry => {
let ko = entry[0];
let ki = entry[1];
m[r.Date].All[ko] = (m[r.Date].All[ko] || 0) + (r[k + ki]||0);
});
});
if (r.State == "Alaska" && r.Date == lastDate-1*1000*24*60*60) {
//debugger;
}
});
Object.values(m).forEach(mm => {
Object.values(mm).forEach(r => {
a.push(r);
});
});
console.log("getVariantsMult returning",a);
return a;
}
Insert cell
Insert cell
Insert cell
totalPositive = d3.sum(allBA4, d=>d.Positives)/7
Insert cell
Insert cell
Insert cell
transitionsBA2toBA4 = getTransitions("BA.2","BA.4+BA.5")
Insert cell
Insert cell
function timeStampToDateString(d) {
return (new Date(d)).toGMTString().slice(0,16);
}
Insert cell
lastVariantDate
Insert cell
lastTimestamp
Insert cell
currentBA4 = allBA4.filter(d => Math.abs(parseInt(d.Date) - (lastVariantDate - 1000*60*60*24*(numberOfDays-mapDay))) < 1000*60*60*1).map(d => ({...d,Date: timeStampToDateString(d.Date)}))
Insert cell
Insert cell
Insert cell
Insert cell
function stateTable(stateName,dataTotals,variantsData) {
let lastDay = mapDay - numberOfDays - 1;
let lagDays = 1;

let kr = "7day_mov_avg";
let kpos = "test_number_pos_rolling";
let kall = "test_number_ALL_rolling";

let empty = {
[kr]:0,
[kpos]:0,
[kall]:0,
};
let current = dataTotals.slice(lastDay-lagDays)[0];
let prior = dataTotals.slice(lastDay-7-lagDays)[0];
console.log(current);
let prior2 = dataTotals.slice(lastDay-14-lagDays)[0];
console.log(kr,{current:current[kr], prior:prior[kr]});
console.log(kpos,{current:current[kpos], prior:prior[kpos]});
console.log(kall,{current:current[kall], prior:prior[kall]});

let currentRate = current[kpos] / current[kall] ;
let priorRate = prior[kpos] / prior[kall] ;
let prior2Rate = prior2[kpos] / prior2[kall] ;

console.log({lastDay, mapDay, numberOfDays});
let ba45 = variantsData.filter(d=>d.Variants=="BA.4+BA.5");
let ba2 = variantsData.filter(d=>d.Variants=="BA.2");
console.log("ba45",ba45);
console.log("ba2",ba2);

let ba45_last_n_days = ba45.slice(-14-lagDays);
let ba2_last_n_days = ba2.slice(-14-lagDays);

let sgtf_samples9_last_week = ba45_last_n_days[0].Samples3day + ba45_last_n_days[3].Samples3day + ba45_last_n_days[6].Samples3day;
let sgtf_samples9 = ba45_last_n_days[7].Samples3day + ba45_last_n_days[10].Samples3day + ba45_last_n_days[13].Samples3day;
let non_sgtf_samples9_last_week = ba2_last_n_days[0].Samples3day + ba2_last_n_days[3].Samples3day + ba2_last_n_days[6].Samples3day;
let non_sgtf_samples9 = ba2_last_n_days[7].Samples3day + ba2_last_n_days[10].Samples3day + ba2_last_n_days[13].Samples3day;

console.log({lastDay,mapDay,ba45length:ba45.length, sgtf_samples9, sgtf_samples9_last_week, non_sgtf_samples9, non_sgtf_samples9_last_week});
let currentBA45 = ba45.slice(lastDay)[0].Proportion;
let currentBA45lag = ba45.slice(lastDay-lagDays)[0].Proportion;
let currentBA45p = (currentBA45*100).toFixed(1)+"%";
let currentBA45Cases = (current[kpos]* currentBA45lag).toFixed(0);
let currentBA2Cases = current[kpos] - currentBA45Cases;

let priorBA45 = ba45.slice(lastDay-7)[0].Proportion;
console.log("priorBA45",priorBA45);
let priorBA45lag = ba45.slice(lastDay-7-lagDays)[0].Proportion;
let priorBA45p = (priorBA45lag*100).toFixed(1)+"%";
let priorBA45Cases = (prior[kpos]* priorBA45lag).toFixed(0);
let priorBA2Cases = prior[kpos] - priorBA45Cases;

let prior2BA45 = ba45.slice(lastDay-14)[0].Proportion;
let prior2BA45lag = ba45.slice(lastDay-14-lagDays)[0].Proportion;
let prior2BA45p = (prior2BA45lag*100).toFixed(1)+"%";
let prior2BA45Cases = (prior2[kpos]* prior2BA45lag).toFixed(0);
let prior2BA2Cases = prior2[kpos] - prior2BA45Cases;

function toPercent(x,d=1) {
return (x * 100).toFixed(d);
}
return md`| ${stateName} Walgreens | Positivity Rate | Positive Tests | Total Tests | SGTF % | SGTF Pos Tests, 9 days | non-SGTF Pos Tests, 9 days
| ------ | -------- | ---------- | -------
| Current week | ${toPercent(currentRate)}% | ${current[kpos].toLocaleString()} | ${current[kall].toLocaleString()} | ${currentBA45p} | ${sgtf_samples9.toLocaleString()} | ${non_sgtf_samples9.toLocaleString()}
| Prior week | ${toPercent(priorRate)}% | ${prior[kpos].toLocaleString()} | ${prior[kall].toLocaleString()} | ${priorBA45p} | ${priorBA45Cases.toLocaleString()} | ${priorBA2Cases.toLocaleString()}
| 2 weeks prior | ${toPercent(prior2Rate)}% | ${prior2[kpos].toLocaleString()} | ${prior2[kall].toLocaleString()} | ${prior2BA45p} | ${prior2BA45Cases.toLocaleString()} | ${prior2BA2Cases.toLocaleString()}
| *1-week Change* | *${toPercent(currentRate-priorRate)}%* | *${toPercent((current[kpos]-prior[kpos])/prior[kpos])}%* | *${toPercent((current[kall]-prior[kall])/prior[kall])}%* | *${toPercent(currentBA45lag-priorBA45lag)}%* | *${toPercent((currentBA45Cases-priorBA45Cases)/priorBA45Cases)}%* | *${toPercent((currentBA2Cases-priorBA2Cases)/priorBA2Cases)}%*
| *2-week Change* | *${toPercent(currentRate-prior2Rate)}%* | *${toPercent((current[kpos]-prior2[kpos])/prior2[kpos])}%* | *${toPercent((current[kall]-prior2[kall])/prior2[kall])}%* | *${toPercent(currentBA45lag-prior2BA45lag)}%* | *${toPercent((currentBA45Cases-prior2BA45Cases)/prior2BA45Cases)}%* | *${toPercent((currentBA2Cases-prior2BA2Cases)/prior2BA2Cases)}%*

<span style="font-size: 0.8em">"Est. SGTF (or non-SGTF) Pos Tests" is the product of the 7-day rolling positive tests times the estimate of the proportion of SGTF (or non-SGTF) cases, ${lagDays} days back (to reduce the effect of reporting lag).</span>
`;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
testsUS.slice(0,10)
Insert cell
function plotTestsPositivity(datain,domain,showAllTests = true, regionSelected="") {
domain = domain || [new Date(2021, 4, 0), Date.now()];
let data = {
tests: datain.tests.sort((a,b)=>a.Date - b.Date).filter(d=>d.Date >= domain[0] && d.Date <= domain[1] && (d.Tests !== "All Tests" || showAllTests)),
positivity: datain.positivity.sort((a,b)=>a.Date - b.Date).filter(d=>d.Date >= domain[0] && d.Date <= domain[1] ),
};

let wastewaterPlot = null;
let wastewaterLabel = null;
console.log("regionSelected",regionSelected);
let wastewaterRegion = regionSelected;
console.log("wastewaterRegion",wastewaterRegion);
if (wastewaterRegion) {
let regionWastewaterData = cdcWasteWaterData.filter(d=>d.date >= domain[0] && d.date <= domain[1] && d.region === wastewaterRegion && d.date_period === "All Results");
console.log("regionWastewaterData",regionWastewaterData);
if (regionWastewaterData.length) {
let recentWastewaterMean = d3.mean(regionWastewaterData.slice(-14,-1),d=>d.wastewater);
let lastWastewaterDate = regionWastewaterData.slice(-2)[0].date.valueOf();
let recentTests = data.tests.filter(d=>d.Tests === "Positive Tests" && d.Date <= lastWastewaterDate && d.Date > lastWastewaterDate-13*7*24*60*60*1000);
//console.log("recentTests",recentTests);
let recentPositivesMean = d3.mean(recentTests,d=>d.WeeklyTests);
//console.log(lastWastewaterDate);
//console.log("recentWastewaterMean",recentWastewaterMean);
//console.log("recentPositivesMean",recentPositivesMean);
let wastewaterScale = recentPositivesMean / recentWastewaterMean;
wastewaterScale = 1;
wastewaterPlot = Plot.lineY(regionWastewaterData, {
x: d=>d.date.valueOf(),
y: d=>d.wastewater * wastewaterScale,
stroke: d=>"Wastewater",
tip: true
});
wastewaterLabel = Plot.text(regionWastewaterData, Plot.selectLast({
x: d=>d.date.valueOf(),
y: d=>d.wastewater * wastewaterScale,
fill: d=>"Wastewater",
text: ()=>"CDC Wastewater " + wastewaterRegion,
textAnchor: "end",
fontSize: chartFontSize,
dx: -5,
dy: -5
}));
//console.log("wastewaterPlot",wastewaterPlot);
}
}
let maxY = d3.max(data.tests,d=>d.WeeklyTests);
let positiveTests = data.tests.filter(d=>d.Tests==="Positive Tests");
let maxPos = d3.max(data.tests.filter(d=>d.Tests==="Positive Tests"),d=>d.WeeklyTests);
let posScale = maxY/maxPos;
let positiveTestsScaled = positiveTests.map(d=> {
return {
...d,
Tests: "Positives scaled",
WeeklyTests: d.WeeklyTests*posScale,
};
});

//data.tests = data.tests.concat(positiveTestsScaled);

let dayMS = 24*60*60*1000 ;
let daysShaded = [-7,0].map(d=>{
return {
Date: lastTimestamp + d*dayMS,
WeeklyTests: maxY,
};
});

let domainDays = (domain[1].valueOf() - domain[0].valueOf())/dayMS;
console.log("domainDays is ",domainDays);
let yearLine = null;
if (domainDays > 372) {
console.log("Going to put a 1-year-ago line, domainDays is ",domainDays);
yearLine = [
Plot.ruleX([{date:new Date(domain[1].valueOf()-365*dayMS)}],{x:d=>d.date.valueOf(),y1:d=>0,y2:d=>maxY, stroke:"#888",opacity:0.9}),
Plot.text([{date:new Date(domain[1].valueOf()-365*dayMS)}],{x:d=>d.date.valueOf(),y:d=>0, text:d=>"One year ago", opacity:0.9, textAnchor:"start",lineAnchor:"bottom", fill:d=>"#888", dx: 5, fontSize: width/75}),

];
}
console.log("year line",yearLine);

let plot = multiLayerX(
{
...chartConfig,
style: "overflow: visible;",
x: {
type: "utc",
domain: domain,
grid: true,
tickRotate: -30
},
y: {
axis: "left",
types: [null,"%"],
grid: true,
zero: true,
label: "Weekly Tests"
},
},
Plot.line(data.tests,{
y: "WeeklyTests",
x: "Date",
stroke:d=>d.Tests === "Positive Tests" ? "#E6B442" : "#4865C2",
tip: true,
}),
Plot.line(data.positivity,{
y: "Positivity",
x: "Date",
stroke:"#cccccc",
tip: true,
}),
Plot.areaY(daysShaded, {
y: "WeeklyTests",
x: "Date",
fill: "#ccc",
opacity: 0.5,
}),
Plot.text(data.tests, Plot.selectMaxY({
x: d => d.Tests === "All Tests" ? d.Date : d.Date,
y: d => d.Tests === "All Tests" ? d.WeeklyTests : d.WeeklyTests/6,
fill:d=>d.Tests === "Positive Tests" ? "#E6B442" : "#4865C2",
text: "Tests",
textAnchor: "end",
fontSize: chartFontSize,
dy: 0,
dx: -10
})),
Plot.text(data.positivity, Plot.selectLast({
x: "Date",
y: "Positivity",
fill: "#888888",
text: ()=>"Positivity",
textAnchor: "end",
fontSize: chartFontSize,
dx: -20,
dy: -5
})),
yearLine,
wastewaterPlot,
wastewaterLabel,
);
plot.setAttribute("font-size",chartFontSize);
return scaleToFit(plot);
}

Insert cell
Insert cell
Insert cell
Insert cell
scaleToFit = function(el,aspectRatio = 1.2) {
let w = Math.min(width*0.9,window.outerHeight*aspectRatio);
return html`<div style="margin:auto; width:${w/width*100}%;">${el}</div>`
}
Insert cell
chartFontSize = Math.min(chartConfig.width/35,12);

Insert cell
firstPlotDate = new Date(2021, 10, 22);
Insert cell
d3.schemeTableau10
Insert cell
variantDescription = ({
"Cases":"Estimated positive tests, last 7 days",
"Samples3day":"Samples detected last 3 days",
"Samples7day":"Samples detected last 7 days",
"Samples1day":"Samples detected last day"
})
Insert cell
Insert cell
plotVariantFacets = function(datain,variant="BA.2",column = "Samples3day", domain = [Date.now()-61*24*60*60*1000, Date.now()],aspectRatio = 4, ydomain=false) {

let curve = {Samples1day:1,Samples3day:1,Samples7day:1}[column] ? "step" : "linear";

//let y = d=>d[column]/statePopulation[d.State]*1000000;

let data = datain.filter(d=>d.Date >= domain[0] && d.Variants === variant);

let maxByState = {};
let minByState = {};
let recentMaxByState = {};
let recentMaxByStateNormalized = {};
let recentAvgByState = {};
let recentAvgByStateNormalized = {};
let recentMaxDivMinByState = {};
let dayMS = 24*60*60*1000 ;

let recentDate = lastTimestamp-6*dayMS ;
statesList.forEach(state => {
maxByState[state] = d3.max(data,d=>d.State === state ? d[column] : 0);
minByState[state] = d3.min(data,d=>d.State === state && d[column] ? d[column] : 9999999);
recentMaxByState[state] = d3.max(data,d=>d.State === state && d.Date > recentDate ? d[column] : 0);
recentAvgByState[state] = d3.sum(data,d=>d.State === state && d.Date > recentDate ? d[column] : 0);
recentMaxByStateNormalized[state] = recentMaxByState[state]/maxByState[state] ;
recentMaxDivMinByState[state] = recentMaxByState[state]/minByState[state] ;
recentAvgByStateNormalized[state] = recentAvgByState[state]/maxByState[state] ;
});
let y = d=>d[column]/maxByState[d.State];
//data = data.filter(d=>maxByState[d.State]>5);
data = data.filter(d=>minByState[d.State]>1);
let items = Object.entries(recentMaxDivMinByState);
items.sort((a,b)=>(recentMaxByStateNormalized[b[0]] - recentMaxByStateNormalized[a[0]])*50 + b[1]-a[1]);
let stateSort = {};
items.forEach((item,i)=>stateSort[item[0]] = i);
console.log("sorted states",items);
//data.sort((a,b)=>recentAvgByStateNormalized[a.State] - recentAvgByStateNormalized[b.State])
ydomain = [0,1.1];

console.log(maxByState);
let daysShaded = [-7,0].map(d=>{
return {
Date: lastTimestamp+d*dayMS,
[column]: 1,
};
});
let plot = Plot.plot({
style: "overflow: visible;",
...chartConfig,
height: 3000,
x: {
type: "utc",
domain,
axis: "top",
grid: true,
},
y: {
grid: true,
domain: ydomain,
nice: true,
//label: column
},
opacity: {
type: "linear",
domain: [0,1],
},
strokeOpacity: {
type: "linear",
domain: [0,1],
range: [0,1],
},
fillOpacity: {
type: "linear",
domain: [0,1],
range: [0,1],
},
r: {
type: "linear",
domain: [0,1],
},
color: {
//type: "categorical",
//reverse:false,
//range: colorRange
},
facet: {
data: data,
y: "State",
//x: d=>d.State.length % 2,
size: chartFontSize * 1.5,
marginRight: 90
},
marks: [
Plot.areaY(daysShaded, {
y: d=>d[column],
x: "Date",
fill: "#ccc",
opacity: 0.5,
}),
Plot.line(data,{
y,
x: "Date",
curve,
z: d=>-stateSort[d.State],
stroke: y,
sort: {
fy: {value: "z", reverse: true}
},
}),
/*
Plot.line(data,{ // all lines as background on all facets
y,
x: "Date",
curve,
opacity: d=>0.05,
stroke: y,
facet: "exclude",
z: d=>recentAvgByStateNormalized[d.State],
sort: {
fy: {value: "z", reverse: true}
},
}),*/
]
});
plot.setAttribute("font-size",chartFontSize*1);
return scaleToFit(plot,aspectRatio);}

Insert cell
Insert cell
Insert cell
Insert cell
variantsUS.slice(-50)
Insert cell
Insert cell
variantsUS.slice(-10)
Insert cell
Insert cell
Insert cell
mapByRegion = 0

Insert cell
Insert cell
mapChart = {
let domain = [0,1];
let data = currentBA4growth;

let type = "diverging";
let pivot = 0.5;
let thresholds = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9];

if ({"BA.4+BA.5 peak to BA.2 peak":1,"BA.4+BA.5 peak to BA.1 peak":1}[mapMode]) {
data = Object.values(variantPeaks);
}

if (mapByRegion) {
let regionData = [];
}

let values = {
Proportion: d => d["BA.2 Proportion"],
"3day": d => {
let tot = d["BA.1+BA.4+BA.5 3day"] + d["BA.2 3day"] + d["Other 3day"];
return (tot < 2) ? null : d["BA.2 3day"]/tot ;
},
"9day": d => {
let tot = d["BA.1+BA.4+BA.5 9day"] + d["BA.2 9day"] + d["Other 9day"];
return (tot < 2) ? null : d["BA.2 9day"]/tot ;
},
"BA.2 Growth": d => {
let tot = d["BA.2 3day"];
return (tot < 6) ? null : d["BA.2 Growth"];
},
"BA.4+BA.5 Growth": d => {
let tot = d["BA.1+BA.4+BA.5 3day"];
return (tot < 6) ? null : d["BA.4+BA.5 Growth"];
},
// Change was calculated for BA1/4/5
Change: d =>-d.Change,
growthAdvantage: d=>(1+d["BA.2 Growth"])/(1+d["BA.4+BA.5 Growth"]) - 1,
}

let value = values[mapMode] || (d => d[mapMode]);
let maxValue = d3.max(data.map(d=>value(d) < 1 ? value(d) : null));
console.log("maxValue",maxValue, data.map(d=>value(d) < 1 ? value(d) : null));
let minValue = d3.min(data.map(d=>value(d) < 1 ? value(d) : null));

let stateLabel = null ;

if (mapMode === "Proportion" || mapMode === "3day" || mapMode === "9day") {
//let m = Math.ceil(mValue*10)/10 ;
//thresholds = thresholds.map(x => (x*m).toFixed(2));
thresholds = thresholds.map(v=>0.5+0.5*v);
}
if (mapMode === "3day") {
stateLabel = (f, d) => {
//console.log({f,d});
return d ? `${d.State}
${(value(d)*100).toFixed(2)}%
${d["BA.2 3day"]}/${d["BA.1+BA.4+BA.5 3day"]+d["BA.2 3day"]+d["Other 3day"]}` : f.properties.name;
}
}
if (mapMode === "9day") {
stateLabel = (f, d) => {
//console.log({f,d});
return d ? `${d.State}
${(value(d)*100).toFixed(2)}%
${d["BA.2 9day"]}/${d["BA.1+BA.4+BA.5 9day"]+d["BA.2 9day"]+d["Other 9day"]}` : f.properties.name;
}
}
if (mapMode === "Change") {
thresholds = thresholds.map(x => ((x-0.5)/2).toFixed(2));
}
else if ({"BA.4+BA.5 peak to BA.2 peak":1,"BA.4+BA.5 peak to BA.1 peak":0}[mapMode]) {
thresholds = [ 0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2];
}
else if (mapMode === "Growth" || mapMode === "Growth2" ) {
thresholds = thresholds.map(x => (x > 0.5 ? 2 : 1)*(x/0.5-1).toFixed(1));
}
else if (mapMode === "BA.4+BA.5 Growth") {
// thresholds = [0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9];
thresholds = [-0.8,-0.6,-0.4,-0.2,0.0,0.2,0.4,0.6,0.8,1];
}
else if (mapMode === "BA.2 Growth") {
thresholds = [-0.8,-0.6,-0.4,-0.2,0.0,0.2,0.4,0.6,0.8,1];
}
else if (mapMode === "Positivity") {
thresholds = thresholds.map(x => (0.05 + x/2).toFixed(2));
}
else if (mapMode === "PositivityChange") {
thresholds = [-0.08,-0.06,-0.04,-0.02,0.0,0.02,0.04,0.06,0.08,.1];
}
else if (mapMode === "Positives Growth") {
//thresholds = [-0.16,-0.12,-0.08,-0.04,0.0,0.04,0.08,0.12,0.16,.2];
thresholds = [-0.5,-0.3,-0.2,-0.1,0.0,0.1,0.2,0.3,0.4,.5];
}
else if (mapMode === "growthAdvantage") {
thresholds = [-0.8,-0.6,-0.4,-0.2,0.0,0.2,0.4,0.6,0.8,1];
thresholds = [-0.8,-0.6,-0.4,-0.2,0.0,0.25,0.5,1,1.5,2];
}
//let colorSchemeName = "scheme"+colorSchemeID.charAt(0).toUpperCase() + colorSchemeID.slice(1);
let colorScheme;
if (colorSchemeID === "schemeCustom") {
colorScheme = [...myScheme];
}
else {
colorScheme = [...(d3[colorSchemeID][10] || d3[colorSchemeID][9] || d3[colorSchemeID][0])] ;
}
if (!reverseMapColors) {
colorScheme.reverse();
}

let map = Choropleth(
data, {
id: d => namemap.get(d.State),
value,
scale: d3.scaleThreshold,
domain: thresholds,
range: colorScheme,
strokeWidth: d=>(d && d["BA.2 3day"] || 0)*10+1, // stroke color for borders
stroke: "#ffffff", // stroke color for borders
fill: "#dddddd", // fill color for outline
title: stateLabel || ((f, d) => {
//console.log({f,d});
return d ? `${d.State}\n${(value(d)*100).toFixed(2)}%` : f.properties.name;
}),
features: states,
borders: statemesh,
width: 1000,
height: 620,
});

function scrollToSelectedState() {
document.getElementById("charts-for-selected-state-puerto-rico-or-dc").scrollIntoView();
}
window.scrollToSelectedState = scrollToSelectedState;

function handleClick(e) {
console.log("Map clicked:",e);
//console.log("Source element:",e.srcElement);
let stateClicked = e.srcElement.textContent.split("\n")[0];
console.log("State clicked: ", stateClicked);
(viewof stateSelected).value = stateClicked;
(viewof stateSelected).dispatchEvent(new Event("input", {bubbles: true}));
scrollToSelectedState();
}
console.log({map});
map.addEventListener("click", handleClick);


return map;
}
Insert cell
Insert cell
mapDaySlider = Inputs.range(
[1, numberOfDays-1],
{
step: 1,
width: width*0.9,
value: numberOfDays
}
)
Insert cell
animationDay = animateSlider(animateButton, mapDaySlider)
Insert cell
Insert cell
viewof animateButton = Inputs.button("Animate")
Insert cell
viewof colorSchemeID = Inputs.select(["schemeCustom",...Object.keys(d3).filter(k => k.startsWith("scheme") && (d3[k][10] || d3[k][9]) && !d3[k][0])], {label: "Color scheme", value: "schemeSpectral", format: k => k.slice(6), width: 90})
Insert cell
viewof reverseMapColors = Inputs.toggle({label: "Reverse Colors", value: false})
Insert cell
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