Mixing viewof with standard inspector

I am trying to show arrays in Table while using the standard inspector for everything else, using the following cell:

viewof y = Array.isArray(x) ? Table(x) : x

This works great when x is an Array, and I can use y as a variable elsewhere in the notebook, but when the variable isn’t an array, y is no longer the value. Is there a way to either use viewof selectively, or wrap a value in such a way that viewof just passes it on to the standard inspector?

Welcome to the forum, Vic — that’s a cool idea! Since viewof has to be statically declared, and expects a DOM element with a value property firing input events, I can’t think of a way to use viewof selectively or make it work with the standard Inspector.

Are you assigning x to y here because you want to use the Table’s checkboxes to filter the values? If you don’t care about the checkboxes (or referencing the value of their output), then this cell could just be Array.isArray(x) ? Table(x) : x and you could refer to x elsewhere, no need for y.

The other (harder!) possibility is to make a custom version of the inspector that works like a view. I’ve sometimes wanted something like that myself; e.g., you can imagine a JSON inspector that lets you select a child as the value of the cell, for recursive drilldown stuff. And I’ve certainly wondered about more control over how the default inspector shows different kinds of things. Hm… looks like the heart of the inspector is here: inspector/inspect.js at master · observablehq/inspector · GitHub. Maybe we could just set the value on that and it’d work with viewof?

But for now I think my pragmatic advice is that it’s an elegant idea which the current implementations make tricky, and I’d just use two separate cells there.

@vic You could roll your own inspect helper, using the following cells:

Inspector = import('@observablehq/notebook-inspector').then(m => m.Inspector)
import {Table} from '@observablehq/inputs'
function inspect(value) {
  if(Array.isArray(value)) return Table(value);
  const wrapper = Object.assign(html`<div>`, {value});
  new Inspector(wrapper).fulfilled(value);
  return wrapper;
}
viewof data = inspect(x)

Edit: @observablehq/notebook-inspector is deprecated. Use @observablehq/inspector instead.

3 Likes

Thank you both for your help. @mootari, thank you for the code example. I hadn’t realized that it was that easy to call the inspector.

Let me recommend as an alternative:

Inspector = (await import('@observablehq/inspector')).Inspector

I’ve written a little helper here:

So now you can say:

import {inspect} from "@observablehq/inspector"

(It doesn’t do the automatic Table conversion like @mootari’s version because that feels a little too opinionated for my tastes.)

1 Like

Same, I just added it for the topic’s original request.

1 Like

Perhaps throw in a div.style.margin = 0; so that if you stack a bunch of inspectors in a row they don’t end up taking a large amount of extra space above/below.

Comparison:

2 Likes

A bit off topic, but is there a reason to prefer require("@observablehq/inspector@3/dist/inspector.js") vs. just require("@observablehq/inspector@3")?

If you specify a complete path then require can skip loading the package.json, so it’s slightly faster to resolve.

1 Like