tol = ({
QualBright: ['#4477AA', '#EE6677', '#228833', '#CCBB44', '#66CCEE','#AA3377'],
QualHighContrast: ['#004488', '#DDAA33', '#BB5566'],
QualVibrant: ['#EE7733', '#0077BB', '#33BBEE', '#EE3377', '#CC3311', '#009988'],
QualMuted: ['#CC6677', '#332288', '#DDCC77', '#117733', '#88CCEE','#882255', '#44AA99', '#999933', '#AA4499'],
QualLight: ['#77AADD', '#EE8866', '#EEDD88', '#FFAABB', '#99DDFF', '#44BB99', '#BBCC33', '#AAAA00'],
Sunset: ['#364B9A', '#4A7BB7', '#6EA6CD', '#98CAE1', '#C2E4EF', '#EAECCC', '#FEDA8B', '#FDB366', '#F67E4B', '#DD3D2D', '#A50026'],
BuRd: ['#2166AC', '#4393C3', '#92C5DE', '#D1E5F0', '#F7F7F7', '#FDDBC7', '#F4A582', '#D6604D', '#B2182B'],
PRGn: ['#762A83', '#9970AB', '#C2A5CF', '#E7D4E8', '#F7F7F7', '#D9F0D3', '#ACD39E', '#5AAE61', '#1B7837'],
YlOrBr: ['#FFFFE5', '#FFF7BC', '#FEE391', '#FEC44F', '#FB9A29',
'#EC7014', '#CC4C02', '#993404', '#662506'],
Iridescent: ['#FEFBE9', '#FCF7D5', '#F5F3C1', '#EAF0B5', '#DDECBF',
'#D0E7CA', '#C2E3D2', '#B5DDD8', '#A8D8DC', '#9BD2E1',
'#8DCBE4', '#81C4E7', '#7BBCE7', '#7EB2E4', '#88A5DD',
'#9398D2', '#9B8AC4', '#9D7DB2', '#9A709E', '#906388',
'#805770', '#684957', '#46353A'],
RainbowPuRd: ['#6F4C9B', '#6059A9', '#5568B8', '#4E79C5', '#4D8AC6',
'#4E96BC', '#549EB3', '#59A5A9', '#60AB9E', '#69B190',
'#77B77D', '#8CBC68', '#A6BE54', '#BEBC48', '#D1B541',
'#DDAA3C', '#E49C39', '#E78C35', '#E67932', '#E4632D',
'#DF4828', '#DA2222'],
RainbowPuBr: ['#6F4C9B', '#6059A9', '#5568B8', '#4E79C5', '#4D8AC6',
'#4E96BC', '#549EB3', '#59A5A9', '#60AB9E', '#69B190',
'#77B77D', '#8CBC68', '#A6BE54', '#BEBC48', '#D1B541',
'#DDAA3C', '#E49C39', '#E78C35', '#E67932', '#E4632D',
'#DF4828', '#DA2222', '#B8221E', '#95211B', '#721E17',
'#521A13'],
RainbowWhRd: ['#E8ECFB', '#DDD8EF', '#D1C1E1', '#C3A8D1', '#B58FC2',
'#A778B4', '#9B62A7', '#8C4E99', '#6F4C9B', '#6059A9',
'#5568B8', '#4E79C5', '#4D8AC6', '#4E96BC', '#549EB3',
'#59A5A9', '#60AB9E', '#69B190', '#77B77D', '#8CBC68',
'#A6BE54', '#BEBC48', '#D1B541', '#DDAA3C', '#E49C39',
'#E78C35', '#E67932', '#E4632D', '#DF4828', '#DA2222'],
RainbowDiscrete: ['#E8ECFB', '#D9CCE3', '#D1BBD7', '#CAACCB', '#BA8DB4',
'#AE76A3', '#AA6F9E', '#994F88', '#882E72', '#1965B0',
'#437DBF', '#5289C7', '#6195CF', '#7BAFDE', '#4EB265',
'#90C987', '#CAE0AB', '#F7F056', '#F7CB45', '#F6C141',
'#F4A736', '#F1932D', '#EE8026', '#E8601C', '#E65518',
'#DC050C', '#A5170E', '#72190E', '#42150A']
})ns = Inputs.text().classList[0]
// custom css to override some ojs defaults for inputs
html`<style>
.${ns} {
--label-width: 80px;
}
form.${ns} {
flex-wrap: wrap;
}
.plot-inputs form.${ns} {
flex-direction: column;
}
.${ns} div label {
background-color: #f4f4f4;
padding: 0.25rem 0.5rem;
border-radius: 0.5rem;
margin-right: 0.25rem;
margin-bottom: 0.25rem;
width: auto;
}
.${ns} div label:hover,
.${ns} div label:active,
.${ns} div label:focus {
background-color: #fbe4b4;
}
.${ns} input[type="checkbox"] {
accent-color: black;
margin-bottom: 0;
}
.${ns} div input[type="number"] {
background-color: #f4f4f4;
padding: 0.25rem 0.5rem;
border-radius: 0.5rem;
flex-shrink: 3;
border: none;
}
.${ns} select {
background-color: #f4f4f4;
border: none;
border-radius: 0.5rem;
padding: 0.25rem 0.5rem;
//width: auto;
}
.${ns} .hist {
width: 100%;
display: flex;
flex-direction: column;
row-gap: 0em;
}
</style>`Plot = import("https://esm.sh/@observablehq/plot@0.6.17")
// defined in _load-data-items.qmd
items = transpose(items_)
models = transpose(models_)
// create combined item_group and language
items_coded = items.map(d => ({...d, lang_group: `${d.item_group} | ${d.language}` }))
// group items by task for task selector
tasks = d3.group(items_coded, d => d.task_label)item_vars = ["item_group", "item_uid", "n_responses", "difficulty"]
item_channels = Object.fromEntries(item_vars.map(k => [k, k]))
task = task_items[0].task_code // current items' task code
model = models.filter(t => t.task_code === task)[0] // current items' model type
by_lang = model.language !== undefined // whether items' model is by language
// sort order of languages -- alpha
langs = d3.sort(new Set(task_items.map(d => d.language)))
// sort order of item groups -- median difficulty (in first language)
l0_items = task_items.filter(d => d.language === langs[0])
groups = d3.groupSort(l0_items, g => d3.median(g, d => d.difficulty), d => d.item_group)
// sort order of language + item group -- above combined
indeces = d3.groups(task_items, d => d.lang_group).map(([lang_group, vals]) => [lang_group, langs.indexOf(vals[0].language), groups.indexOf(vals[0].item_group)])
lang_groups = d3.sort(indeces, d => d[1], d => d[2]).map(d => d[0])heights = ({
"hf": 180,
"sds": 240,
"mg": 220,
"math": 490,
"matrix": 220,
"mrot": 150,
"trog": 690,
"vocab": 340,
"tom": 500,
})
// shared options for both plots
item_opts = ({
style: { fontFamily: "var(--sans-serif)", fontSize: 12, overflow: "visible" },
width: 700,
height: heights[task],
marginLeft: 120,
marginTop: 50,
marginBottom: 40,
grid: true,
facet: { label: null, grid: true },
x: { line: true },
r: { range: [1, 4] },
fy: { domain: by_lang ? lang_groups : groups },
color: { domain: groups.length > 1 ? groups : langs, legend: false, scheme: "viridis" },
})
// dot mark for each plot, depending on x variable
item_dots = (x_var) => {
return Plot.marks(
Plot.dot(task_items, Plot.dodgeY("middle", {
x: x_var,
fy: by_lang ? "lang_group" : "item_group",
fill: groups.length > 1 ? "item_group" : "language",
r: "n_responses",
tip: { format: { fy: false }, anchor: "left" },
channels: item_channels
}))
)
}// info on items' model registry record
html`<div class="source"><a href="${model.file_link}" target="_blank">Source</a>: ${model.itemtype} IRT model (${model.invariance_label}) fit to ${model.n_runs} runs, uploaded on ${model.added_at_date} to model registry version ${model.registry_version}.</div>`