Public
Edited
Aug 20, 2024
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
tabla = Inputs.table(data)
Insert cell
srcColumn = d3.map(data, d => d.src)
Insert cell
Insert cell
urlsFiltradas = {

function caminoSeleccionado(camino){
const filtradas = data
.filter(d => d.camino === camino)
.map(d => d.url);
return filtradas
}
return caminoSeleccionado("Putumayo")
}
Insert cell
panelFromScenes = async (data, scenes, start) => {
const newScenes = JSON.parse(JSON.stringify(scenes));
await setScenes(data, newScenes);
showPanel(newScenes, start);
return newScenes
}
Insert cell
scenes = (
{
"start": {
"viz": {"filter": [[]], "type": "compare", "x": 276, "y": 288},
"titulo": "Daléctica del Amo y esclavo. Dialéctica del carguero y cargado",
"texto": "<a href='https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&ved=2ahUKEwjCqbef3oqBAxWFrIkEHWw8DrIQFnoECA4QAQ&url=http%3A%2F%2Fwww.worldcat.org%2Foclc%2F741480544&usg=AOvVaw29hbYvFJOR9BxuJ64ke826&opi=89978449' target='_blank'>Susan Buck-Morss</a> sustentó la posibilidad de que Hegel hubiese basado su figura del amo y el esclavo en la revolución de Haití. Humboldt también se interesó en Haití. Los cargueros, los bogas, y otros sujetos subordinados con los que se encontró en América, sirvieron para hacer contrastes con las condiciones de los esclavos. Usando como analogía el caso de Hegel, es posible hablar de una dialéctica del carguero y el cargado. En el relato de Hegel esta dialéctica se desarrolla por medio de una clara inversión en la que el esclavo vence, a partir del conocimiento y la autonomía que adquiere al tener la experiencia directa del objeto por medio de su trabajo, frente al amo quien pierde la autonomía al estar abocado a una experiencia mediada del objeto que solo puede ser consumido en su faceta de manufactura <a href='https://desarmandolacultura.files.wordpress.com/2018/04/hegel-georg-fenomenologia-del-espiritu-edicion-bilingue.pdf' target='_blank'>(Hegel, [1807]2010: 265)</a>. Por su parte, la manera en que Humboldt valora la experiencia directa que tiene el carguero del territorio, frente a la experiencia mediada de los cargados, permite imaginarse una interacción dialéctica semejante a la hegeliana, pero aplicada en este caso al modo como se habita el espacio vertical andino.<br><br> Entonces, Humboldt empieza preocupándose por el modo como el carguero es considerado por los criollos y los españoles como un animal de carga. Es decir, el carguero es cosificado por sus usuarios, quienes lo instrumentalizan y lo usan como un medio para no experimentar ellos mismos el viaje. En este momento del proceso, el carguero no tiene autoconciencia y el reconocimiento que recibe por parte del cargado es el de un animal, que en términos legales es un objeto. Sin embargo, a medida que se desenvuelve el proceso dialéctico, a los ojos de Humboldt el aparente dominio del cargado se invierte debido a que se percata de que, durante el viaje, los cargados dependen totalmente del carguero. Humboldt al describir la figura afirma que “el sillero camina infinitamente recto y erguido, mientras que el cargado, atrás, recostado, presenta una miserable y desamparada figura” <a href='https://descubridor.banrepcultural.org/permalink/57BDLRDC_INST/qk5q4l/alma991005445879707486' target='_blank'>(Humboldt, [1801]1992: 113a)</a>. Asimismo, en su gesto de no querer dejarse cargar está implícito el reconocimiento de la humanidad del otro y de su carácter de fin y no de medio, pero también su determinación de tener una experiencia inmediata del objeto, es decir la experiencia del viaje. <br><br> Por otro lado, Humboldt se explica la existencia de estas personas por el gusto de una vida errante y vagabunda y la idea de independencia (indépendance) que en sus diarios en 1801 había comparado con la “vida libre” (freien leben) sin obligaciones, salvaje como la del “jabalí” con fuertes ansias de volver al “crudo estado de naturaleza” (rohen Naturzustand)<a href='https://descubridor.banrepcultural.org/permalink/57BDLRDC_INST/qk5q4l/alma991005445879707486' target='_blank'>(Humboldt, [1801]1992: 83a)</a>. En este sentido, podria decirse que el carguero va en una dirección opuesta al curso de la historia. El carguero utiliza su poder, libertad y autodeterminación para aferrarse a títulos nobiliarios anacrónicos en un contexto de procesos revolucionarios como los ocurridos en América del Norte, Francia y Haití. Utiliza su poder de negociación y agencia, orientándose hacia un pasado mítico que representa un estado “crudo” de la naturaleza en lugar de buscar la formación de una comunidad política. <br><br> Para Humboldt, esta contradicción debe resolverse por medio de una acción de las autoridades, a las que indistintamente Estado (der Staat), República (Republik), o Gobierno (Gouvernement) <a href='https://descubridor.banrepcultural.org/permalink/57BDLRDC_INST/qk5q4l/alma991005445879707486' target='_blank'>(Humboldt, [1801]1992: 114a)</a>. En este caso, reformas legales, en la educación y racionalizaciones en el ejercicio de la técnica pueden en efecto redirigir los usos de la energía humana. De esta manera, la lectura que hace Humboldt del carguero presenta ambigüedades que no tienen una resolución cierta por el momento. Estas se mantienen en un estado de suspensión. Así, la escena del encuentro de Humboldt con Villanero se puede leer como un evento en el que ciertos lenguajes, metáforas, imágenes y gestos permiten imaginar una inversión en los términos de la relación entre lo que está arriba y lo que está abajo.",
"opciones": [{"btn":"<<<", "scene":"inicio"}]

},
}
)
Insert cell
setScenes = async (data, scenes) => {
const msg = d3.select("#panel-container").append("div").text("Loading Atlas...");
// v 0.3.0
// sintaxis = {filter: () => {}, type: pack, scatter, compare, x:, y:}
const keys = Object.keys(scenes);
const vizFunction = {'pack': vanillaCanvasPack, 'scatter': vanillaCanvasScatter, 'compare': vanillaCanvasCompare}

for (let k of keys) {
if (scenes[k].viz !== undefined) {
const {filter, type, x, y} = scenes[k].viz;
let filtered = data;
for (let f of filter) {
const fn = filterFn(f)
filtered = fn(filtered);
}
const {viz, areas} = await vizFunction[type](filtered, x, y);
scenes[k].image = viz;
scenes[k].areas = areas;
}

let newText = "";
if (scenes[k].meta) {
newText += getMeta(data[scenes[k].meta]);
scenes[k].image = data[scenes[k].meta].url;
delete scenes[k].meta;
}
if (scenes[k].title) {
newText += `<h3>${scenes[k].title}</h3>`;
delete scenes[k].title;
}
scenes[k].text = newText + (scenes[k].text || "");

if (scenes[k].info) { scenes[k].text +=`<a href=${scenes[k].info[1]} target="_blank">${scenes[k].info[0]}</a>` }
}

function getMeta(d) {
return `<div class="meta-container"><p><b>Title:</b> ${d.obras}</p><p><b>Date:</b> ${d.fecha}</p><p><b>Author:</b> ${d.autor}</p><p><b>Source:</b> ${d.fuente}</p><p><b>Description:</b> ${d.descripcion}</p><a class="repo-link" href="${d.repositorio}" target="_blank">Repository</a></div>`
}

function filterFn(f) {
if (f[1] === "=" || f[1] === "==" || f[1] === "===") {
const condition = /true|True/i.test(""+f[2]) ? true : /false|False/i.test(""+f[2]) ? false : f[2];
return data => data.filter(d => d[f[0]] == condition)
} else if (f[1] === "<") {
return data => data.filter(d => d[f[0]] < f[2])
} else if (f[1] === ">") {
return data => data.filter(d => d[f[0]] > f[2])
} else {
return data => data
}
}

for (let d of data) {
scenes[`ind_${d.n}`] = {
image: d.url,
text: getMeta(d),
options: [{ btn: "<<<", scene: `ind_${d.n}`, back: true }]
}
}

msg.remove();

return scenes
}
Insert cell
showPanel = (scenes, start) => {
let prevScene = start;
const a = new aventuraModule.Aventura('en', {
adventureContainer: "panel-container",
typewriterSpeed: 0,
sceneCallbackStart: (scene) => {
if (prevScene === scene.key) return
if (scene.options === undefined) {
scene.options = [{ btn: "<<<", scene: prevScene, back: true }];
} else {
if (scene.options[0].back) {
scene.options[0].scene = prevScene;
} else {
scene.options.unshift({ btn: "<<<", scene: prevScene, back: true });
}
}

if (!scene.key.includes("ind_")) {
prevScene = scene.key;
}
}
})
a.setScenes(scenes).testScenes().startAdventure(start)
return scenes
}
Insert cell
processedScenes = panelFromScenes(data, scenes, 'start')
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
vanillaCanvasScatter = async (data, vx, vy) => {
const size = 50;
const margin = {l: 0.2 * width, r: 0.1 * width, t: 0.1 * height, b: 0.1 * height};
const wm = width - margin.l - margin.r;
const hm = height - margin.t - margin.b;
const filtered = data;

const domainX = [...new Set(filtered.map(d => d[vx]))];
const domainY = [...new Set(filtered.map(d => d[vy]))];
const scaleX = d3.scalePoint().domain(domainX).range([0, wm]).padding(0.5).round(true);
const scaleY = d3.scalePoint().domain(domainY).range([0, hm]).padding(0.5).round(true);

const imgs = [];
for (let d of filtered) {
const img = new Image();
img.setAttribute('crossorigin', 'anonymous');
img.src = d.url;
await new Promise(r => { img.onload = () => { r(true) }});
imgs.push({ url: d.url, x: scaleX(d[vx]), y: scaleY(d[vy]), img: img, r: size, n: d.n });
}

const simulation = d3.forceSimulation(imgs)
.force("charge", d3.forceManyBody().strength(5))
.force("collide", d3.forceCollide(10))
.tick(200)

const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
ctx.fillStyle = "#313131";
ctx.fillRect(0, 0, width, height);

ctx.strokeStyle = "white";
ctx.font = "14px serif";
ctx.textBaseline = "middle";
ctx.textAlign = "center";

for (let d of domainX) {
ctx.fillStyle = "white";
ctx.fillText(d, margin.l + scaleX(d), margin.t + hm + (margin.b / 2));
}
ctx.beginPath();
ctx.moveTo(margin.l, margin.t + hm);
ctx.lineTo(margin.l + wm, margin.t + hm);
ctx.stroke();

ctx.textAlign = "right";
for (let d of domainY) {
ctx.fillStyle = "white";
ctx.fillText(d, margin.l - 5, margin.t + scaleY(d));
}
ctx.beginPath();
ctx.moveTo(margin.l, margin.t);
ctx.lineTo(margin.l, margin.t + hm);
ctx.stroke();

ctx.strokeStyle = "black";

const areas = [];
for (let i of imgs) {
const w = size;
const h = w * i.img.height / i.img.width;
const j = Math.random() * 100;
const x = i.x + margin.l + j;
const y = i.y + margin.t // + Math.random() * 10;

ctx.save();
ctx.translate(-w/2, -h/2);
ctx.drawImage(i.img, x, y, w, h);
ctx.restore();

const area = {
x, y, w, h,
btn: "",
scene: `ind_${i.n}`,
tooltip: ""
}
areas.push(area);
}

return {viz: canvas.toDataURL('image/png'), areas}
}
Insert cell
vanillaCanvasPack = async (data, h1, h2) => {
const filtered = data;
const groups = d3.rollup(filtered, v => v.length, d => d[h1], d => d[h2])
const childrenAccessorFn = ([ key, value ]) => value.size && Array.from(value)
const root = d3.hierarchy(groups, childrenAccessorFn)
.sum(([,value]) => value)
.sort((a, b) => b.value - a.value)

const scheme = [...d3.schemeGreys[4]].reverse();
// scheme[0] = "#313131";
const desc = root.descendants();

const color = (v) => scheme[v];

d3.pack(root)
.size([width, height])
.padding(20)
(root)
const imgs = [];
for (let f of filtered) {
for (let d of root.leaves()) {
if (f[h1] === d.parent.data[0] && f[h2] === d.data[0]) {
const img = new Image();
img.setAttribute('crossorigin', 'anonymous');
img.src = f.url;
await new Promise(r => { img.onload = () => { r(true) }});
imgs.push({ url: f.url, x: d.x, y: d.y, r: 25, img: img, n: f.n });
}
}
}
const simulation = d3.forceSimulation(imgs)
.force("collide", d3.forceCollide(20))
.tick(200)
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
ctx.fillStyle = "#313131";;
ctx.fillRect(0, 0, width, height);
ctx.font = "12px serif";
ctx.textBaseline = "middle";
ctx.textAlign = "center";

for (let d of desc) {
ctx.save();
ctx.translate(d.x, d.y);
ctx.strokeStyle = "black";
ctx.fillStyle = color(d.depth);
ctx.beginPath();
ctx.ellipse(0, 0, d.r, d.r, 0, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();

ctx.fillStyle = "black";
ctx.fillText(d.depth === 1 || d.depth === 2 ? d.data[0] : "", 0, -d.r - 5);
ctx.restore();
}

const areas = [];
for (let i of imgs) {
const w = parseInt(50);
const h = parseInt(w * i.img.height / i.img.width);
const j = (Math.random() - 0.5) * 100;
const x = i.x // + j;
const y = i.y // + j;
ctx.save();
ctx.translate(-w/2, -h/2);
ctx.drawImage(i.img, x, y, w, h);
ctx.restore();

const area = {
x, y, w, h,
btn: "",
scene: `ind_${i.n}`, // ¿Cómo definir esto?
tooltip: ""
}
areas.push(area);
}

return {viz: canvas.toDataURL('image/png'), areas}
// return canvas
}
Insert cell
vanillaCanvasCompare = async (data, h1, h2) => {
const filtered = [data.find(d => d.n == h1), data.find(d => d.n == h2)];

const imgs = [];
for (let f of filtered) {
const img = new Image();
img.setAttribute('crossorigin', 'anonymous');
img.src = f.url;
await new Promise(r => { img.onload = () => { r(true) }});
imgs.push({ url: f.url, img: img, n: f.n });
}
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
ctx.fillStyle = "#313131";
ctx.fillRect(0, 0, width, height);
ctx.font = "12px serif";
ctx.textBaseline = "middle";
ctx.textAlign = "center";

const areas = [];
let count = 0;
for (let i of imgs) {
const m = parseInt(width / 2) * 0.1
const w = parseInt(width / 2) - m;
const h = parseInt(w * i.img.height / i.img.width);
const x = (count * (w + m)) + (w/2) + (m/2);
const y = height/2;
ctx.save();
ctx.translate(-w/2, -h/2);
ctx.drawImage(i.img, x, y, w, h);
ctx.restore();

const area = {
x, y, w, h,
btn: "",
scene: `ind_${i.n}`, // ¿Cómo definir esto?
tooltip: ""
}
areas.push(area);
count++;
}

return {viz: canvas.toDataURL('image/png'), areas}
// return canvas
}
Insert cell
Insert cell
Insert cell
Insert cell
<!-- <style>
#storygeneraldiv {
font-family: Baskerville, "Baskerville Old Face", "Hoefler Text", Garamond, "Times New Roman", serif;
box-sizing: border-box;
background: white;
margin: auto;
max-width: 900px;
border: solid 1px black;
border-radius: 5px;
/* box-shadow: 1px 1px 5px black; */
}

/* .storydiv {
display: grid;
grid-template-columns: 4fr 2fr 1fr;
} */

.storyp {
min-height: 40px;
max-width: 100%;
padding: 0px 10px;
font-size: 18px;
text-align: justify;
}
.storyp h3 {
font-size: 30px;
text-align: left;
max-width: 100%;
margin: 5px 0px;
font-weight: 400;
}
.storyp p{
}

.storyp a{
text-decoration: none;
color:#3fab9b;
font-weight: 300px;
margin: 10px 0px;
}
.storyp a:hover {
text-decoration: none;
color:#FFFFFF;
background:#3fab9b;
}
.storyp img {
width: 50%;
justify-content: center;
margin: auto;
border: 20px;
display: block;
padding: 20px;
}

.meta-container p {
max-width: 100%;
margin: 0px;
padding: 0px;
}

.meta-container {
/* max-width: 100%; */
margin: 20px 0px;
}


.storybutton-container {
text-align: center;
}
.storybutton {
font-family: Baskerville, "Baskerville Old Face", "Hoefler Text", Garamond, "Times New Roman", serif;
padding: 10px;
background:#FFFFFF;
color:#3fab9b;
border: solid 1px black;
cursor: pointer;
/* box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19); */
/* border-radius: 12px; */
margin: 5px 1em 5px 5px;
font-size: 20px;
font-weight: 600;
}
.storybutton:hover {
color:#FFFFFF;
background:#3fab9b;
/* box-shadow: 0 6px 20px 0 rgba(0,0,0,0.19), 0 8px 16px 0 rgba(0,0,0,0.2); */
}

.storyimage-container {
box-sizing: border-box;
position: relative;
padding: 10px;
max-width: 100%;
max-height: 80vh;
margin: auto;
display: flex;
}

.storyimage {
justify-content: center;
max-width: 100%;
max-height: 80vh;
margin: auto;
border: 1px solid black;
border-radius: 5px;
display: block;
}

.storyimage-area {
box-sizing: border-box;
position: absolute;
cursor: pointer;
text-align: center;
font-size: 10px;
border: solid black 1px;
}

.storyimage-area:hover {
background-color:#FFFFFF;
opacity: 0.4;
}
@media screen and (max-device-width: 400px) {
#storygeneraldiv {
max-width:50%;
}
.storyimage {
max-width: 50%;
}
.storyp {
font-size: 7vw;
}
.storybutton {
font-size: 10vw;
}
}
</style> -->
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