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.

5 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.