# Programming with rich text (Jupyter notebooks or similar?) on remote servers

**URL:** <https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249>\
**Category:** Tooling\
**Tags:** vscode, scripting, notebooks\
**Created:** [September 10, 2024, 12:43pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249 "2024-09-10T12:43:34Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![albertomercurio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albertomercurio/32/27051_2.png) [@albertomercurio](https://discourse.julialang.org/u/albertomercurio)\
**Post date:** [September 10, 2024, 12:43pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/1 "2024-09-10T12:43:35Z")

</div>

Hello,

I have been programming in Julia since 2020. I first used JupyterLab with IJulia.jl, and now I’m working with VSCode, still with IJulia.jl.

In this last case, I actually don’t like programming using the Julia extension and a pure Julia script, since I can’t write markdown text or equations, and I can’t keep the plots visible, even if I close and reopen it after months. Indeed, I usually code using Jupyter Notebooks.

I’m fine with that, but what I don’t like it that I have to install a python environment for that. I usually need to keep the simulation working on my remote machine while I turn off the ssh connection with VSCode. To do that, I need to start a manual Jupyter kernel under a `tmux` virtual terminal.

I was wondering if there exists a clever way to do that. I need something which is readable (a Julia script is not the case), which eventually keeps the plots displayed, which can remain in execution even if I disconnect to the remote server, and that eventually doesn’t require to installation of other packages like python. It is better if this can be run on VSCode, to take advantage of GitHub Copilot.

So, are there better options than Jupyter Notebooks?

---

<div class="post-metadata">

**Author:** ![Tortar](https://avatars.discourse-cdn.com/v4/letter/t/6bbea6/32.png) [@Tortar](https://discourse.julialang.org/u/Tortar)\
**Post date:** [September 10, 2024, 12:45pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/2 "2024-09-10T12:45:42Z")

</div>

what about

> [@\[ANN\] Native Julia engine for quarto using QuartoNotebookRunner.jl](https://discourse.julialang.org/t/ann-native-julia-engine-for-quarto-using-quartonotebookrunner-jl/112753):
>
> The dev team at [PumasAI](https://pumasai.com/) is excited to announce that, after months of work, the quarto project has accepted [PR #8645](https://github.com/quarto-dev/quarto-cli/pull/8645) which adds a new, native Julia engine based on PumasAI’s [QuartoNotebookRunner.jl](https://github.com/PumasAI/QuartoNotebookRunner.jl/) package. The engine is now available in prereleases [Release v1.5.29 · quarto-dev/quarto-cli · GitHub](https://github.com/quarto-dev/quarto-cli/releases/tag/v1.5.29) until the release of quarto’s next minor version 1.5. [Quarto](https://quarto.org/) is the successor to RMarkdown, and a widely used document authoring and publishing system based on Pandoc. So far, Julia has been supporte…

---

<div class="post-metadata">

**Author:** ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)\
**Post date:** [September 10, 2024, 12:54pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/3 "2024-09-10T12:54:58Z")

</div>

Have you tried [Pluto.jl](https://plutojl.org/)? It is basically Jupyter but you don’t need a python environment. There is a big difference: in Jupyter, you run cells manually, whereas in Pluto the cells update automatically (changing one cell causes all dependent cells to recompute).

---

<div class="post-metadata">

**Author:** ![albertomercurio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albertomercurio/32/27051_2.png) [@albertomercurio](https://discourse.julialang.org/u/albertomercurio)\
**Post date:** [September 10, 2024, 12:58pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/4 "2024-09-10T12:58:58Z")

</div>

Yes I tried it a few times, but I have found any extension for VSCode. I really like VSCode, the way I can easily connect to remote servers, its git handling and its Copilot.

---

<div class="post-metadata">

**Author:** ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)\
**Post date:** [September 10, 2024, 1:37pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/5 "2024-09-10T13:37:53Z")

</div>

Pluto notebooks are valid Julia files, so technically, you could open the same notebook in Pluto and VSCode at the same time, use Pluto for basic development, and VSCode for [Copilot](https://github.com/fonsp/Pluto.jl/discussions/2408) and Git.

But I can see how inconvenient that could be. If VSCode is a hard requirement, then perhaps Pluto is not the right choice for you.

---

<div class="post-metadata">

**Author:** ![xgdgsc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xgdgsc/32/608_2.png) [@xgdgsc](https://discourse.julialang.org/u/xgdgsc)\
**Post date:** [September 10, 2024, 1:53pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/6 "2024-09-10T13:53:15Z")

</div>

I’ ve implemented inline results and plot saving at [Feat/persist inline results by xgdgsc · Pull Request #3123 · julia-vscode/julia-vscode (github.com)](https://github.com/julia-vscode/julia-vscode/pull/3123) . But the extension devs weren’ t interested. It works with remote reconnections across client devices.

You can try [Release A quick dot methods completion demo · xgdgsc/julia-vscode (github.com)](https://github.com/xgdgsc/julia-vscode/releases/tag/v1.41.1_methodswith) . Should still work with 1.10. Last time I tried merging latest master from upstream to my branch and had many issues that I don’ t have time to fix. So it’ s based on a branch that’ s old.

And it also doesn’ t have markdown equation support.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [September 10, 2024, 2:10pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/7 "2024-09-10T14:10:48Z")

</div>

> [@albertomercurio](#):
>
> I’m fine with that, but what I don’t like it that I have to install a python environment for that.

You don’t. You can use the lightweight package NBInclude.jl to load a Jupyter notebook into a Julia script just as you would for `include`, no Python required.

(You can even use Jupyter notebooks as part of a Julia package/module in this way.)

---

<div class="post-metadata">

**Author:** ![albertomercurio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albertomercurio/32/27051_2.png) [@albertomercurio](https://discourse.julialang.org/u/albertomercurio)\
**Post date:** [September 10, 2024, 2:54pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/8 "2024-09-10T14:54:10Z")

</div>

But NBInclude is just for including notebook inside a Julia script. But it seems a bit strange, that I have first to write a Jupyter notebook, but then I run it inside a Julia script.

---

<div class="post-metadata">

**Author:** ![albertomercurio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albertomercurio/32/27051_2.png) [@albertomercurio](https://discourse.julialang.org/u/albertomercurio)\
**Post date:** [September 10, 2024, 2:56pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/9 "2024-09-10T14:56:08Z")

</div>

This seems like the `jmd` files where you mix markdown and Julia, right? But you have to render it, right?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [September 10, 2024, 2:57pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/10 "2024-09-10T14:57:42Z")

</div>

> [@albertomercurio](#):
>
> But NBInclude is just for including notebook inside a Julia script. But it seems a bit strange, that I have first to write a Jupyter notebook, but then I run it inside a Julia script.

You could run `julia -e "using NBInclude; @nbinclude(\"my-script.ipynb\")"`.

Or write a 2-line wrapper shell script `juliaipynb my-script.ipynb` that does this for you.

(You could also use NBInclude to export the `.ipynb` file to a julia `.jl` file.)

The point is that NBInclude.jl takes care of the job of executing notebook files without requiring Python, but it is still up to you to invoke it somehow. The `julia` executable by itself doesn’t know about this package.

---

<div class="post-metadata">

**Author:** ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)\
**Post date:** [September 10, 2024, 5:12pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/11 "2024-09-10T17:12:34Z")

</div>

Is your issue basically this?

> <https://github.com/microsoft/vscode-remote-release/issues/3096>
>
> A lot of users of our \[Julia extension\](https://marketplace.visualstudio.com/ite…ms?itemName=julialang.language-julia) love the remote SSH features, they are super useful in a scientific research computing context!
> 
> One thing that has come up a lot lately, though, is that folks want an ability to have a persistent session on a server that they can disconnect from and then reconnect to way later.
> 
> The scenario is essentially something like this:
> 1. User connects to some remote server via the Remote SSH extension
> 2. They do some work
> 3. They get interrupted and close their local VS Code instance
> 4. They do something else for a couple of days
> 5. The now want to reconnect to the server, and ideally \_nothing\_ was shut down on the server. For example, if they opened a REPL in step 2 and started a Julia instance in that REPL, it would still be running, and was never shut down. Similarly with pretty much all other runtime state they had.
> 
> I think this might be related to https://github.com/microsoft/vscode-remote-release/issues/440, but what I'm really asking for is not just an option to change the timeout, but some way to make the timeout infinit, so that the server session never shuts down.
> 
> This might also require some kind of UI, maybe a command like "Disconnect but keep server alive" or something like that, not sure.

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [September 10, 2024, 10:21pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/12 "2024-09-10T22:21:35Z")

</div>

This doesn’t completely address all your issues, but I can tell you what I use as a workflow.

First, I think it is important to think of Jupyter as an _application_. It should never be part of your project environments: [A _kernel_ might be](https://github.com/goerz/python-localvenv-kernel), but Jupyter itself is just some program (that happens to be implemented in Python) that you need to install somewhere on your system. Personally, I use a dedicated [Miniforge](https://github.com/conda-forge/miniforge) environment. People get confused by stuff like the [IJulia instructions](https://github.com/JuliaLang/IJulia.jl) to run `notebook()` in your Julia REPL. That might be good if you have a class to teach and you just need things to run, but it just creates a lot of confusion.

So, make sure you have Jupyter installed (on your remote workstation), with all the plugins you like. Then also install `IJulia` into your main Julia environment (not your project environments; luckily, Julia is better than Python in that respect). One plugin that’s absolutely essential (and that should be installed alongside Jupyter itself) is [Jupytext](https://jupytext.readthedocs.io/en/latest/). This allows you to link your `.ipynb` files to `.md` or `.jl` files that get synchronized automatically.

Now what I’ll do is connect to my remote workstation via ssh (with X-forwarding) and run `tmux`. I’ll open the `.jl` version of the notebook in `neovim` and a Julia REPL side-by side in two tmux windows. I’ll then use [vim-slime](https://github.com/jpalardy/vim-slime) to send code from the editor to the REPL. This is great for experimentation and to build up a notebook.

I’ll also have a Jupyter Lab server running on the remote workstation where I view the `.ipynb` version of the notebooks. I can access that server through SSH with port forwarding. As I said, `Jupytext` will make sure that these are synchronized (but you might have to do “reload from disk” sometimes). Once I finish experimenting, I’ll re-run the entire notebook (the `.ipynb` version) in Jupyter and save it. I might also work in the notebooks directly for smaller fixes, or if I’m comparing plots, or stuff like that. Those notebooks stay on disk, as something that I can show my boss if he drops in. I’ve also used [Quarto](https://quarto.org) to generate “reports” in PDF format from time to time.

So, basically, work in your editor and the REPL via ssh/tmux, and the `.ipynb` files automatically get saved as a permanent record of that work.

I’ll commit only the `.md`/`.jl` versions of the notebooks, not the `.ipynb` version, since they’re much more amenable to version control (the original motivation of `juypytext`!). The `.ipynb` version can also easily be recreated. Nowadays, I usually write myself a `Makefile` that regenerates any missing `.ipynb` files from a clean checkout.

The resulting repo might look [something like this](https://github.com/ARLQCI/2022-11_rotating_tai) (this is research code, not really meant for public consumption). When a project ends, I’ll zip up the entire folder including all the `.ipynb` files with all the plots in them, for archival in addition to the git.

---

<div class="post-metadata">

**Author:** ![RoyiAvital](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/royiavital/32/571_2.png) [@RoyiAvital](https://discourse.julialang.org/u/RoyiAvital)\
**Post date:** [September 11, 2024, 5:57pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/13 "2024-09-11T17:57:51Z")

</div>

You may find [VS Code Interactive Window](https://code.visualstudio.com/docs/python/jupyter-support-py) the perfect tool for your needs.

You may support adding Julia as a featured language in:

- [Multi Language Support in Interactive Window (Julia, Rust, CSharp, etc)](https://github.com/microsoft/vscode-jupyter/issues/273).
- [Execute Code Cell: Add Codelens](https://github.com/julia-vscode/julia-vscode/issues/858).
- [Feature Request: Jupyter/IPython (IJulia) interactive REPL console instead of Julia REPL console](https://github.com/julia-vscode/julia-vscode/issues/2713).

I appreciate the pragmatic mainstream aimed design of the Julia eco system.  
Hence I think it makes sense to support the [JupytText format](https://jupytext.readthedocs.io) (Which is what Interactive Window implements).  
I hope it will be added to Julia VS Code extension.

I find it the best format for literature programming as it gives all the capabilities of Jupyter in a version control friendly format.

---

<div class="post-metadata">

**Author:** ![albertomercurio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albertomercurio/32/27051_2.png) [@albertomercurio](https://discourse.julialang.org/u/albertomercurio)\
**Post date:** [September 24, 2024, 8:19pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/14 "2024-09-24T20:19:28Z")

</div>

Thanks. Although I will mainly use VSCode instead of Neovim, the idea of working with .jl files and then automatically converting them into jupyter notebooks seems a good workaround.

I think that Julia lacks such a feature. I mean, Julia is built for numerical simulations and plots. It is supposed to have a native framework that allows you to do it seamlessly.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [September 24, 2024, 9:35pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/15 "2024-09-24T21:35:00Z")

</div>

> [@albertomercurio](#):
>
> I think that Julia lacks such a feature. I mean, Julia is built for numerical simulations and plots. It is supposed to have a native framework that allows you to do it seamlessly.

You want Julia to implement something like Jupyter notebook support in the base language? That seems inflexible to me.

I don’t understand why it is a problem to use a package like NBInclude, which you can execute from the command-line as I noted above.

(Julia doesn’t include plotting in the core language either. Neither does Python. And I’m glad it didn’t, because that allows plotting packages to evolve and diversify at a pace that the language cannot.)

---

<div class="post-metadata">

**Author:** ![albertomercurio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albertomercurio/32/27051_2.png) [@albertomercurio](https://discourse.julialang.org/u/albertomercurio)\
**Post date:** [September 24, 2024, 11:04pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/16 "2024-09-24T23:04:53Z")

</div>

Sorry, but I don’t get why NBInclude should be my option.

I still need to program using a framework that allows me to make the document commendable (latex and markdown) and readable like the jupyter notebook does. As far as I understood, NBInclude just imports the jupyter notebook code, but then I still program using a Julia file, which is not very readable and commendable.

How do you program using NBInclude? Do you first write the Jupyter Notebook, and then you include it inside a Julia file, and then you run functions in the Julia file? I don’t get it sorry.

BTW, I was wondering if the .jmd format would be an option for me. The Julia extension of VSCode supports it, and I can basically write a markdown file with the Julia code inside the code blocks. I still don’t understand if it is possible to render in live view (I change the code and the rendered output changes). Do you recommend it?

@Tortar mentioned Quarto, it seems very similar to the .jmd file extension. What is the difference?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [September 25, 2024, 1:47am UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/17 "2024-09-25T01:47:35Z")

</div>

> [@albertomercurio](#):
>
> As far as I understood, NBInclude just imports the jupyter notebook code, but then I still program using a Julia file, which is not very readable and commendable.

No, you can program entirely using Jupyter notebook files if that is what you want: they just become your source file. You don’t need to create any `.jl` file as I explained above: you can execute your notebook directly from the command line.

That is:

1. Create/edit a `my-script.ipynb` notebook file using whatever Jupyter-compatible program that you like (Jupyter, JupyterLab, VSCode, …). This contains all your code, and whatever additional rich text you want.
2. When you want to run it outside of the notebook environment, e.g. on a remote server, just do `julia -e 'using NBInclude; @nbinclude("my-script.ipynb")'` — no Python or Jupyter installation required.

The only time you would _need_ a `.jl` file would be if you want to make a Julia package out of your code, and even then you only need a 4-line `Foo.jl` file

```julia
module Foo
using NBInclude
@nbinclude("foo.ipynb")
end

```

and the rest of your code can be in Jupyter notebooks if that is what you want.

---

<div class="post-metadata">

**Author:** ![albertomercurio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albertomercurio/32/27051_2.png) [@albertomercurio](https://discourse.julialang.org/u/albertomercurio)\
**Post date:** [September 25, 2024, 7:32am UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/18 "2024-09-25T07:32:04Z")

</div>

But ten you loose the concept of interactive coding, with cells to run etc, right?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [September 25, 2024, 11:42am UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/19 "2024-09-25T11:42:51Z")

</div>

No, you can code interactively in the notebook environment as normal. But you can also save the notebook and run it non-interactively with NBInclude, without having to convert back and forth between `.jl` files and notebooks.

---

<div class="post-metadata">

**Author:** ![albertomercurio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albertomercurio/32/27051_2.png) [@albertomercurio](https://discourse.julialang.org/u/albertomercurio)\
**Post date:** [September 25, 2024, 12:16pm UTC](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249/20 "2024-09-25T12:16:51Z")

</div>

Ok, I see. But then I still keep coding with Jupyter notebooks, which is what I’m already doing. Good to know that I can simply include it using this package.

[Next page](https://discourse.julialang.org/t/programming-with-rich-text-jupyter-notebooks-or-similar-on-remote-servers/119249.md?page=2)
