sigData = FileAttachment("chapter2_sigtests.csv").csv({ typed: true })
sigsDrug = sigData.filter(
({ drug }) => drug === select
)
significance = sigsDrug.filter(({ time }) => time === radio[0].time)
significanceDocumentation
Adult and Young Adult Substance Use Dashboard
Significance Tests
Significance Legend in Graph
sigLegend1 = html`<style>
caption {
font-size: 9px;
}
table {
margin-bottom: 0.5rem;
}
.small td {
font-size: 9px;
color: #000066;
}
</style>
<table class="small" style="width: 250px; ">
<caption style="color: #000066;"> <b><u>2024 Trends</b></u> </caption>
<tr>
<td>Ages 19-30</td>
<td>1-Year Change</td>
<td>${significance[0]?.oneyrchange}</td>
<td>${significance[0]?.sig_oneyr}</td>
</tr>
<tr>
<td> </td>
<td>5-Year Change</td>
<td>${significance[0]?.fiveyrchange}</td>
<td>${significance[0]?.sig_fiveyr}</td>
</tr>
<tr style="background-color: white;">
<td></td>
<td>10-Year Change</td>
<td>${significance[0]?.tenyrchange}</td>
<td>${significance[0]?.sig_tenyr}</td>
</tr>
</table>`
sigLegend2 = html`<style>
caption {
font-size: 9px;
}
table {
margin-bottom: 0.5rem;
}
.small td {
font-size: 9px;
color: #000066;
}
</style>
<table class="small" style="width: 250px; ">
<caption style="color: #000066;"> <b><u>2024 Trends</b></u> </caption>
<tr>
<td>Ages 19-30</td>
<td>1-Year Change</td>
<td>${significance[0]?.oneyrchange}</td>
<td>${significance[0]?.sig_oneyr}</td>
</tr>
<tr>
<td> </td>
<td>5-Year Change</td>
<td>${significance[0]?.fiveyrchange}</td>
<td>${significance[0]?.sig_fiveyr}</td>
</tr>
<tr style="background-color: white;">
<td></td>
<td>10-Year Change</td>
<td>${significance[0]?.tenyrchange}</td>
<td>${significance[0]?.sig_tenyr}</td>
</tr>
<tr>
<td>Ages 35-50</td>
<td>1-Year Change</td>
<td>${significance[1]?.oneyrchange}</td>
<td>${significance[1]?.sig_oneyr}</td>
</tr>
<tr>
<td> </td>
<td>5-Year Change</td>
<td>${significance[1]?.fiveyrchange}</td>
<td>${significance[1]?.sig_fiveyr}</td>
</tr>
<tr>
<td></td>
<td>10-Year Change</td>
<td>${significance[1]?.tenyrchange}</td>
<td>${significance[1]?.sig_tenyr}</td>
</tr>
<tr>
<td>Ages 55-65</td>
<td>1-Year Change</td>
<td>${significance[2]?.oneyrchange}</td>
<td>${significance[2]?.sig_oneyr}</td>
</tr>
<tr>
<td> </td>
<td>5-Year Change</td>
<td>.</td>
<td>N/A</td>
</tr>
<tr>
<td></td>
<td>10-Year Change</td>
<td>.</td>
<td>N/A</td>
</tr>
</table>`
sigLegend = significance[1]?.oneyrchange === undefined ? sigLegend1 : sigLegend2
legendPlace = {if (radio[0]?.drug == "Alcohol" && radio[0]?.time == "12 Month"){
return "bottom: 60px; right: 50px;";
} else if (radio[0]?.drug == "Alcohol" && radio[0]?.time == "Lifetime") {
return "bottom: 60px; right: 50px;";
} else if (radio[0]?.drug == "Alcohol" && radio[0]?.time == "30 Day") {
return "bottom: 60px; right: 50px;";
} else {
return "top: 50px; right: 50px;";
}
}
legendPlaceTable Wide Format
Code
wideTable = html`
<style>
.branch {overflow-x:scroll; direction: rtl; margin-left:200px; }
td:nth-child(1), th:first-child { left: 110px; white-space:nowrap; word-wrap: break-word; }
td:nth-child(2), th:nth-child(2) { left: 210px; word-wrap: break-word;}
td, th { vertical-align: middle; padding: .5em; color: black; }
th { text-decoration: underline; white-space:nowrap; }
tr:nth-child(3) {
background-color: #ADD8E6;
}
.sticky {position:absolute; width:100px; top:auto; white-space:normal;}
table {
direction: ltr;
border: none;
border-collapse: collapse;
text-align: center;
}
/* On screens that are 1720px or less, do this for the table and citation size */
@media screen and (max-width: 1680px) {
.branch {overflow-x:scroll; direction: rtl; margin-left:190px; }
td:nth-child(1), th:first-child {left: 90px; white-space:nowrap; word-wrap: break-word; }
td:nth-child(2), th:nth-child(2) {left: 190px; word-wrap: break-word;}
tr:nth-child(3) {
background-color: #ADD8E6;
}
}
/* On screens that are 1720px or less, do this for the table */
@media screen and (max-width: 1375px) {
.branch {overflow-x:scroll; direction: rtl; margin-left:180px; }
td:nth-child(1), th:first-child {left: 65px; white-space:nowrap; word-wrap: break-word; }
td:nth-child(2), th:nth-child(2) {left: 170px; word-wrap: break-word;}
tr:nth-child(3) {
background-color: #ADD8E6;
}
}
/* On screens that are 992px or less, do this for the table and citation size */
@media screen and (max-width: 992px) {
.branch {overflow-x:scroll; direction: rtl; margin-left:175px; }
td:nth-child(1), th:first-child {left: 45px; white-space:nowrap; word-wrap: break-word; }
td:nth-child(2), th:nth-child(2) {left: 145px; word-wrap: break-word;}
tr:nth-child(3) {
background-color: #ADD8E6;
}
}
/* On screens that are 600px or less, do this for table and citation size */
@media screen and (max-width: 600px) {
.branch {overflow-x:scroll; direction: rtl; margin-left:155px; }
td:nth-child(1), th:first-child {left: 25px; white-space:nowrap; word-wrap: break-word; }
td:nth-child(2), th:nth-child(2) {left: 115px; word-wrap: break-word;}
tr:nth-child(3) {
background-color: #ADD8E6;
}
}
</style>
<table aria-label="${radio[0].drug}: Trends in ${radio[0].time} Prevalence of Use in 19-30 and 35-50 year olds">
<tr>
<th class="sticky" scope="col">Report Interval</th>
<th class="sticky" scope="col">Age</th>
<th scope="col">1988</th>
<th scope="col">1989</th>
<th scope="col">1990</th>
<th scope="col">1991</th>
<th scope="col">1992</th>
<th scope="col">1993</th>
<th scope="col">1994</th>
<th scope="col">1995</th>
<th scope="col">1996</th>
<th scope="col">1997</th>
<th scope="col">1998</th>
<th scope="col">1999</th>
<th scope="col">2000</th>
<th scope="col">2001</th>
<th scope="col">2002</th>
<th scope="col">2003</th>
<th scope="col">2004</th>
<th scope="col">2005</th>
<th scope="col">2006</th>
<th scope="col">2007</th>
<th scope="col">2008</th>
<th scope="col">2009</th>
<th scope="col">2010</th>
<th scope="col">2011</th>
<th scope="col">2012</th>
<th scope="col">2013</th>
<th scope="col">2014</th>
<th scope="col">2015</th>
<th scope="col">2016</th>
<th scope="col">2017</th>
<th scope="col">2018</th>
<th scope="col">2019</th>
<th scope="col">2020</th>
<th scope="col">2021</th>
<th scope="col">2022</th>
</tr>
<tr>
<td class="sticky" >${htmlTables[0]?.time == undefined ? "-" : htmlTables[0]?.time}</td>
<td class="sticky" >${htmlTables[0]?.age == undefined ? "-" : htmlTables[0]?.age}</td>
<td>${htmlTables[0]._1988 == "NaN" ? "-" : htmlTables[0]._1988}</td>
<td>${htmlTables[0]._1989 == "NaN" ? "-" : htmlTables[0]._1989}</td>
<td>${htmlTables[0]._1990 == "NaN" ? "-" : htmlTables[0]._1990}</td>
<td>${htmlTables[0]._1991 == "NaN" ? "-" : htmlTables[0]._1991}</td>
<td>${htmlTables[0]._1992 == "NaN" ? "-" : htmlTables[0]._1992}</td>
<td>${htmlTables[0]._1993 == "NaN" ? "-" : htmlTables[0]._1993}</td>
<td>${htmlTables[0]._1994 == "NaN" ? "-" : htmlTables[0]._1994}</td>
<td>${htmlTables[0]._1995 == "NaN" ? "-" : htmlTables[0]._1995}</td>
<td>${htmlTables[0]._1996 == "NaN" ? "-" : htmlTables[0]._1996}</td>
<td>${htmlTables[0]._1997 == "NaN" ? "-" : htmlTables[0]._1997}</td>
<td>${htmlTables[0]._1998 == "NaN" ? "-" : htmlTables[0]._1998}</td>
<td>${htmlTables[0]._1999 == "NaN" ? "-" : htmlTables[0]._1999}</td>
<td>${htmlTables[0]._2000 == "NaN" ? "-" : htmlTables[0]._2000}</td>
<td>${htmlTables[0]._2001 == "NaN" ? "-" : htmlTables[0]._2001}</td>
<td>${htmlTables[0]._2002 == "NaN" ? "-" : htmlTables[0]._2002}</td>
<td>${htmlTables[0]._2003 == "NaN" ? "-" : htmlTables[0]._2003}</td>
<td>${htmlTables[0]._2004 == "NaN" ? "-" : htmlTables[0]._2004}</td>
<td>${htmlTables[0]._2005 == "NaN" ? "-" : htmlTables[0]._2005}</td>
<td>${htmlTables[0]._2006 == "NaN" ? "-" : htmlTables[0]._2006}</td>
<td>${htmlTables[0]._2007 == "NaN" ? "-" : htmlTables[0]._2007}</td>
<td>${htmlTables[0]._2008 == "NaN" ? "-" : htmlTables[0]._2008}</td>
<td>${htmlTables[0]._2009 == "NaN" ? "-" : htmlTables[0]._2009}</td>
<td>${htmlTables[0]._2010 == "NaN" ? "-" : htmlTables[0]._2010}</td>
<td>${htmlTables[0]._2011 == "NaN" ? "-" : htmlTables[0]._2011}</td>
<td>${htmlTables[0]._2012 == "NaN" ? "-" : htmlTables[0]._2012}</td>
<td>${htmlTables[0]._2013 == "NaN" ? "-" : htmlTables[0]._2013}</td>
<td>${htmlTables[0]._2014 == "NaN" ? "-" : htmlTables[0].drug == "MDMA (Ecstasy)" ? htmlTables[0]._2014 + "†" : htmlTables[0]._2014}</td>
<td>${htmlTables[0]._2015 == "NaN" ? "-" : htmlTables[0]._2015}</td>
<td>${htmlTables[0]._2016 == "NaN" ? "-" : htmlTables[0]._2016}</td>
<td>${htmlTables[0]._2017 == "NaN" ? "-" : htmlTables[0]._2017}</td>
<td>${htmlTables[0]._2018 == "NaN" ? "-" : htmlTables[0]._2018}</td>
<td>${htmlTables[0]._2019 == "NaN" ? "-" : htmlTables[0]._2019}</td>
<td>${htmlTables[0]._2020 == "NaN" ? "-" : htmlTables[0]._2020}</td>
<td>${htmlTables[0]._2021 == "NaN" ? "-" : htmlTables[0]._2021}</td>
<td>${htmlTables[0]._2022 == "NaN" ? "-" : htmlTables[0]._2022}</td>
</tr>
<tr>
<td class="sticky" >${htmlTables[1]?.time == undefined ? "-" : htmlTables[1]?.time}</td>
<td class="sticky" >${htmlTables[1]?.age == undefined ? "-" : htmlTables[1]?.age}</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>${htmlTables[1]?._2008 == "NaN" ? "-" : htmlTables[1]?._2008 == undefined ? "-" : htmlTables[1]?._2008}</td>
<td>${htmlTables[1]?._2009 == "NaN" ? "-" : htmlTables[1]?._2009 == undefined ? "-" : htmlTables[1]?._2009}</td>
<td>${htmlTables[1]?._2010 == "NaN" ? "-" : htmlTables[1]?._2010 == undefined ? "-" : htmlTables[1]?._2010}</td>
<td>${htmlTables[1]?._2011 == "NaN" ? "-" : htmlTables[1]?._2011 == undefined ? "-" : htmlTables[1]?._2011}</td>
<td>${htmlTables[1]?._2012 == "NaN" ? "-" : htmlTables[1]?._2012 == undefined ? "-" : htmlTables[1]?._2012}</td>
<td>${htmlTables[1]?._2013 == "NaN" ? "-" : htmlTables[1]?._2013 == undefined ? "-" : htmlTables[1]?._2013}</td>
<td>${htmlTables[1]?._2014 == "NaN" ? "-" : htmlTables[1]?._2014 == undefined ? "-" : htmlTables[1]?._2014}</td>
<td>${htmlTables[1]?._2015 == "NaN" ? "-" : htmlTables[1]?._2015 == undefined ? "-" : htmlTables[1]?._2015}</td>
<td>${htmlTables[1]?._2016 == "NaN" ? "-" : htmlTables[1]?._2016 == undefined ? "-" : htmlTables[1]?._2016}</td>
<td>${htmlTables[1]?._2017 == "NaN" ? "-" : htmlTables[1]?._2017 == undefined ? "-" : htmlTables[1]?._2017}</td>
<td>${htmlTables[1]?._2018 == "NaN" ? "-" : htmlTables[1]?._2018 == undefined ? "-" : htmlTables[1]?._2018}</td>
<td>${htmlTables[1]?._2019 == "NaN" ? "-" : htmlTables[1]?._2019 == undefined ? "-" : htmlTables[1]?._2019}</td>
<td>${htmlTables[1]?._2020 == "NaN" ? "-" : htmlTables[1]?._2020 == undefined ? "-" : htmlTables[1]?._2020}</td>
<td>${htmlTables[1]?._2021 == "NaN" ? "-" : htmlTables[1]?._2021 == undefined ? "-" : htmlTables[1]?._2021}</td>
<td>${htmlTables[1]?._2022 == "NaN" ? "-" : htmlTables[1]?._2022 == undefined ? "-" : htmlTables[1]?._2022}</td>
</tr>
</table>
`Table Long Format
longTable = Inputs.table(tablesTime, {
columns: [
"year",
"age_18",
"age_19_20",
"age_21_22",
"age_23_24",
"age_25_26",
"age_27_28",
"age_29_30",
"age_35",
"age_40",
"age_45",
"age_50",
"age_55",
"age_60",
"age_65"
],
header: {
year: "Year",
age_18: "Age 18",
age_19_20: "Ages 19-20",
age_21_22: "Ages 21-22",
age_23_24: "Ages 23-24",
age_25_26: "Ages 25-26",
age_27_28: "Ages 27-28",
age_29_30: "Ages 29-30",
age_35: "Age 35",
age_40: "Age 40",
age_45: "Age 45",
age_50: "Age 50",
age_55: "Age 55",
age_60: "Age 60",
age_65: "Age 65"
},
format: {
year: d => html`<b>${d}</b>`,
age_18: d=> d.toFixed(1),
age_19_20: d=> d.toFixed(1),
age_21_22: d=> d.toFixed(1),
age_23_24: d=> d.toFixed(1),
age_25_26: d=> d.toFixed(1),
age_27_28: d=> d.toFixed(1),
age_29_30: d=> d.toFixed(1),
age_35: d=> d.toFixed(1),
age_40: d=> d.toFixed(1),
age_45: d=> d.toFixed(1),
age_50: d=> d.toFixed(1),
age_55: d=> d.toFixed(1),
age_60: d=> d.toFixed(1),
age_65: d=> d.toFixed(1)
},
rows: 75,
width: 1200
})Citation
citation = html`<div style="max-width: 750px;"><p style="font-size: small;">Suggested citation: Patrick, M. E., Miech, R. A., Johnston, L. D., & O’Malley, P. M. (2025). Monitoring the Future Panel Study annual report: National data on substance use among adults ages 19 to 65, 1976-2024. Monitoring the Future Monograph Series. Ann Arbor: Institute for Social Research, The University of Michigan.</p></div>`Footnotes
footnotesData = FileAttachment("Footnotes.csv").csv({ typed: true })
footnotesFiltered = footnotesData.filter(
({ drug }) => drug.toLocaleLowerCase() === select.toLocaleLowerCase()
)
function checkFootnote(d) {
if (d.length == 0 ) {
return html`<div></div>`;
} else if (d.length == 1) {
return html`<div style="max-width: 750px;"><p style="font-size: small;"><sup>${footnotesFiltered[0]?.superscript}</sup>${footnotesFiltered[0]?.footnote}</p></div>`;
} else {
return html`<div style="max-width: 750px;"><p style="font-size: small;"><sup>${footnotesFiltered[0]?.superscript}</sup>${footnotesFiltered[0]?.footnote}<br><sup>${footnotesFiltered[1]?.superscript}</sup>${footnotesFiltered[1]?.footnote}</p></div>`;
}
}
footnotes = checkFootnote(footnotesFiltered)
html`${footnotes}`Table Data
tables = FileAttachment("final_table_data.csv").csv({ typed: true })
tablesFormatted = {
const tables2 = tables.map(
({ time, drug, year, age_18, age_19_20, age_21_22, age_23_24, age_25_26, age_27_28, age_29_30, age_35, age_40, age_45, age_50, age_55, age_60, age_65
}) => ({
time: time,
drug: drug,
year: String(year),
age_18: +age_18,
age_19_20: +age_19_20,
age_21_22: +age_21_22,
age_23_24: +age_23_24,
age_25_26: +age_25_26,
age_27_28: +age_27_28,
age_29_30: +age_29_30,
age_35: +age_35,
age_40: +age_40,
age_45: +age_45,
age_50: +age_50,
age_55: +age_55,
age_60: +age_60,
age_65: +age_65
})
);
return tables2.filter(
({ drug }) => drug?.toLocaleLowerCase() === select?.toLocaleLowerCase()
);
}
tablesTime = tablesFormatted.filter(({ time }) => time === radio[0].time)
tablesTimePlot Data
parser = d3.timeParse("%Y")
format = d3.format(".4")
raw = FileAttachment("final_graph2_data.csv").csv({ typed: true })
rawAlphabetical = raw.sort((a, b) => {
if (a.drug && b.drug) {
return a.drug.localeCompare(b.drug);
} else {
return 0; // Preserve the order if 'name' is missing
}
});
rawAlphabeticalprevalence = rawAlphabetical.filter(thing => thing.drug != null)
data = {
const subset = prevalence.map(
({ year, drug, estimate, age, time, flag }) => ({
year: parser(year),
year2: format(year),
estimate: +estimate,
drug: drug,
age: age,
time: time,
flag: flag
})
);
const filtered = subset.filter(thing =>
thing.drug?.toLocaleLowerCase() === select?.toLocaleLowerCase()
);
return filtered;
}
dataradioSearch Bar
import {PersistInput} from "@john-guerra/persist-input@latest"
import {aq, op} from "@uwdata/arquero"
viewof drugs = aq // viewof shows the table view, but assigns the table value
.fromCSV(await FileAttachment("substance-use-graphs.csv").text())
.groupby("drug")
.count()
.view({ height: 240 })
drugSelection = drugs.objects()
viewof search = PersistInput(
"drug",
Inputs.text({
datalist: drugSelection.map((d) => d.drug),
placeholder: "Enter drug name",
submit: true,
label: "Search Drug:",
autocomplete: false,
spellcheck: true,
width: 350
})
)Dropdown Input
viewof select = PersistInput("drug",
Inputs.select(
prevalence.map((d) => d.drug),
{
value: "Alcohol",
width: 175,
unique: true
}
))Plot Title
ageQuestion = significance.length > 1
? "Respondents Aged 19 through 65"
: "Respondents Aged 19 through 30"Rendered Plot for Combined Age Groups
import {addTooltips} from "@mkfreeman/plot-tooltip"
formatter = d3.timeFormat("%Y")
color = d3.scaleOrdinal(
["Age 19-30", "Age 35-50", "Age 55-65"],
["#59bbeb", "#6ac4a1", "#cca438"]
)
symbol = d3.scaleOrdinal(
["Age 19-30", "Age 35-50", "Age 55-65"],
["circle", "square", "triangle"]
)
dateFilter1 = radio.filter(d => d.year > new Date("1988-01-01"));
dateFilter2 = radio.filter(d => d.year > new Date("2008-01-01"));
dateFilter3 = radio.filter(d => d.year > new Date("2023-01-01"));
legendFilter1 = dateFilter1.filter(d => d.age === "Age 19-30");
legendFilter2 = dateFilter2.filter(d => d.age === "Age 35-50");
legendFilter3 = dateFilter3.filter(d => d.age === "Age 55-65");
legendData = [...legendFilter1, ...legendFilter2, ...legendFilter3];
legendDataplot = addTooltips(
Plot.plot({
ariaLabel: "Line graph depicting trends in drug use by age group (ages 19-30, ages 35-50, ages 55-65) over time",
width: 900,
height: 700,
marginBottom: 50,
marginLeft: 50,
style: {
overflow: "visible",
fontSize: 12
},
symbol: {
domain: new Set(legendData.map((d) => d.age)),
range: [...new Set(legendData.map((d) => d.age))].map(symbol),
legend: true,
swatchSize: 23
},
color: {
domain: new Set(legendData.map((d) => d.age)),
range: [...new Set(legendData.map((d) => d.age))].map(color),
},
y: {
label: "Percentage (%)",
labelAnchor: "center",
domain: yscale
},
x: {
type: "time",
domain: [new Date("1987-01-01"), new Date("2024-01-01")],
label: "Years",
anchor: "bottom",
labelAnchor: "center"
},
marks: [
Plot.ruleY([0]),
Plot.dot(legendData, {
x: "year",
y: "estimate",
r: 4,
fill: "age",
symbol: "age",
title: (d) => `${d.age} \n ${formatter(d.year)}: ${d.estimate.toFixed(1)}%`
}),
Plot.line(legendData, {
x: "year",
y: "estimate",
z: (d) => // This creates the line breaks
[
d.age,
d.flag
].join(),
stroke: "age"})
]
}),
{ fill: "age" }
)All Ages Heatmap
filter1 = radio.filter(d => d.age != "Ages 19-30")
filter2 = filter1.filter(d => d.age != "Ages 35-50")
plot2 = addTooltips(Plot.plot({
marginTop: 50,
marginLeft: 100,
width: 1500,
height: 500,
grid: true,
x: {axis: "top", label: "Year", type: "band"},
y: {label: "Age", domain: ["Ages 19-20", "Ages 21-22", "Ages 23-24", "Ages 25-26", "Ages 27-28", "Ages 29-30", "Age 35", "Age 40", "Age 45", "Age 50", "Age 55", "Age 60"]},
color: {type: "linear", scheme: "BuRd", legend: true, label: "Drug Use Estimate"},
marks: [
Plot.cell(filter2, {x: "year2", y: "age", fill: "estimate", inset: 0.5, title: (d) => `${d.age} \n ${formatter(d.year)}: ${d.estimate}%`}),
Plot.text(filter2, {x: "year2", y: "age", text: "estimate", stroke: "white", strokeOpacity: 0.7, fill: "black", title: (d) => `${d.age} \n ${formatter(d.year)}: ${d.estimate}%`})
]
}),
{fill: "estimate"}
)Combined Sig Plot with Legend
comboPlot = html`
<div style="position: relative;">
${plot}
<div style="position: absolute; ${legendPlace} border: solid 1px black;">
${sigLegend}
</div>
</div>`