🏠 back to Observable

selecting / reporting data from CSV using D3


#1

How does one report on a specific value (‘data cell’) using JavaScript / d3.js? I am having trouble finding information about some very basic issues of selection (stems from my general lack of understanding JS).

Ideally, I would like to write sentences that could change based on a ‘row’ in a database, something like:

md` ${president.first-name.0} {$president.last-name.0} is president ${president.number.0}.`

Resulting in: Donald Trump is president 45.

and

md` ${president.first-name.1} {$president.last-name.1} is president ${president.number.1}.`

Resulting in: Barack Obama is president 44.

The CSV would be something like:

president = d3.csvParse(`number, first-name, last-name
45, Donald, Trump
44, Barack, Obama
`)

I am sure that my data references above aren’t formatted punctuated correctly - but I am not even sure if this type of specification is possible(?); Many of the tables I am seeing on this site reproduce all data rows - not specific values as for a particular row/colum.

Any insights?

Here’s my draft notebook with the code above:

Thanks in advance for your patience and guidance! It is due to the amazing Observable platform and community that I started learning about JavaScript this year. I appreciate all the help!!


#2

You were almost there! You just had a few minor things tripping you up:

Some notes:

  • spaces are meaningful, so I got rid of those in your CSV
  • csvParse returns an array of objects, so to get data out of it, first give the index of the array, and then the key for the object.
  • The ‘-’ symbol in a key prevents using the ‘.’ syntax; see this reference for some discussion of the dot vs bracket notation.

#3

Awesome Bryan! Thank you for this - super helpful!

I really appreciate all the help. I feel like I am just on the cusp of being able to use JavaScript to more effectively write and communicate… but the learning curve is very steep. Observable has been a great help – and this community is so friendly. Thank you again!!


#4

Hi @bgchen -

A bit of a follow-up question—and maybe this is getting more complex…

How about linking the array identifier to another value? I tried this:

value = 0

md` ${president[{value}]['first-name']} ${president[{value}]['last-name']} is United States president ${president[{value}].number}.` 

… but it doesn’t seem that this sort of in-line nesting of a function within a function works

I am envisioning text that can be changed with an input, like show me the stats for:

Donald,
Barack

And the results would show:

President 44
President 45

Thanks in advance for your time and insights!


#5

For the first part, is what you want a cell like this?

{
  let value = 0;
  return md` ${president[value]['first-name']} ${president[value]['last-name']} is United States president ${president[value].number}.`
}

(The curly braces you had were telling JS to do something else.)
You could also define a function that returns some markdown:

function presidentText(value) {
  const pres = president[value];
  return md` ${pres['first-name']} ${pres['last-name']} is United States president ${pres.number}.`;
}

And then call presidentText(0) or presidentText(1) elsewhere.

The second part is a bit more challenging but still doable. Here’s an outline; if you get stuck feel free to post again. You’ll need to set up an input cell and an output cell. For the input cell, I’d look into using one of the functions from the “Input bazaar”; probably textarea.

For the output, you’ll need two pieces of functionality: first, a parser that processes the data from the input cell and second, some output function that acts on the results from the parser. The parser could be simple or complicated depending on how much flexibility you want to allow in the inputs. In the simplest case, assume that the input data is guaranteed to be a string that consists of a sequence of first names, each on its own line. Then your parser could just be input.split('\n') which chops the input string into an array of strings.

Given that array, you would then write a loop which outputs some text for each element, perhaps something like this:

let output = '';
for (let str of array) {
  // gets the first object in president such that the first-name value is identical to str
  const pres = president.find(p => p['first-name'] === str);
  // append 'President #' + a newline to the output
  output += `President ${pres.number}<br>`;
}
// return output
return md`The output is:<br>${output}`;

#6

Sweet, thanks @bgchen !! This was super helpful.

I managed to get the options working without the more complicated code by aliasing input labels for a dropdown: