Python vs. R in org-mode babel output graphics

Question:

I am trying to write up a report in org-mode.
Read data from a csv file (single column three rows, floating numbers), compare in a bar chart, have the chart embedded in the report so that it can be exported to latex and then to pdf.

I am having difficulty understanding as in what I am doing in bar creation part of the python code because R_plot works fine, meaning chart is embedded into the report under the same org-mode :export :results :file setting.

What am I doing wrong with the python code? If I run the python code on interactive mode, it produces the chart with no trouble but for some reason py_comparison.png isn’t saved when I run by cell-block.

#+NAME: R_plot
#+BEGIN_SRC R :exports both :results output graphics :file r_comparison.png
# graph in R
library("ggplot2")
performance <- read.csv("comparison.csv", header=FALSE)$V1
df <- data.frame(resource = c("1node1core", "1node8core", "2node8core"), performance = performance)
p <- ggplot(data = df, aes(x=resource, y=performance)) +
     geom_bar(stat="identity", fill="steelblue") + 
     theme_minimal() +
     ggtitle("Computation time (min) vs. Resource (type)")
p
#+END_SRC

#+NAME: python_plot
#+BEGIN_SRC python :exports both :results output graphics :file py_comparison.png
import matplotlib.pyplot as plt; plt.rcdefaults()
import matplotlib.pyplot as plt
import csv

objects = ['1node1core', '1node8core', '2node8core']
y_pos = list(range(0, len(objects)))

performance = []
with open('comparison.csv', newline='') as csvfile:
  reader = csv.reader(csvfile)
  for row in reader:
    f_row = float(row[0])
    performance.append(f_row)

plt.bar(y_pos, performance, align='center', alpha=0.5)
plt.xticks(y_pos, objects)
plt.ylabel('Time')
plt.title('Resource vs. Time')

plt.show()
#+END_SRC

+END_SRC

Asked By: Young Ha Kim

||

Answers:

I believe your header value for python code block is wrong. There is a difference between :results <file name> file and :file <file name>. According to the documentation (redacted for clarity):

:results file

There are four classes of :results header arguments. Each ‘src’ code
block can take only one option per class. […]

Collection […]

  • value Default. Functional mode. Result is the value returned by the last statement in the ‘src’ code block. Languages like Python may
    require an explicit return statement in the ‘src’ code block. Usage
    example: :results value.

Type […]

  • file Interpret as path to a file. Inserts a link to the file. Usage example: :results value file.

:file <file name>

An external :file that saves the results of execution of the code
block. […] Some languages, such as ‘R’, ‘dot’, ‘ditaa’, and ‘gnuplot’,
automatically wrap the source code in additional boilerplate code.
Such code wrapping helps recreate the output, especially graphics
output, by executing just the :file contents.

In python the result of plt.show() (or savefig for that matter) is None, the image is only a side effect, so nothing gets inserted. In R it works because of the boilerplate wrapper mentioned above

So in python you need to save and return your image instead of showing it. Something like this should work:

#+NAME: python_plot
#+BEGIN_SRC python :results img.png file

import matplotlib.pyplot as plt
plt.plot(range(5))
plt.savefig('img.png')
return 'img.png'

#+END_SRC
Answered By: jjj

to save the plot (if you want to save it in some other directory, you can do so) and show it in the results as well …

#+begin_src python :results output file :file img.png :output-dir img/ :exports both
import sys
import matplotlib.pyplot as plt
plt.plot(range(5))
plt.savefig(sys.stdout.buffer

#+end_src

enter image description here

Answered By: Arun Kumar Khattri