Hey, there. I’m having a strange issue with some data loaded from a CSV file. The notebook is here: The Most Unique Comic Book Characters / Jon Schultz / Observable
I’m trying to do some macro analysis of the data in the attached file, a collection of comic book character names, with their respective publisher name and a collection of boolean values for if they do/don’t have certain powers.
The notebook is importing the data from the CSV just fine with this code:
heroesFull = d3.csvParse(await FileAttachment("Heroes_Powers@2.csv").text())
Upon loading the notebook, the second cell is correctly referencing a specific row of data in that CSV
heroesFull[238]
I’m getting the expected result of Name: “Man of Miracles”, Publisher: “Image Comics”, etc.
However, anytime I click the expand arrow on that cell, or even re-run that cell, it changes the value of that cell to be an array of all the “Name” values in the original dataset. This doesn’t seem to happen with other rows from that data set.
Any idea what’s going on here?
Sup @foundflavor! In the cell heroesUniqueness
you write:
let name = [];
…
name = heroesFull[238]
…
for (let i = 0; i < heroesFull.length; i++) {
name[i] = heroesFull[i].Name;
…
}
…
(I found this by opening the new “Find and Replace” sidebar with the icon on the right and searching for 238.)
This assigns the hero object with index 238 to the name name
. Then it loops over all heroes and assigns each of their names to the key i
of name
. So hero 238 ends up with the names of all the heroes, in addition to its original properties. If you check heroesFull[238].Name
, you can see it still has it (“Man of Miracles”) — it just has six hundred properties (0, 1, 2…) that show up in the inspector first. It looks like an array, but it’s still the same object; heroesFull[238].length
is undefined.
The first time you load the notebook, heroesFull[238]
runs before heroesUniqueness
, so it shows the original value. When heroesUniqueness
mutates the value of item 238, Observable doesn’t know that anything has changed, so it doesn’t update the inspector. But when you expand it or re-run it or anything, you see the mutated version of the object.
I’m probably over-explaining here; it seems like maybe you just forgot you had the line name = heroesFull[238]
in there. It seems like it’s not really doing anything; you had already declared let name = [];
, and things seem to work fine without it.
This sort of surprising behavior often results from mutation; when I saw your question, the first thing I did was look for code that was mutating heroesFull
. There are various explanations of mutation in JavaScript; this was just one of the top Google results: Arrays, Objects and Mutations. Here are some thoughts on how to avoid… | by Federico Knüssel | Medium.
Mutation is fine and common and natural and useful in plenty of programming environments, but in Observable, we recommend avoiding mutating the value of one cell from another cell. This and other advice is explained in this notebook:
Thank you! Such a silly thing to miss. Nevertheless, I appreciate the thorough explanation. Cheers.
1 Like