1

So I am trying to create a Data Science workflow using org-mode source-blocks. Basically, I need to emulate the jupyter notebook functionality where you create a plot and it shows the figure. Now, following this link, you can do this:

#+begin_src python :results file
import matplotlib, numpy
matplotlib.use('Agg')
import matplotlib.pyplot as plt
fig=plt.figure(figsize=(4,2))
x=numpy.linspace(-15,15)
plt.plot(numpy.sin(x)/x)
fig.tight_layout()
plt.savefig('images/python-matplot-fig.png')
return 'images/python-matplot-fig.png' # return filename to org-mode
#+end_src

The problem with this is that, you have to save the figure manually and then you have to return the path to the figure (Because org is wrapping that code in a function).

That is super awkward to me, because I don't want to be saving the figure manually nor have that return statement at the end, because I want to export these org files to my blog using orig-publish, and that return statement is not valid code outside of the org source blocks code context. I then tried to do this:

#+begin_src python  :file example.png :dir images/ :results file
  import numpy as np
  import matplotlib.pyplot as plt
  import seaborn as sns

  sns.set()  # Enable Seaborn theme

  random_points = np.random.randint(0, 10, (100, 2))

  plt.scatter(random_points[:, 0], random_points[:, 1])
  plt.show()
#+end_src

#+RESULTS:
[[file:images/example.png]]

But the problem is that, it does not save any figure at the images/example.png path. What I would want to do would be that org-mode would save that figure on the path I specified in the header, and then allow me to visualize it in the results.

How could I achieve this? Thank you!

  • To display the image, you need to toggle org-display-inline-images. Have you tried :file images/example.png and skipping the :dir tag altogether? Finally, you may mean :results output. This enables 'scripting mode' – Metropolis May 24 at 15:08
  • Yes I know you have to toggle the display images. The problem is that it does not save the image. Its like a blank png. Regarding the :dir tag, I have tried using it on the current directory so that is not the problem, and I also tried switching the :results mode to output. The issue here is, how can I make org save the matplotlib images automatically. – David Marques May 24 at 15:14
  • hm, when I execute your code block, the png file is being created in the images directory (relative to the directory where the org file exists). Dumb question, but, have you created the images directory? – Metropolis May 24 at 15:17
  • Yes yes I did. Which block are you running the first or the second? And does that png contain the image or is it just blank? – David Marques May 24 at 15:19
  • Oh, ha! Yeah it is empty. I assumed it was the right image because the scatterplot popped up in a python window. That is strange. I've definitely gotten this kinda thing to work with other tools (mermaid). – Metropolis May 24 at 15:29
0

The basic problem is that plt.show() does not produce anything (other than showing the image as a side-effect and blocking), so there is nothing to save (it actually produces the None object, so that's what you get in the result):

#+begin_src python :results file
  import numpy as np
  import matplotlib.pyplot as plt

  random_points = np.random.randint(0, 10, (100, 2))

  plt.scatter(random_points[:, 0], random_points[:, 1])
  plt.show()
#+end_src

#+RESULTS:
[[file:None]]

The None that you see in the link is the return value of plt.show().

So you have to save the image:

#+begin_src python :results file :var f="images/example.png"
  import numpy as np
  import matplotlib.pyplot as plt

  random_points = np.random.randint(0, 10, (100, 2))

  plt.scatter(random_points[:, 0], random_points[:, 1])
  plt.savefig(f)
#+end_src

#+RESULTS:
[[file:None]]

That still does not work, because savefig() saves the image but still returns None. So we need to change things to return the file name:

#+begin_src python :results file :var f="images/example.png"
  import numpy as np
  import matplotlib.pyplot as plt

  random_points = np.random.randint(0, 10, (100, 2))

  plt.scatter(random_points[:, 0], random_points[:, 1])
  plt.savefig(f)
  return f
#+end_src

#+RESULTS:
[[file:images/example.png]]

Usign a :var f="..." header allows us to define it in one place and use it in the block. But I don't know how to avoid that and use :file/:dir headers instead.

| improve this answer | |
  • This does not seem to be working for me. It neither creates the figure nor outputs the path to the figure in the result block – David Marques May 24 at 18:04
  • You are right: I'm getting something wrong. Let me work on it a bit. – NickD May 24 at 18:42
  • This is still not what you want but it may help a bit. – NickD May 24 at 19:17
  • Thanks for the help! Ok I am starting to understand the problem.. So my problem with doing that is, if I publish that code on a blog, the code is a bit weird right? Maybe I will see if I can use other plotting tool that returns an image. I tried running it without the plt.show(), because the line plt.scatter(random_points[:, 0], random_points[:, 1]) actually returns something but I don't think it works as well – David Marques May 24 at 20:03
  • "The code is a bit weird ..." - in what way? I don't understand what you are saying here. Also plt.scatter returns a matplotlib.collections.PathCollection object: I have no idea what you can do with that but it's very unlikely that org-babel will be able to make heads or tails of it. – NickD May 24 at 21:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.