Back to the talks Previous by time: Saturday opening remarks Next by time: One year progress update Schemacs (formerly Gypsum) Track: General - Watch

Making Org-Babel Reactive

Abhinav Tushar (he/him) - https://lepisma.xyz, @lepisma@mathstodon.xyz, abhinav@lepisma.xyz

The following image shows where the talk is in the schedule for Sat 2025-12-06. Solid lines show talks with Q&A via BigBlueButton. Dashed lines show talks with Q&A via IRC or Etherpad.

Format: 9-min talk ; Q&A: Etherpad https://pad.emacsconf.org/2025-org-babel
Etherpad: https://pad.emacsconf.org/2025-org-babel
Discuss on IRC: #emacsconf-gen
Status: Q&A finished, IRC and pad will be archived on this page

00:01.120 What are reactive notebooks? 00:49.042 Reactivity demo 02:38.499 Org-Babel 03:21.080 Running the whole buffer 03:51.901 Caching 04:21.760 Computation dependencies 06:04.534 Making this even better 07:29.966 Wrapping up

Duration: 08:08 minutes

Description

In Org mode, you can add and execute small snippets of code using Org-Babel. This lets you have an extremely useful mixed-language notebook like environment inside Emacs. These days, many notebook systems provide fully reactive notebooks where changes made in any cell or variable propagate to its dependents without manual execution. This pattern is very useful for exploratory data analysis, visualization, and many other use-cases that notebooks are generally good for.

Unsurprisingly, we can enable such reactivity in Org-Babel without too much effort. In this talk, I will cover how to do that while also adding certain other interaction niceties to make full use of the resultant reactivity.

About the speaker:

I am a programmer and machine learning engineer, and I have enjoyed working with Org-Babel code blocks inside my writings. Other notebooks and platforms have recently started to adopt fully reactive computation, which is something I have liked a lot for exploratory analysis. In this talk, I will show how to add similar reactivity in Org-Babel.

Transcript

[00:00:01.120] What are reactive notebooks?
Hello, everyone. My name is Abhinav, and I'm going to talk about how to make Org Babel reactive. So reactivity here means reactivity in the sense of reactive notebooks. So if you used Org Babel, you might also have used Jupyter notebooks, which are basically notebooks primarily for Python programming, where you have these text and code blocks interleaved, and then you can execute every code block independently, and then you control the order of execution manually, or you can just run the code blocks from top to bottom. But with reactive notebooks, what happens is that there's another way of running which is basically by having all these dependent code blocks automatically get executed whenever you make a change. So for example, if you change a variable, everything else that's dependent on that variable will be executed automatically. I'll show you an example of what that looks like.
[00:00:49.042] Reactivity demo
Right, here's an example reactive Notebook. So this is called Observable. Observable is this tool made by the creator of d3.js which is a famous JavaScript charting library. So here, the interface is very similar to Jupyter Notebook. You basically are having these cells and each cell could be a text cell, like here, this is a Markdown cell and then there are these code blocks. Now each code cell is basically defining a variable. This is important in reactive notebooks because each cell is connected to other cell via this variable usage. So here data is defined, then there is filtered which is defined which is dependent on data, and then this plot is dependent on filtered. So now, in a classical notebook, what I will do is if I change something here, let's say from 1 to 2, I will have to run this, and then run this plot block again to make the change be visible. But in a reactive notebook, what happens is I can just change this from some value to some value, and then execute, and then every descendant is also executed, because that's how the reactivity works. You change this variable, so this should also be changed, because this is dependent on this variable. Now this is really helpful if you have a very complex and messy notebook which is what actually happens in reality. You end up doing an exploratory analysis, and you have these code blocks lying here and there. Then you change something and then you have to keep something in your mind that if I change this, I need to run these five code blocks again to finally get to the result that I want to see. Stale state causes a lot of issues in Jupyter Notebooks. So this is really good for reactivity, sorry reproducibility, but this is also really good for just having this exploration that you're trying to do. For example, you're changing something and it's really easy to just see that change happening in real time in your outcome variables, right?
[00:02:38.499] Org-Babel
So I was wondering how to introduce this reactivity in Org Mode. And here's how it will look like. So this is a demo Org Mode file. There are many Org Babel blocks here. So you start from here. Let's say this is a code block. It has a name. And then there's another code block, which is dependent on the previous one, as you can see here, and so on. And then finally, there's a plot here, which is a gnuplot code. And you can see the image here. Now, what happens usually is that if I change this value from, let's say, 113 to 112, nothing happens on its own right? There's an extra step of execution that I will have to do so I will do that, and then the value is changed. Now the problem is that only this value is changed and if I go down and see the image, nothing will have changed.
[00:03:21.080] Running the whole buffer
So what I can do is basically, a really simple thing is that, a simple trick is to basically enable a hook, like, add a hook whenever you're saving the buffer, you just run the full buffer again, like run all the code blocks automatically. Now if you do that, you can basically make a change somewhere and then you can, you know, see how everything else is changing which gives you some sort of reactivity, but there's still a lot of computation that's being wasted. You might not want to change or run this code block again when something down there is changing. So to counter that, you can actually add caching. So if you add caching to any code block, that code block will only be executed again if that code has changed or the input variables have changed. But the other problem is that you don't want caching to be enabled for a lot of cases where the code block is actually dependent on external state, like for example, some sort of randomness or time. So caching also is, you know, kind of, it's, like, an important thing to use, but it's probably not giving you the complete answer.
[00:04:21.760] Computation dependencies
So what we can instead do is basically figure out the whole computation dependencies here. So let's say if I look at this buffer, here's how all the blocks are connected. So as you can see the plot code block is dependent on c and then legendpg, and they themselves are dependent on these other nodes. So when I make a change in b, I only want b to run and then c and then plot. I don't want anything else to run. So what I did was I wrote a small minor mode for Org Mode which does exactly this. So whenever you are in a code block and you are making a change and then you save it, it will just follow the trail from that code block to every other descendant which is going to be impacted, and it just runs all of them, and nothing else gets executed. So to see it in action, I will just enable that mode. Yeah, right. So now here, if I change this 113 to 112 and I save, this code, this variable gets changed. It's the same value because I did not update it again. And you can also see b also got changed because it's just following all the execution order and so on. The plot also got updated. We will be able to see more clearly once I change something more substantial. So here's another variable. So I added a small toggle button here, which is again part of the minor mode. So since this is nil, if I toggle it, it will become true. And this variable dictates whether the plot will have the legend or not. So if I toggle it to be t, now it's t and you can see that the plot has legend that's visible. If I toggle it back again to nil, the legend is gone. Now this is nice, this...
[00:06:04.534] Making this even better
This is already pretty helpful for me but what we can do is we can make it even better. So one of the nicer ideas from these reactive notebooks is this idea of having an infinite canvas where you don't look at the document model, you look at the whole document as a canvas of multiple connected documents. One good thing that happens there is that you can basically have a piece of code somewhere and then piece of code somewhere very different position in the document, but you can put them together in the canvas and then see them side by side. So here also, let's say if I want to just have this image shown up at the top, what I can do is like I can pop this out, which opens a child frame, and then I can just go here. This child frame is showing the same image. So there's no change. So if I toggle this variable here, you can see that the image is updated. If I toggle it back to nil, the image, the legend is gone. And you can obviously, you know, you can make a lot of things come up as child frames. This is the same image. So even if you go down to the document, you will see the same image. So yeah, this is what I have right now. I'm definitely looking forward to making it more useful, probably including more kinds of child frames, maybe like making the whole document an infinite canvas.
[00:07:29.966] Wrapping up
Alright, so that's the talk. If you're interested in the codebase, here's the homepage for the project [https://dev.lepisma.xyz/git/ob-rx]. So the next steps for me are basically making my workflow easier in matplotlib, which is a Python-based library, and d3.js, which is for JavaScript. For the JS thing, I might have to add the interactive JS child frames, and I am also looking forward to building something which can replicate the work of the Observable's infinite canvas, because that's something which I found really useful in my work with just JS visualizations. So yeah, happy to take questions on Etherpad and thank you for your time.

Captioner: abhinav

Questions or comments? Please e-mail abhinav@lepisma.xyz

Back to the talks Previous by time: Saturday opening remarks Next by time: One year progress update Schemacs (formerly Gypsum) Track: General - Watch