Public
Edited
Dec 25, 2024
1 star
Insert cell
Insert cell
exportedCell = {
const charts = sections.map(config => ({config, header: BotHeader(config), chart: OneChart(config)}) )
const app = html`
${styles}
<div class="app-container">
<div class="info-section">
${explanation}
<div class="info-question-details"></div>
</div>
<div class="info-hint-topics">${explanationTopics}</div>
<div class="chart-section">
${charts.map(m => html.fragment`${m.header}${m.chart}`)}
<img style="position:absolute; top:-10px; left:35%; width:7%" src="${botLogos["Chimp"]}"/>
<div style="position:absolute; top:5px; left:43%; color:orange">Chimp level (answering by random)</div>
</div>
<div class="questions-section">
${QuestionsCatalog}
</div>
</div>
`
interactivity(app, charts);
return app;
}
Insert cell
import {beeswarmX, beeswarmY} from "@angiehjort/beeswarm-plot"
Insert cell
DDFCsvReader = require('https://unpkg.com/@vizabi/reader-ddfcsv@4.3.11')
Insert cell
readerInstance = {
const reader = new DDFCsvReader.getDDFCsvReaderObject();
reader.init({path: "https://github.com/open-numbers/ddf--gapminder--ai_worldview_benchmark.git"})
return reader;
}
Insert cell
concepts = readerInstance.read({
from: "concepts",
language: "en",
select: {key: ["concept"], value: ["concept_type", "name"]},
where: {}
})
Insert cell
model_configuration = readerInstance.read({
from: "entities",
language: "en",
select: {key: ["model_configuration"], value: ["model_id","model_name", "vendor", "is--latest_model"]},
where: {}
})
Insert cell
model_configurationWithHuman = model_configuration.concat({
model_configuration: "human",
model_id: "human",
model_name: "Human",
vendor: "Human",
"is--latest_model": true
})
Insert cell
question = readerInstance.read({
from: "entities",
language: "en",
select: {
key: ["question"],
value:[
"language",
"published_version_of_question",
"contentful_id",
"human_wrong_percentage",
"topic_list","sdg_world_topics",
"other_topics",
"correct_answer",
"wrong_answer",
"very_wrong_answer"
]},
where: {}
}).then(
r => r.map(m => ({...m, sdg_world_topics: m.sdg_world_topics || "other"}))
)
Insert cell
questionMap = d3.rollup(question, v=>v[0], d=>d.question)
Insert cell
human = question.map(m => ({question: m.question, model_configuration: "human", correct_rate: 100-(+m.human_wrong_percentage)}))
Insert cell
rates = readerInstance.read({
from: "datapoints",
language: "en",
select: {key: ["question", "model_configuration"], value: ["correct_rate"]},
where: {}
})
Insert cell
ratesWithHuman = rates.concat(human)
Insert cell
ratesByModel = d3.group(ratesWithHuman, d => d.model_configuration)
Insert cell
mutable selectedModels = {
const rollup = d3.rollups(model_configurationWithHuman, v=>v.find(f => f["is--latest_model"])?.model_configuration, d => d.vendor)
.filter(([_, f]) => ratesByModel.has(f))
return Object.fromEntries(rollup);
}
Insert cell
BotHeader = function({vendor, top="none"}){
function getModelOptions(vendor) {
return model_configurationWithHuman
.filter(f => f.vendor === vendor && ratesByModel.has(f.model_configuration))
}
const div = d3.create("div")
.attr("class", "header")
.style("top", top);
div.append("div").attr("class", "logo").append("img")
.attr("src", botLogos[vendor])
//.style("width", "50px")
.style("height", "50px")

div.append("div").attr("class", "title")
.text(vendor)
.style("font-size", "2em")

const modelOptions = getModelOptions(vendor);

if (vendor !== "Human") {
const select = div.append("div").attr("class", "input").append("select")
.attr("name", "options")
.attr("id", vendor)

select.selectAll("option")
.data(modelOptions)
.join("option")
.attr("value", d => d.model_configuration)
.text(d => d.model_name)
select.property('value', selectedModels[vendor]);
select.on("change", event => {
const setOption = d3.select(event.target).property("value");
const newSelectedModels = Object.assign({}, selectedModels, {[vendor]: setOption});
mutable selectedModels = newSelectedModels;
})
}
return div.node();
}
Insert cell
function OneChart({vendor, data, axis=null, marginBottom = 0, marginTop=0, height = 150}) {
const chart = Plot.plot({
style: {fontSize: 24},
color: {
legend: false,
domain: Object.keys(sdgcolors),
range: Object.values(sdgcolors),
unknown: "#ccc"
},
x: { axis, domain: [0,100], grid: true, tickFormat: (n) => n === 100 ? "100% " : n+"%", label: "Correct answers", labelArrow: false},
y: { axis: null },
marks: [
beeswarmX(data, {
className: "swarm",
x: (d) => d.correct_rate,
y: () => 0,
r: 4,
opacity: 0.6,
xStrength: 3,
yStrength: 0.06,
fill: d => questionMap.get(d.question).sdg_world_topics,
strokeWidth: 1,
stroke: "white",
paintOrder: "stroke",
}),

Plot.ruleX([33.3], {stroke: "orange", strokeWidth: 5}),
],
width,
height,
inset: 20,
marginTop,
marginRight: 0,
marginLeft: 0,
marginBottom
})



return chart;

}

Insert cell
function interactivity(app, sections){


// .attr("class", "question-icon-container")
// .attr("class", "question-pile-container")
// .attr("class", "question-pile")
// .attr("class", "question-rect")
const DOM = {};
DOM.container = d3.select(app);
DOM.qIconContainer = DOM.container.select(".question-icon-container");
DOM.qPileContainer = DOM.container.select(".question-pile-container");
DOM.qIcons = DOM.qIconContainer.selectAll(".question-icon");
DOM.qPiles = DOM.qPileContainer.selectAll(".question-pile");
DOM.qRects = DOM.qPileContainer.selectAll(".question-rect");
DOM.qDetails = DOM.container.select(".info-question-details");

DOM.container
.on("mouseleave", (event, d) => highlight(null));
DOM.qIcons
.on("mouseenter", (event, d) => highlight({goal: d.goal}));
DOM.qRects
.on("mouseenter", (event, d) => highlight({question: d.question}));

sections.forEach(section => {
const data = section.config.data;
d3.select(section.chart)
.on("mouseleave", (event, d) => highlight(null))
.selectAll("circle")
.on("mouseenter", (event, i) => highlight({question: data[i].question}));
})

function highlight(spec){
console.log(spec)

sections.forEach(section => {
const data = section.config.data;
const circles = d3.select(section.chart).selectAll("circle")
.style("opacity", !spec
? 1 //default opacity
: i => spec.goal === questionMap.get(data[i].question).sdg_world_topics || spec.question === data[i].question? 1 : 0.1)
.attr("r", !spec
? 4 //default radius
: i => spec.goal === questionMap.get(data[i].question).sdg_world_topics || spec.question === data[i].question? 6 : 3);
})

if(spec && spec.question){
DOM.qRects
.style("opacity", q => q.question === spec.question ? 1 : 0.1)

//containerQuestionText.style("display", "block");
//if (spec && spec.question) containerQuestionText.text(question.find(f =>f.question ===spec.question).published_version_of_question)
}
if (!spec || spec.goal) {
DOM.qRects.style("opacity", 1)
//containerQuestionText.style("display", "none");
}

if(spec && spec.goal) {
const text = sdgGoalText[spec.goal];
DOM.qDetails.html(`<h2>${text.title}</h2><h1>${text.objective}</h1><p>${text.description}</p>`);
}
if(spec && spec.question) {
DOM.qDetails.html(`<p>${spec.question}</p>`);
const text = questionMap.get(spec.question);
DOM.qDetails.html(`
<h2>Question ${spec.question}</h2>
<p>${text.published_version_of_question}</p>
<p><span class="correct">Correct answer:</span><br/>${text.correct_answer}</p>
<p><span class="wrong">Wrong answer:</span><br/>${text.wrong_answer}</p>
<p><span class="verywrong">Very wrong answer:</span><br/>${text.very_wrong_answer}</p>
`);
}
if(!spec) {
DOM.qDetails.text("");
}
}

//highlight(null);
}
Insert cell
explanation = html`<h1>Artificial Worldview Benchmark</h1>
<p>We are testing if the chat bots suffer from the same misconceptions as humans. Here are the results from the ${questionMap.size} fact-questions that humans are generally wrong about.</p>
<p>Hover the circles to see which question it represents →</p>`

Insert cell
explanationTopics = html`<p>Or browse questions by topics ↓</p>`
Insert cell
<style type="text/css">
.app-container{
font-family: sans-serif;
display:grid;
grid-template-rows: auto auto;
grid-template-columns: 1fr 4fr;
column-gap: 20px;
row-gap: 20px;
}
.info-section {
grid-column-start: 1; grid-column-end: 2; grid-row-start: 1; grid-row-end: 2;
}
.info-hint-topics {
grid-column-start: 1; grid-column-end: 2; grid-row-start: 1; grid-row-end: 2; align-self: end;
}
.chart-section {
grid-column-start: 2; grid-column-end: 3; grid-row-start: 1; grid-row-end: 2;
position: relative;
}
.questions-section {
grid-column-start: 1; grid-column-end: 3; grid-row-start: 2; grid-row-end: 3;
}
.info-question-details {
margin-top: 30px;
}
.correct {
font-weight: bold;
color: darkgreen;
}
.wrong {
font-weight: bold;
color: orange;
}
.verywrong {
font-weight: bold;
color: red;
}
.header{
position: absolute;
display: grid;
align-items: center;
grid-template-columns: auto auto;
grid-template-rows: 25px 20px;
justify-content: start;
row-gap: 5px;
column-gap: 10px;
}
.header .logo {
grid-column-start: 1; grid-column-end: 2; grid-row-start:1; grid-row-end:3;
}
.header .title {
grid-column-start: 2; grid-column-end: 3; grid-row-start:1; grid-row-end:2;
}
.header .input {
grid-column-start: 2; grid-column-end: 3; grid-row-start:2; grid-row-end:3;
}
.header .input select {
font-size: 0.75em;
border: 1px solid transparent;;
border-radius: 3px;
padding-top: 2px;
padding-bottom: 2px;
background-color: rgba(255, 255, 255, 0.5);
color: #444;
cursor: pointer;
}
.header .input select:hover {
border: 1px solid #000;
color: #000;
background-color: rgba(255, 255, 255, 1);
}

.questions-section .question-icon-container,
.questions-section .question-pile-container {
display: grid;
grid-template-columns: repeat(18, 1fr);
}
.questions-section .question-pile {
line-height: 10px;
}
.questions-section .icon{
cursor: pointer;
}
.questions-section .question-rect{
display: inline-block;
width: 10px;
height: 10px;
border: 1px solid white;
cursor: pointer;
}
</style>
Insert cell
QuestionsCatalog = {
const questionGroups = d3.create("div");

questionGroups
.attr("class", "question-icon-container")
.selectAll("div")
.data(icons)
.join("div")
.attr("class", "question-icon")
.append(d => d.image)

const questionPiles = d3.create("div");

questionPiles
.attr("class", "question-pile-container")
.selectAll("div")
.data(icons)
.join("div")
.attr("class", "question-pile")
.each(function(d){
const view = d3.select(this)
view.selectAll("div")
.data(question.filter(f => f.sdg_world_topics === d.goal))
.join("div")
.attr("class", "question-rect")
.style("background-color", sdgcolors[d.goal])
})

return html`
${questionGroups.node()}
${questionPiles.node()}
`
}
Insert cell
icons = Promise.all([
FileAttachment("GOAL_1.svg").image(),
FileAttachment("GOAL_2.svg").image(),
FileAttachment("GOAL_3.svg").image(),
FileAttachment("GOAL_4.svg").image(),
FileAttachment("GOAL_5.svg").image(),
FileAttachment("GOAL_6.svg").image(),
FileAttachment("GOAL_7.svg").image(),
FileAttachment("GOAL_8.svg").image(),
FileAttachment("GOAL_9.svg").image(),
FileAttachment("GOAL_10.svg").image(),
FileAttachment("GOAL_11.svg").image(),
FileAttachment("GOAL_12.svg").image(),
FileAttachment("GOAL_13.svg").image(),
FileAttachment("GOAL_14.svg").image(),
FileAttachment("GOAL_15.svg").image(),
FileAttachment("GOAL_16.svg").image(),
FileAttachment("GOAL_17.svg").image(),
FileAttachment("GOAL_other.svg").image(),
]).then(r =>
r.map((m,i)=>({
goal: i===17 ? "other" : "sdg-world-" + d3.format("02")(i+1),
image: m
}))
)
Insert cell
sdgcolors = ({
"sdg-world-01": "#E5243B",
"sdg-world-02": "#DDA63A",
"sdg-world-03": "#4C9F38",
"sdg-world-04": "#C5192D",
"sdg-world-05": "#FF3A21",
"sdg-world-06": "#26BDE2",
"sdg-world-07": "#FCC30B",
"sdg-world-08": "#A21942",
"sdg-world-09": "#FD6925",
"sdg-world-10": "#DD1367",
"sdg-world-11": "#FD9D24",
"sdg-world-12": "#BF8B2E",
"sdg-world-13": "#3F7E44",
"sdg-world-14": "#0A97D9",
"sdg-world-15": "#56C02B",
"sdg-world-16": "#00689D",
"sdg-world-17": "#19486A",
"other": "#555",
})
Insert cell
botLogos = ({
"Anthropic": "https://www.appengine.ai/uploads/images/profile/logo/Anthropic-AI.png",
"OpenAI": "https://static.vecteezy.com/system/resources/previews/022/227/364/non_2x/openai-chatgpt-logo-icon-free-png.png",
"Google": "https://seeklogo.com/images/G/google-ai-logo-996E85F6FD-seeklogo.com.png",
"Alibaba": "https://cms.article-factory.ai/wp-content/uploads/2023/08/alibaba.png",
"Human": "https://s3.eu-west-1.amazonaws.com/static.gapminder.org/GapminderMedia/wp-uploads/20191011145650/mission-framed.png",
"Meta":"https://static.vecteezy.com/system/resources/previews/004/201/564/non_2x/meta-social-network-emblem-blue-stylish-letter-m-or-mobius-band-vector.jpg",
"XAI": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/XAI_Logo.svg/512px-XAI_Logo.svg.png",
"Chimp": "https://s3.eu-west-1.amazonaws.com/static.gapminder.org/GapminderMedia/wp-uploads/20191012155318/gapminder-method.png"
})
Insert cell
sdgGoalText = ({
"sdg-world-01": {
title: "UN Goal 1",
objective: "No Poverty",
description: "By 2030, eradicate extreme poverty for all people everywhere."
},
"sdg-world-02": {
title: "UN Goal 2",
objective: "Zero Hunger",
description: "End hunger, achieve food security and improved nutrition by 2030."
},
"sdg-world-03": {
title: "UN Goal 3",
objective: "Good Health and Well-being",
description: "Ensure healthy lives and promote well-being for all at all ages by 2030."
},
"sdg-world-04": {
title: "UN Goal 4",
objective: "Quality Education",
description: "Ensure that all girls and boys complete free, equitable and quality primary and secondary education by 2030."
},
"sdg-world-05": {
title: "UN Goal 5",
objective: "Gender Equality",
description: "To achieve gender equality and empower all women and girls."
},
"sdg-world-06": {
title: "UN Goal 6",
objective: "Clean Water and Sanitation",
description: "Ensure availability and sustainable management of water and sanitation for all by 2030."
},
"sdg-world-07": {
title: "UN Goal 7",
objective: "Affordable and Clean Energy",
description: "Ensure access to affordable, reliable, sustainable and modern energy for all by 2030."
},
"sdg-world-08": {
title: "UN Goal 8",
objective: "Decent Work and Economic Growth",
description: "Promote sustained, inclusive and sustainable economic growth."
},
"sdg-world-09": {
title: "UN Goal 9",
objective: "Industry, Innovation and Infrastructure",
description: "Build resilient infrastructure, promote inclusive and sustainable industrialization and foster innovation by 2030."
},
"sdg-world-10": {
title: "UN Goal 10",
objective: "Reduced Inequality",
description: "Reduce inequality within and among countries by 2030."
},
"sdg-world-11": {
title: "UN Goal 11",
objective: "Sustainable Cities and Communities",
description: "Make cities and human settlements inclusive, safe, resilient and sustainable."
},
"sdg-world-12": {
title: "UN Goal 12",
objective: "Responsible Consumption and Production",
description: "Ensure sustainable consumption and production patterns."
},
"sdg-world-13": {
title: "UN Goal 13",
objective: "Climate Action",
description: "Take urgent action to combat climate change and its impacts."
},
"sdg-world-14": {
title: "UN Goal 14",
objective: "Life Below Water",
description: "Conserve and sustainably use the oceans, seas and marine resources for sustainable development."
},
"sdg-world-15": {
title: "UN Goal 15",
objective: "Life on Land",
description: "Protect, restore and promote sustainable use of terrestrial ecosystems, combat desertification and halt biodiversity loss."
},
"sdg-world-16": {
title: "UN Goal 16",
objective: "Peace and Justice Strong Institutions",
description: "Promote peaceful and inclusive societies for sustainable development; provide access to justice for all."
},
"sdg-world-17": {
title: "UN Goal 17",
objective: "Partnerships to achieve the Goal",
description: "Strengthen the means of implementation and revitalize the global partnership for sustainable development."
},
"other": {
title: "Other",
objective: "",
description: "Questions not related to UN Sustainable Development Goals"
}
})


Insert cell
sections = {
const height = 175;
return [
{vendor: "OpenAI", data: ratesByModel.get(selectedModels["OpenAI"]), height, marginTop: 0},
{vendor: "Anthropic", data: ratesByModel.get(selectedModels["Anthropic"]), height},
{vendor: "Google", data: ratesByModel.get(selectedModels["Google"]), height},
{vendor: "Alibaba", data: ratesByModel.get(selectedModels["Alibaba"]), height},
{vendor: "Meta", data: ratesByModel.get(selectedModels["Meta"]), height},
{vendor: "XAI", data: ratesByModel.get(selectedModels["XAI"]), height},
{vendor: "Human", data: ratesByModel.get(selectedModels["Human"]), axis: true, marginBottom: 60, height:height+60}
]
}
Insert cell
html = htl.html
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