Evaluate from FileAttachment

Is there a way to evaluate a cell from a FileAttachment call

index = 3
FileAttachment(`image_${index}.gif`).image()

produce the error SyntaxError: FileAttachment requires a single literal string argument

html`${await FileAttachment(`image_3.gif`).image()}`

works. How to transform this expession to an evaluted expression where 3 could take values from 1 to 12 from an input slider for example.

It’s not possible :man_shrugging:

References to files are parsed statically. We use static analysis to determine which files a notebook uses so that we can automatically publish referenced files when a notebook is published (and only referenced files), and similarly copy only referenced files when forking a notebook. The FileAttachment function thus accepts only literal strings; code such as

FileAttachment("my" + "file.csv")

or similar dynamic invocation is invalid syntax. For details on how this is implemented, see our parser.

You can alias FileAttachment:

FA = FileAttachment

and then use the aliased function with dynamic strings:

FA(`image_${index}.gif`).image()

However, please note that this is most likely unsupported and not something to rely on regularly.

6 Likes

If you want to just swap different images dynamically, maybe you can pull all the .url() to another cell in an object like {a:…,b:…,c…} and then use that to get the image dynamically from the list of uploaded files? I’m sure it has an overhead of waiting for the urls though.

that’s a cool hack!

1 Like

Mike is spilling aLL Ze SeCrEts if you just watch the Observable repos long enough, e.g. observablehq/parser/pull/129.

On a more serious note, it’s easier to explain Observable (and its gotchas) to others if you understand how it works under the hood. And, except for the occasional dependabot rampage, they’re not too noisy.

1 Like

The recommended way to do this is to enumerate all your file attachments, and then reference them symbolically, rather than referencing the names.

So:

files = [
  FileAttachment("image_0.gif"),
  FileAttachment("image_1.gif"),
  FileAttachment("image_2.gif"),
  FileAttachment("image_3.gif"),
  FileAttachment("image_4.gif"),
  FileAttachment("image_5.gif"),
  FileAttachment("image_6.gif"),
  FileAttachment("image_7.gif"),
  …
]

And then

index = 3
files[index].image()

Or

html`${await files[index].image()}`

We use static analysis to determine which files your notebook references, so that files are automatically made public when you publish. There are ways to circumvent this, but it shouldn’t be needed if you enumerate your file attachments statically as shown above. And it’s also important to note that this technique is compatible with lazy loading: a referenced file is not loaded until you call a load method on it, such as file.image or file.json.

7 Likes

Thank you !

Not sure to achieve the small interface to control animation I have started. I am still not confortable with this dynamic programming.

My current attempt

You may find this helpful:

Here’s a quick example forked from your notebook:

1 Like

Yes, Scrubber input helps perfectly on how to control animations. Thanks.

I also mention work from https://observablehq.com/@oscar6echo/player that has more control options.