Skip to content

Latest commit

 

History

History
639 lines (424 loc) · 13.8 KB

scimax-jupyter.org

File metadata and controls

639 lines (424 loc) · 13.8 KB

scimax-jupyter

/Users/jkitchin/Dropbox/emacs/scimax/scimax-jupyter.png

https://github.com/nnicandro/emacs-jupyter uses a compiled module to communicate directly with a jupyter kernel using zeromq. This requires that you have an emacs with support for compiled modules, and that you are able to compile it. This is the default option in scimax. The older ob-ipython modules might work, but I don’t use or support them anymore.

(require 'scimax-jupyter)

Customization in scimax

Overall, emacs-jupyter is an improvement on ob-ipython. There are a few things I want that don’t come out of the box with emacs-jupyter. Here are a few customizations I have done in scimax.

default header args

These are the settings that work well for me.

org-babel-default-header-args:jupyter-python

Some of these are scimax-specific. For example :results . "both" captures both printed and returned values, which is most consistent with Jupyter notebooks. I set :pandoc . "t" to convert outputs like html to org format where possible.

buffer specific kernels that close when you kill the buffer

I find it confusing to have one kernel shared among many files.

  1. It is easy to mess up the state if you use similar variables in different files
  2. I often assume the CWD is the file I work from, but the kernel starts in the directory it was started in, which is often different than another org-file
  3. I want the kernel to shutdown and close when I close the buffer because I don’t need it after that.

scimax makes that happen.

scimax jupyter src-block hydra

Try it: elisp:scimax-jupyter-org-hydra/body

Easy access to:

  • inspect (M-i)
  • completion (M-tab)
  • editing functions
  • kernel management

Examples of usage

Getting help

import numpy as np

?np.linspace

np.linspace
??np.linspace

If you have your cursor on linspace, type M-i or f12-/ to inspect it.

np.linspace

Completion

Use M-tab to complete the thing at point. Sometimes you have to type it more than once.

np.geomspace

Plotting with matplotlib

Figures work like you expect.

import matplotlib.pyplot as plt
import numpy as np

t = np.linspace(0, 20 * np.pi, 350)
x = np.exp(-0.1 * t) * np.sin(t)
y = np.exp(-0.1 * t) * np.cos(t)

plt.plot(x, y)
plt.axis('equal')

plt.figure()
plt.plot(y, x)

plt.axis('equal')

print('Length of t = {}'.format(len(t)))
print('x .dot. y = {}'.format(x @ y))

pycse and plotly

Emacs still does not natively render html or interactive javascript. Until that happens, I monkey-patched plotly to capture a static image, and save the interactive html so you can still use it in a browser. This isn’t purely scimax, it requires you to pip install pycse, which is a Python package I wrote to do things like this.

from pycse.plotly import *

import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species",
                 size='petal_length', hover_data=['petal_width'])
fig.show()

pandas

using the pandoc: "t" header generally makes pandas behave well with org-mode. Turn that off if you want with an empty header like :pandoc; note you will get html output then.

import pandas as pd

f = pd.DataFrame([['a', 'b'], [1, 2]])
f
01
0ab
112

Figures and Tables with captions, names, attributes with pycse

pycse.orgmode defines several helpful classes to make org figures and tables with attributes.

from pycse.orgmode import *

Table([['x', 'y'],
       [1, 2],
       [3, 4]],
      headers='firstrow',
      name='org-data',
      caption='The information about the table',
      attributes=[('latex', ':environment longtable :align |l||l|')])
xy
12
34

See Table ref:org-data.

import matplotlib.pyplot as plt

f = './test.png'
plt.plot([1, 4, 17])
plt.savefig(f)
plt.close() # you need this to not see two figures.
Figure(f, name='org-fig', caption='a line plot',
       attributes=[('org', ':width 300'),
                   ('latex', ':placement [H]')])

ref:org-fig

import matplotlib.pyplot as plt
import numpy as np

t = np.linspace(0, 20 * np.pi, 350)
x = np.exp(-0.1 * t) * np.sin(t)
y = np.exp(-0.1 * t) * np.cos(t)

plt.plot(x, y)
plt.axis('equal')
plt.savefig('fig-1.png')
plt.close()

plt.figure()
plt.plot(y, x)
plt.axis('equal')
plt.savefig('fig-2.png')
plt.close()

print('Length of t = {}'.format(len(t)))
print('x .dot. y = {}'.format(x @ y))

from pycse.orgmode import Figure, Org

from IPython.display import display

display(Org("\n\n"),
        Figure('./fig-1.png', name='clock',
               caption='a clockwise line plot'),
        Org("\n\n"),
        Figure('./fig-2.png', name='counterclock',
               caption='a counter-clockwise line plot'))

./fig-1.png

./fig-2.png

import pandas as pd

Table(pd.DataFrame([['a', 'b'],
                    [1, 2],
                    [5, 6]]),
      headers='firstrow',
      name='pd-data',
      caption='A table from a dataframe')
0ab
112
256

There is also a keyword.

Keyword('name', 'fig-1')    

and a comment.

Heading('An example of a heading from code', 3)
Comment('A comment for orgmode')

Exceptions

Exceptions go in the results. Type f12 e to jump to the exception in the src block.

print(5)


a = 5




for j in range(5):
    1 / 0



print(54)

print(z)

Select rich outputs with :display

The priority for display is:

  • text/org
  • image/svg+xml, image/jpeg, image/png
  • text/html
  • text/markdown
  • text/latex
  • text/plain

LaTeX is automatically rendered to a png

from sympy import *
init_printing()
x, y, z = symbols('x y z')

Integral(sqrt(1 / x), x)

To get the actual LaTeX, use the :display

from sympy import *
init_printing()
x, y, z = symbols('x y z')

Integral(sqrt(1 / x), x)

and to get it in plain text:

from sympy import *
init_printing()
x, y, z = symbols('x y z')

Integral(sqrt(1 / x), x)

Rich displays mostly work

These get converted to org-syntax by pandoc I think. Note that emacs-jupyter and/or pandoc seems to put some \ in the converted results. I use the function scimax-rm-backslashes in a hook to remove these.

from IPython.display import FileLink, Image, display

FileLink('scimax.png')
Image('test.png')
display(FileLink('scimax.png'), Image('test.png'))

Some of these are already orgified, e.g. YouTubeVideo.

from IPython.display import YouTubeVideo

YouTubeVideo('ZXSaLcFSOsU')

scratch space and the REPL

The buffer is a great scratch space, but there is also a separate Jupyter scratch buffer. Use it to try out ideas, check values, etc.

Each kernel has a REPL associated with it. Type C-c C-v C-z or f12-z to get to it. It is like an IPython shell! You can explore things there, make plots, etc…

REPL like interaction mode in src blocks

print(3) 
3 + 4  # highlight region, C-M-x to run it.

a = 5  # Run C-x C-e here
5 + a  # Then, M-i here to inspect a

debugging with the REPL

Put a breakpoint in a function. Define it, then go to the REPL (f12 z) to step through it.

def f(x):
    breakpoint()
    return 1 / x

learn more about PDB at https://realpython.com/python-debugging-pdb/#getting-started-printing-a-variables-value.

Export to ipynb

See ox-ipynb. This org-file is not ideal for this export, it has some links that are not supported, and I marked the Known issues section as noexport because it has src-blocks with variables in it.

#+ox-ipynb-language: jupyter-python

(setq  org-export-with-broken-links t)
(ox-ipynb-export-to-ipynb-file-and-open)

Other languages

Julia seems to work

./scimax-jupyter-julia.org

R

./scimax-jupyter-r.org

Known issues

widgets do not seem to work

In theory emacs-jupyter supports widgets, if you build it in the emacs-jupyter src directory. I did that, and don’t see any obvious issues, but this does not work. I am not likely to spend time fixing this anytime soon.

(let ((default-directory (file-name-directory (locate-library "jupyter"))))
  (shell-command-to-string "make widgets"))

This at least outputs something, but I think it should open a browser.

import ipywidgets as widgets

w = widgets.VBox([widgets.Text('#+attr_org: :width 300'),
                  widgets.Text('#+name: fig-data'),
                  widgets.Text('#+caption: something here.')])
display(w)

I am not sure why. I don’t think it is related to my changes. See emacs-jupyter/jupyter#333, I am not sure widgets still work.

This just hangs, and does not do anything.

widgets.Image(value=open("test.png", "rb").read(),  width=400)

Tricky using :cache

This sequence of cells leads to an error when you run them the first time. The issue is the first cell doesn’t use jupyter, it uses a cached result, so when you get to a * 4 the variable is not defined.

a = 15
print(a)

import time
time.sleep(5)

#+RESULTS[890bb80ec5ce30e9fa7f63b50d7df113702c43c5]: one

15
data
a * 4

Wishlist

handle long outputs

Sometimes you get long outputs from things, and especially when it is something that needs fontification, this makes Emacs hard to use. I would like to have a way to truncate long outputs, and maybe write them to a file where you could look at them.

Jump to definition of variable or function

It would be awesome to do this. Probably this could build on ./scimax-literate-programming.el and ./scimax-ob-flycheck.el.

inspect variables in function calls

This does not always work when variables are inside a call. I usually see help for the function then.

a = 5
print(a + 5)  # inspect a here, I usually see print documentation