diff --git a/public/stage-1-covid/config-stage-1.json b/public/stage-1-covid/config-stage-1.json index 060b8f86f6..112b444dc0 100644 --- a/public/stage-1-covid/config-stage-1.json +++ b/public/stage-1-covid/config-stage-1.json @@ -141,7 +141,7 @@ }, "covid-metadata-task": { "type": "react-component", - "path": "viz-guardrails/CovidMetadataTask.tsx", + "path": "viz-guardrails/MetadataRankingTask.tsx", "instruction": "Below are four different visualizations (A–D) of COVID-19 data for Norway. Please review each chart and select the one you think is the most useful comparison for Norway.", "parameters": { "dataset": "clean_data", @@ -162,7 +162,7 @@ "response": [ { "id": "explanation", - "prompt": "What are your reasons for your ranking? Which aspects made you rank one chart as “best”?", + "prompt": "Please briefly explain why you chose that chart. Which aspects influenced your choice?", "secondaryText": "", "location": "belowStimulus", "type": "longText", diff --git a/public/stage-1/config-stage-1.json b/public/stage-1/config-stage-1.json index 114d0300be..e8a7543462 100644 --- a/public/stage-1/config-stage-1.json +++ b/public/stage-1/config-stage-1.json @@ -139,6 +139,37 @@ "initial_selection": ["VZ"] } }, + "stock-metadata-task": { + "type": "react-component", + "path": "viz-guardrails/MetadataRankingTask.tsx", + "instruction": "Below are four different visualizations (A–D) of stock data for Verizon (VZ). Please review each chart and select the one you think is the most useful comparison for Verizon.", + "parameters": { + "dataset": "sp500_stocks", + "start_date": "2024-01-01", + "end_date": "2024-12-31", + "x_var": "date", + "y_var": "value", + "cat_var": "name", + "group_var": "sector", + "selection": ["VZ"], + "range": null, + "items": [], + "data": [], + "metadataFiltered": false, + "numRandomSamples": 5, + "numQuantiles": 5 + }, + "response": [ + { + "id": "explanation", + "prompt": "Please briefly explain why you chose that chart. Which aspects influenced your choice?", + "secondaryText": "", + "location": "belowStimulus", + "type": "longText", + "placeholder": "Enter your reasoning here" + } + ] + }, "stock-b-control": { "baseComponent": "stock", "parameters": { @@ -5194,6 +5225,7 @@ } ] }, + "stock-metadata-task", "post-study-quant" ] } diff --git a/src/public/viz-guardrails/CovidMetadataTask.tsx b/src/public/viz-guardrails/CovidMetadataTask.tsx deleted file mode 100644 index e8ea78778f..0000000000 --- a/src/public/viz-guardrails/CovidMetadataTask.tsx +++ /dev/null @@ -1,134 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import React, { - useEffect, useState, useMemo, useRef, -} from 'react'; -import seedrandom from 'seedrandom'; -import { - Box, SimpleGrid, Text, Paper, Loader, Card, -} from '@mantine/core'; -import * as d3 from 'd3'; -import { LineChart } from './LineChart'; -import RankingWidget from './RankingWidget'; - -const baseGuardrails = ['percentileClosest', 'super_data', 'metadata', 'cluster'] as const; -type GuardrailType = typeof baseGuardrails[number]; - -export function CovidMetadataTask({ parameters, setAnswer }: any) { - const [data, setData] = useState(null); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [dataname, setDataname] = useState(parameters.dataset || 'clean_data'); - const [items, setItems] = useState(null); - const [range, setRange] = useState<[Date, Date] | null>([new Date(parameters.start_date || '2020-03-01'), new Date(parameters.end_date || '2021-08-28')]); - const [selection] = useState(parameters.selection || ['Norway']); - const [numRandomSamples] = useState(parameters.numRandomSamples ?? 5); - const [numQuantiles] = useState(parameters.numQuantiles ?? 5); - const [baseGuardrailOrder, setBaseGuardrailOrder] = useState([]); - const [rankingOrder, setRankingOrder] = useState([]); - const initialSeedRef = useRef(null); - if (initialSeedRef.current === null) { - initialSeedRef.current = Date.now().toString(); - } - const seededOrder = useMemo(() => { - const rng = seedrandom(initialSeedRef.current!); - const arr = [...baseGuardrails]; - for (let i = arr.length - 1; i > 0; i -= 1) { - const j = Math.floor(rng() * (i + 1)); - [arr[i], arr[j]] = [arr[j], arr[i]]; - } - return arr; - }, []); - - useEffect(() => { - setBaseGuardrailOrder(seededOrder); - setRankingOrder(seededOrder); - setAnswer?.({ status: true, answers: { 'chart-ranking': seededOrder } }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [seededOrder]); - - useEffect(() => { - d3.csv(`./data/${dataname}.csv`).then((csvData) => { - setData(csvData); - setItems(Array.from(new Set(csvData.map((row) => (JSON.stringify({ - name: row[parameters.cat_var || 'name'], - group: row[parameters.group_var || 'region'], - longName: row.long_name || null, - sector: row.sector || null, - subregion: row.subregion || null, - }))))).map((row) => JSON.parse(row))); - }); - if (dataname === 'clean_data') { - setRange([new Date('2020-03-01'), new Date('2021-08-28')]); - } else { - setRange([new Date(parameters.start_date || '2020-03-01'), new Date(parameters.end_date || '2021-08-28')]); - } - }, [dataname, parameters.cat_var, parameters.group_var, parameters.start_date, parameters.end_date]); - - const filteredData = useMemo(() => { - if (data && range) { - return data - .filter((val) => (new Date(val[parameters.x_var || 'date'])).getTime() >= range[0].getTime()) - .filter((val) => (new Date(val[parameters.x_var || 'date'])).getTime() <= range[1].getTime()); - } - return null; - }, [data, range, parameters.x_var]); - - if (!filteredData || !items || !range || !selection) { - return ; - } - - return ( - - - - Below are four charts comparing Norway’s COVID-19 cases to different sets of countries. Which chart do you think shows the most useful and appropriate comparison for Norway? - - - - {baseGuardrailOrder.map((guardrail, idx) => { - const label = `Chart ${String.fromCharCode(65 + idx)}`; - return ( - - {label} - Total infections per million people - - - ); - })} - - - { - setRankingOrder(newOrder as GuardrailType[]); - setAnswer?.({ status: true, answers: { 'chart-ranking': newOrder } }); - }} - /> - - - ); -} - -export default CovidMetadataTask; diff --git a/src/public/viz-guardrails/MetadataRankingTask.tsx b/src/public/viz-guardrails/MetadataRankingTask.tsx new file mode 100644 index 0000000000..38427a02a5 --- /dev/null +++ b/src/public/viz-guardrails/MetadataRankingTask.tsx @@ -0,0 +1,181 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React, { + useEffect, useState, useMemo, useRef, +} from 'react'; +import seedrandom from 'seedrandom'; +import { + Box, SimpleGrid, Text, Paper, Loader, Card, +} from '@mantine/core'; +import * as d3 from 'd3'; +import { LineChart } from './LineChart'; + +const baseGuardrails = ['percentileClosest', 'super_data', 'metadata', 'cluster'] as const; +type GuardrailType = typeof baseGuardrails[number]; + +export function MetadataRankingTask({ parameters, setAnswer }: any) { + const [data, setData] = useState(null); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [dataname, setDataname] = useState(parameters.dataset || 'clean_data'); + const [items, setItems] = useState(null); + const [range, setRange] = useState<[Date, Date] | null>([new Date(parameters.start_date || '2020-03-01'), new Date(parameters.end_date || '2021-08-28')]); + const [selection] = useState(parameters.selection || ['Norway']); + const [numRandomSamples] = useState(parameters.numRandomSamples ?? 5); + const [numQuantiles] = useState(parameters.numQuantiles ?? 5); + const [baseGuardrailOrder, setBaseGuardrailOrder] = useState([]); + const [selectedGuardrail, setSelectedGuardrail] = useState(null); + const initialSeedRef = useRef(null); + if (initialSeedRef.current === null) { + initialSeedRef.current = Date.now().toString(); + } + const seededOrder = useMemo(() => { + const rng = seedrandom(initialSeedRef.current!); + const arr = [...baseGuardrails]; + for (let i = arr.length - 1; i > 0; i -= 1) { + const j = Math.floor(rng() * (i + 1)); + [arr[i], arr[j]] = [arr[j], arr[i]]; + } + return arr; + }, []); + + useEffect(() => { + setBaseGuardrailOrder(seededOrder); + setSelectedGuardrail(null); + setAnswer?.({ status: false, answers: { condition: selectedGuardrail } }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [seededOrder]); + + useEffect(() => { + d3.csv(`./data/${dataname}.csv`).then((csvData) => { + setData(csvData); + setItems(Array.from(new Set(csvData.map((row) => (JSON.stringify({ + name: row[parameters.cat_var || 'name'], + group: row[parameters.group_var || 'region'], + longName: row.long_name || null, + sector: row.sector || null, + subregion: row.subregion || null, + }))))).map((row) => JSON.parse(row))); + }); + if (dataname === 'clean_data') { + setRange([new Date('2020-03-01'), new Date('2021-08-28')]); + } else { + setRange([new Date('2024-01-01'), new Date('2024-12-31')]); + } + }, [dataname, parameters.cat_var, parameters.group_var]); + + const filteredData = useMemo(() => { + if (data && range) { + return data + .filter((val) => (new Date(val[parameters.x_var || 'date'])).getTime() >= range[0].getTime()) + .filter((val) => (new Date(val[parameters.x_var || 'date'])).getTime() <= range[1].getTime()); + } + return null; + }, [data, range, parameters.x_var]); + + if (!filteredData || !items || !range || !selection) { + return ; + } + + return ( + + + + {dataname === 'clean_data' + ? 'Below are four charts comparing Norway’s COVID-19 cases to different sets of countries. Which chart do you think shows the most useful and appropriate comparison for Norway? Select the chart by clicking the "Select" button at the top-left of the chart.' + : 'Below are four charts comparing Verizon’s (VZ) stock performance to different sets of stocks. Which chart do you think shows the most useful and appropriate comparison for Verizon (VZ)? Select the chart by clicking the "Select" button at the top-left of the chart.'} + + + + {baseGuardrailOrder.map((guardrail, idx) => { + const label = `Chart ${String.fromCharCode(65 + idx)}`; + return ( + + + +
{ + if (selectedGuardrail === guardrail) { + setSelectedGuardrail(null); + setAnswer?.({ status: false, answers: {} }); + } else { + setSelectedGuardrail(guardrail); + setAnswer?.({ status: true, answers: { condition: guardrail } }); + } + }} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + if (selectedGuardrail === guardrail) { + setSelectedGuardrail(null); + setAnswer?.({ status: false, answers: {} }); + } else { + setSelectedGuardrail(guardrail); + setAnswer?.({ status: true, answers: { condition: guardrail } }); + } + } + }} + style={{ + display: 'inline-block', + padding: '6px 10px', + borderRadius: 9999, + background: selectedGuardrail === guardrail ? '#1c7ed6' : '#e7f5ff', + color: selectedGuardrail === guardrail ? '#fff' : '#1864ab', + fontSize: 13, + fontWeight: 700, + boxShadow: selectedGuardrail === guardrail ? '0 2px 6px rgba(28,126,214,0.35)' : 'none', + cursor: 'pointer', + userSelect: 'none', + }} + > + {selectedGuardrail === guardrail ? 'Selected' : 'Select'} +
+
+ + {label} + + + {dataname === 'clean_data' ? 'Total infections per million people' : 'Percent change in stock price'} + + +
+
+ ); + })} +
+
+ ); +} + +export default MetadataRankingTask;