Public
Edited
May 25
1 fork
Insert cell
Insert cell
Insert cell
mc1_graph = FileAttachment("MC1_graph.json").json()
Insert cell
graph = FileAttachment("MC1_graph.json").json()
Insert cell
graph.nodes.length // cantidad de nodos
Insert cell
graph.links.length // cantidad de relaciones (edges)
Insert cell
data = graph.nodes.slice(0, 5) // muestra los primeros 5 nodos
Insert cell
data
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
data1
X
Node Type
Y
Color
Size
Facet X
Facet Y
Mark
Auto
Type Chart, then Shift-Enter. Ctrl-space for more options.

Insert cell
data3
X*
Y*
Color
Size
Facet X
Facet Y
Mark
Auto
Type Chart, then Shift-Enter. Ctrl-space for more options.

Insert cell
songsFolk = graph.nodes.filter(d =>
(d["Node Type"] === "Song" || d["Node Type"] === "Album") &&
d.genre === "Oceanus Folk"
)


Insert cell
songsFolk
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
Insert cell
tiposDeInfluencia = [
"InStyleOf",
"CoverOf",
"LyricalReferenceTo",
"InterpolatesFrom",
"DirectlySamples"
]

Insert cell
typeof graph.links[0].source // ¿Es string o number?

Insert cell
typeof songsFolk[0].id // ¿Es string o number?
Insert cell
folkIDs = new Set(songsFolk.map(d => d.id)) // ahora es Set<number>

Insert cell
influenciasSalientes = graph.links.filter(d =>
folkIDs.has(d.source) && tiposDeInfluencia.includes(d["Edge Type"])
)

Insert cell
influenciasSalientes.length

/*influenciasSalientes.length = 371 indica que encontraste 371 relaciones de influencia desde canciones o álbumes de Oceanus Folk hacia otras obras.

songsFolk: 305 canciones/álbumes Oceanus Folk

folkIDs: Set de IDs de esos nodos

influenciasSalientes: 371 relaciones de influencia saliente
*/

Insert cell
influenciados = influenciasSalientes.map(d => {
const nodoDestino = graph.nodes.find(n => n.id === d.target)
return {
id: d.target,
genre: nodoDestino?.genre ?? "Desconocido",
year: nodoDestino?.release_date || nodoDestino?.written_date || "Desconocido"
}
}).filter(d => d.genre && d.year)

// Este array influenciados será la base para responder las preguntas 2a y 2b.

Insert cell
data1
X*
Y*
Color
Size
Facet X
Facet Y
Mark
Auto
Type Chart, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
Plot.plot({
y: {label: "Año", type: "band"},
x: {label: "Cantidad de obras influenciadas"},
marks: [
Plot.barX(
d3.rollups(influenciados, v => v.length, d => d.year)
.map(([year, count]) => ({year, count}))
.sort((a, b) => a.year - b.year),
{y: "year", x: "count"}
)
]
})


//🔎 Si ves que sube progresivamente → influencia gradual
//📉 Si hay picos → influencia intermitente

Insert cell
Insert cell
Plot.plot({
marginLeft: 140, // ajusta este valor para más espacio a los nombres
x: {label: "Cantidad"},
y: {label: "Género", type: "band"},
marks: [
Plot.barX(
d3.rollups(influenciados, v => v.length, d => d.genre)
.map(([genre, count]) => ({genre, count}))
.sort((a, b) => d3.descending(a.count, b.count)),
{x: "count", y: "genre"}
)
]
})


Insert cell
Insert cell
// Tipos reales de nodos:
Array.from(new Set(graph.nodes.map(d => d["Node Type"])))
Insert cell
// Paso 1: Conseguir los IDs de obras influenciadas
obrasInfluenciadas = influenciasSalientes.map(d => d.target)
Insert cell
// Paso 2: Buscar relaciones PerformerOf sobre esas obras
performances = graph.links.filter(d =>
obrasInfluenciadas.includes(d.target) && d["Edge Type"] === "PerformerOf"
)
Insert cell
// Paso 3: Mapear performers únicos
performers = performances.map(d => {
const persona = graph.nodes.find(n => n.id === d.source && n["Node Type"] === "Person")
return persona?.stage_name || persona?.name
}).filter(Boolean)

Insert cell
// Paso 4: Contar cuántas veces aparece cada artista
conteoArtistas = d3.rollups(
performers,
v => v.length,
d => d
).map(([name, count]) => ({name, count}))
.sort((a, b) => d3.descending(a.count, b.count))

Insert cell
// Visualización: artistas más influenciados por obras de Oceanus Folk
Plot.plot({
marginLeft: 160,
x: {label: "Cantidad"},
y: {label: "Artista", type: "band"},
marks: [
Plot.barX(conteoArtistas.slice(0, 10), {x: "count", y: "name"})
]
})

Insert cell
Insert cell
// Paso 1: Filtrar obras de Oceanus Folk posteriores a 2028
folkPostSailor = songsFolk.filter(d => +d.release_date >= 2028)

Insert cell
// Paso 1: Filtrar obras de Oceanus Folk posteriores a 2028
folkPostIDs = new Set(folkPostSailor.map(d => d.id))
Insert cell
// Paso 2: Buscar influencias entrantes sobre esas obras
influenciasEntrantes = graph.links.filter(d =>
folkPostIDs.has(d.target) &&
tiposDeInfluencia.includes(d["Edge Type"])
)

Insert cell
// Paso 3: Extraer géneros de los nodos que las influenciaron
origenes = influenciasEntrantes.map(d => {
const nodoOrigen = graph.nodes.find(n => n.id === d.source)
return {
id: d.source,
genre: nodoOrigen?.genre ?? "Desconocido",
year: nodoOrigen?.release_date || nodoOrigen?.written_date || "Desconocido"
}
}).filter(d => d.genre && d.year)

Insert cell
// Visualización: ¿De qué géneros se nutre el Oceanus Folk post-2028?
Plot.plot({
marginLeft: 140, // ajusta este valor para más espacio a los nombres
y: {label: "Género", type: "band"},
x: {label: "Cantidad"},
marks: [
Plot.barX(
d3.rollups(origenes, v => v.length, d => d.genre)
.map(([genre, count]) => ({genre, count}))
.sort((a, b) => d3.descending(a.count, b.count)),
{x: "count", y: "genre"}
)
]
})

//A partir del éxito viral de Sailor Shift en 2028, el género Oceanus Folk comenzó a incorporar elementos estilísticos de géneros como Dream Pop y Space Rock. Esto indica una evolución estética hacia sonidos más atmosféricos y experimentales. Al mismo tiempo, se observa una fuerte autocontinuidad dentro del propio Oceanus Folk, señal de una escena consolidada que se retroalimenta y redefine a partir de sus propios referentes.

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