# Automatically convert a Pluto Cell to markdown

**URL:** <https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012>\
**Category:** Pluto\
**Tags:** markdown\
**Created:** [September 30, 2021, 8:52pm UTC](https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012 "2021-09-30T20:52:35Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Bastien](https://avatars.discourse-cdn.com/v4/letter/b/51bf81/32.png) [@Bastien](https://discourse.julialang.org/u/Bastien)\
**Post date:** [September 30, 2021, 8:52pm UTC](https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012/1 "2021-09-30T20:52:35Z")

</div>

Hi,

I am thinking of using Pluto as a sort of Electronic Lab Notebook from where I could drive an experiment and do analysis on the fly. To avoid running a command (e.g. measuring the transmission of a device with a VNA) several times, I was thinking of turning a cell into markdown after it has been executed. Ideally, I would like to add a timestamp and place the command in between backticks so that it’s nicely formatted. Is there a way to do that automatically, for instance using a macro? If not, is there a way to define keyboard shortcuts?

Any suggestion to make this cell conversion to markdown would be appreciated.

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [September 30, 2021, 9:10pm UTC](https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012/2 "2021-09-30T21:10:11Z")

</div>

You may want to consider [`produce_or_load`](https://juliadynamics.github.io/DrWatson.jl/dev/save/#DrWatson.produce_or_load) from DrWatson.jl, which would save the results of each command to an external file for later analysis.

---

<div class="post-metadata">

**Author:** ![Bastien](https://avatars.discourse-cdn.com/v4/letter/b/51bf81/32.png) [@Bastien](https://discourse.julialang.org/u/Bastien)\
**Post date:** [September 30, 2021, 9:42pm UTC](https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012/3 "2021-09-30T21:42:11Z")

</div>

Thanks for your input but I don’t think it fits what I’m looking for. I’d like to be able to mix instrument driving/data taking and analysis. To clarify, I made a mock-up of what I have in mind: suppose I have a command `measure_transmission` that drives an instrument and there’s a ‘magic’ macro that does the cell conversion I’m thinking of. Before running the cell, it would look like that:

 ![Screenshot 2021-09-30 153213](https://global.discourse-cdn.com/julialang/original/3X/a/7/a73f3815566cfdd8556b9eaa3b09630b9496fd8e.jpeg)  
and after running the cell, it would look like this:  
 ![Screenshot 2021-09-30 153445](https://global.discourse-cdn.com/julialang/original/3X/5/f/5ffc9ce4d8bb12901a14abb1b945388e3b843680.jpeg)

I hope this clarifies what I have in mind…

---

<div class="post-metadata">

**Author:** ![tbeason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbeason/32/15898_2.png) [@tbeason](https://discourse.julialang.org/u/tbeason)\
**Post date:** [September 30, 2021, 9:46pm UTC](https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012/4 "2021-09-30T21:46:27Z")

</div>

After my little playing with Pluto, I’m not sure what you seek is possible and if I’m allowed to speculate I believe it goes against the very intentions of the tool.

I believe you’d have more luck trying to get Jupyter notebooks to do something like this.

---

<div class="post-metadata">

**Author:** ![Bastien](https://avatars.discourse-cdn.com/v4/letter/b/51bf81/32.png) [@Bastien](https://discourse.julialang.org/u/Bastien)\
**Post date:** [September 30, 2021, 9:54pm UTC](https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012/5 "2021-09-30T21:54:41Z")

</div>

Not sure why this would be against the intentions of the tool. All I want is a quick and easy way to turn a cell into markdown (easy with a ctrl+m) but in addition I’d like to have the code surrounded by backticks so that it is displayed as a code block in markdown.

I’d like to keep using Pluto because I actually really like the reactivity for the analysis part and I also like that it directly adds packages that are not installed yet.

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [September 30, 2021, 10:04pm UTC](https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012/6 "2021-09-30T22:04:44Z")

</div>

I don’t think it’s completely out of scope - Fons started a discussion on experimental control this spring:

> **[Use Pluto to control physical systems · fonsp/Pluto.jl · Discussion #958](https://github.com/fonsp/Pluto.jl/discussions/958)**
>
> We are very interested to learn how Pluto can be used to control physical systems, and we would like to hear your ideas on how Pluto can be improved to better support this use case! Why? Controllin...

There’s some discussion of converting cells to Markdown here:

> [@Markdown cells in Pluto](https://discourse.julialang.org/t/markdown-cells-in-pluto/60948):
>
> Hello! I think this could be a nice feature: be able to make some cells md cells. The idea is the following: Click to button next to the “fold” button Then the code is wrapped by md"""\<your code\>""", as with Ctrl-M. [image] Extra feature: hide md""" and """ from the code and highlight as markdown. This could apply for Ctrl-M too. UPDATE: I’m at this point [https://github.com/i-apellaniz/Pluto.jl/tree/markdown-toggle](https://github.com/i-apellaniz/Pluto.jl/tree/markdown-toggle) at the moment.

---

<div class="post-metadata">

**Author:** ![Bastien](https://avatars.discourse-cdn.com/v4/letter/b/51bf81/32.png) [@Bastien](https://discourse.julialang.org/u/Bastien)\
**Post date:** [September 30, 2021, 10:12pm UTC](https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012/7 "2021-09-30T22:12:25Z")

</div>

Thanks for the links, this is exactly what I had in mind. The issues mentioned in that thread (e.g. unintentional reactivity) are the reasons why I was thinking of turning the cells into markdown: I would keep track of past commands without running the risk of having these commands re-run if I restart the notebook.

---

<div class="post-metadata">

**Author:** ![disberd](https://avatars.discourse-cdn.com/v4/letter/d/8edcca/32.png) [@disberd](https://discourse.julialang.org/u/disberd)\
**Post date:** [September 30, 2021, 10:13pm UTC](https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012/8 "2021-09-30T22:13:46Z")

</div>

Should be doable by making a macro return a block where the first expression execute the Julia code and the second expression (the one that is sent to the Pluto output) returns an Html with Javascript inside a script tag that modifies the cell to markdown and then rerun it…

~~Not at the computer to try it now though~~

Edit:  
I did have a chance to try this and indeed it is possible:  
 ![79b7954a-c6aa-4a4f-a89a-ca91cac8dcbc](https://global.discourse-cdn.com/julialang/original/3X/a/7/a7a3224bba8e52bc248756484285591d11ef1858.gif)

And here is the link to the notebook code for testing:

> <https://github.com/disberd/pluto-notebook-tests/blob/main/turn_cell_into_markdown.jl>

Note that this is somehow a hacky solution which might not work anymore when Pluto changes to CM6 (don’t know how long it’ll take), or in general with new versions of Pluto.

But overall it still highlight the amazing capabilities of Pluto!

---

<div class="post-metadata">

**Author:** ![Bastien](https://avatars.discourse-cdn.com/v4/letter/b/51bf81/32.png) [@Bastien](https://discourse.julialang.org/u/Bastien)\
**Post date:** [October 1, 2021, 4:01pm UTC](https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012/9 "2021-10-01T16:01:24Z")

</div>

That looks awesome! I’m going to try it in lab as soon as I have a chance. Thanks!

---

<div class="post-metadata">

**Author:** ![AwesomeQuest](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/awesomequest/32/38910_2.png) [@AwesomeQuest](https://discourse.julialang.org/u/AwesomeQuest)\
**Post date:** [March 19, 2025, 8:47pm UTC](https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012/10 "2025-03-19T20:47:44Z")

</div>

Hi, any updates on this? It doesn’t seem to work anymore.  
I’m using ImageClipboard.jl to copy images into the notebook but I need the images to be persistent.  
Is there a way to just never re-run a pluto cell?

---

<div class="post-metadata">

**Author:** ![disberd](https://avatars.discourse-cdn.com/v4/letter/d/8edcca/32.png) [@disberd](https://discourse.julialang.org/u/disberd)\
**Post date:** [March 20, 2025, 8:24am UTC](https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012/11 "2025-03-20T08:24:59Z")

</div>

Things changed a bit with recent CodeMirror updates in Pluto since the answer.

The original macro code can be simply modified to work again by changing this line:

```js
const cm = cell.querySelector('pluto-input .CodeMirror').CodeMirror

```

into this other line

```js
const cm = cell.querySelector('pluto-input .cm-editor').CodeMirror

```

with the new macro code being:

```julia
macro run_and_log(ex::Expr)
	ex = esc(ex)
	blk = Expr(:block) # Create the block
	push!(blk.args,ex) # Add the input expression for execution
	# Here we create the javascript snippet that will be sent to the output and thus be executed.
	script = :(@htl("""
		<script>
			// Get the current timestamp
			let currentdate = new Date(); 
			let dateTime = currentdate.toLocaleString();
			
			// Change the cell input contents
			const cell = currentScript.closest('pluto-cell')
			const cm = cell.querySelector('pluto-input .cm-editor').CodeMirror
			let new_text = cm.getValue().replace('@run_and_log ','')
			const newVal = `md\"\"\"
timestamp: \${dateTime}
\\`\\`\\`julia
\${new_text}
\\`\\`\\`
\"\"\"`
			cm.setValue(newVal)
			
			// Simulate pressing the run button
			cell.querySelector('.runcell').click()
			
		</script>
	"""))
	push!(blk.args,script)
	blk
end

```

That being said, this code will not really work directly as is to copy an image persistently to the notebook, as it is only storing the raw text of the expression provided as input to it.

You need to modify it to actually store in the cell code the raw HTML necessary to show the image (which you can extract in string form using `repr(MIME"text/html"(), image)`).

I can’t try it out in Pluto now to create a solution but you should be able to experiment with it to get a working solution based on the pointers above

---

<div class="post-metadata">

**Author:** ![AwesomeQuest](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/awesomequest/32/38910_2.png) [@AwesomeQuest](https://discourse.julialang.org/u/AwesomeQuest)\
**Post date:** [March 21, 2025, 9:47am UTC](https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012/12 "2025-03-21T09:47:15Z")

</div>

Thanks for the reply!  
I’m having trouble getting the cell output (my javascript is a bit rusty).  
I don’t understand how `cell.querySelector('pluto-input .cm-editor').CodeMirror` works, specifically why does the result of `querySelector` have the property `CodeMirror`? What does getting it do?

I’ve tried using `cell.querySelector('pluto-output div').innerHTML` and sticking that to the cell input but all I get in the cell is

```html
<script>{
    window. ____FUNCTION_TO_RUN_INSIDE_SCRIPT_1.result = window.____ FUNCTION_TO_RUN_INSIDE_SCRIPT_1.function_to_run(window. ____ FUNCTION_TO_RUN_INSIDE_SCRIPT_1.currentScript)
}</script>

```

How do I get the output of the cell?  
Also, if I can get the output of the cell, can’t I get the raw image from the html instead of using `repr`?

---

<div class="post-metadata">

**Author:** ![disberd](https://avatars.discourse-cdn.com/v4/letter/d/8edcca/32.png) [@disberd](https://discourse.julialang.org/u/disberd)\
**Post date:** [March 22, 2025, 9:03am UTC](https://discourse.julialang.org/t/automatically-convert-a-pluto-cell-to-markdown/69012/13 "2025-03-22T09:03:45Z")

</div>

The call

```js
cell.querySelector('pluto-input .cm-editor').CodeMirror

```

first selects (with the querySelector) a specific DOM element inside the input of the current cell (specifically the first element with class `cm-editor` inside the cell input).  
This object happens to be the one that holds the `CodeMirror` property that can be used to change the cell code.

For the second point, indeed Pluto does some magic inside and hides output of scripts inside a function that relies on internals and you don’t directly have access to the output when using scripts.

Lastly, the reason why I was suggesting using directly `repr` is that it’s just an easier way to get the output of a specific object you want to make _ **permanent** _ (with the caveat that your object needs to have a method defined for `MIME"text/html"()` to work easily).

That being said, if what you want to do is really take an image (or any other object with a `show` defined for `MIME"text/html"`) and make it static/permanent in the notebook, you can do it quite easily using just functions instead of a macro (I had the macro in the solution of this thread as I needed to also know the expression fed to it).

Here is the code of a very small test notebook I just tested (omitting the last cell as it became quite big with the image)

Note that the code used in this notebook does not use anymore the CodeMirror instance directly but relies on some Pluto actions that are accessible from the cells. While this still relies on Pluto internals and is thus not guaranteed to work in the future, I think these internal actions are more stable than relying on extracting the `CodeMirror` object directly.

> **Notebook Code**
>
> ````julia
> ### A Pluto.jl notebook ###
> # v0.20.5
> 
> using Markdown
> using InteractiveUtils
> 
> # ╔═╡ 566835f8-7014-48e7-af47-679c551e5188
> using HypertextLiteral
> 
> # ╔═╡ a7fbc49f-e32a-43dd-aff4-7cf3d5fcb8d5
> using ImageClipboard
> 
> # ╔═╡ 2c5464de-db37-45ec-871a-aeb59a867f1f
> using Images # Needed to have the show method in HTML
> 
> # ╔═╡ 736f6600-06f5-11f0-2cbb-3d4f5a18edee
> begin
> update_this_cell_content(io::IO) = update_this_cell_content(String(take!(io)))
> function update_this_cell_content(content::AbstractString)
> @htl("""
> <script>
> const cell = currentScript.closest("pluto-cell")
> const actions = cell._internal_pluto_actions
> actions.set_local_cell(cell.id, $(content))
> actions.set_and_run_multiple([cell.id])
> </script>
> """)
> end
> end
> 
> # ╔═╡ bcb4db15-c949-452e-8981-c56d10c8570d
> """
> replace_cell_with_show(object)
> This function will replace the content of a cell with the output of 
> ```julia
> show(io, MIME"text/html"(), object)
> ``` 
> effectively making the cell content/output static and permanent within a notebook.
> 
> !!! note
> The actual cell input might become quite long after executing this cell.
> """
> function replace_cell_with_show(object)
> io = IOBuffer()
> println(io, "html", '"', '"', '"')
> show(io, MIME"text/html"(), object)
> println(io)
> print(io, '"', '"', '"')
> update_this_cell_content(io)
> end
> 
> ````

And here is a video example of how this simple function works in action:
