2

I have a number of png images that get updated somewhat regularly and want to include them in an IPython notebook, having them automatically updated in the notebook.

I thought I could do it by adapting the following matplotlib example:

import numpy as np
import matplotlib.pyplot as plt
from IPython import display
import time

%matplotlib inline

plt.ion()

fig = plt.figure()
ax = fig.gca()
fig.show()

for i in range(10):
    mu, sigma = 200, 25
    x = mu + sigma*np.random.normal(loc=2, scale=1, size=50)

    if i == 0:
        barpl = plt.bar(range(len(x)), x)
    else:
        for rect, h in zip(barpl, x):
            rect.set_height(h)
    display.clear_output(wait=True)
    display.display(plt.gcf())
    time.sleep(2)

So I used this snippet:

from IPython import display
import os

timestamp = get_latest_file_ts(directory="figures", file_name="fig1.png", strip_directory=True)

display.Image(os.path.join("figures", "fig1.png"))

while True:
    timestamp = check_if_modified_file(directory="figures", file_name="fig1.png", touched_on=timestamp, sleep_time=1, strip_directory=True)
    display.clear_output(wait=True)
    display.Image(os.path.join("figures", "fig1.png"))

But no output is produced. Apparently statements that follow Image() override the display (and I am unsure this was supposed to work even without this happening). In the above code, get_latest_file_ts() fetches the timestamp of the latest version of the image, and check_if_modified_file() keeps checking for a newer timestamp on the same file, and returns the newer timestamp when it finds it.

[UPDATE] I found a partial way to do this using widgets, but my implementation creates a new HTML block at the end of the old one. What I want instead, is to replace the old HTML block with the new one -i.e. replace the content only.

Here is the code that stacks one HTML behind the other:

from IPython.html.widgets import interact, interactive, fixed
from IPython.html import widgets
from IPython.display import clear_output, display, HTML

def show_figs(directory="figures", file_name="fig1.png"):
    s = """<figure>\n\t<img src="%s" alt="The figure" width="304" height="228">\n</figure>""" % os.path.join(directory, file_name)
    display(HTML(s))

timestamp = get_latest_file_ts(directory="figures", file_name="fig1.png", strip_directory=True)
show_figs()
while True:
    timestamp = check_if_modified_file(directory="figures", file_name="fig1.png", touched_on=timestamp, sleep_time=1, strip_directory=True)
    show_figs()

I would really appreciate a way to get the second or third snippets above to work, or some other method to get this done.

Cœur
  • 37,241
  • 25
  • 195
  • 267
nikosd
  • 919
  • 3
  • 16
  • 26

1 Answers1

3

The problem with your first attempt is that you just create the image object (display.Image) but not display it! To display the image, use the display.display function which is similar to python's print statement but uses the IPython display machinery. Your call should look like

display.display(display.Image(os.path.join("figures", "fig1.png")))

Some background

If you just create the image object, the returned object is displayed only if it is the last command in the execution block -> the image object is the "OUT" value. Note, that it is placed next to the Out[x] prompt. In this particular case, the display machinery automatically displays it.

In your case you create the image within a loop without capturing it. It is not the last command in the execution block, thus the image object is not returned as "out" value and not displayed automatically. Latter has to be manually done.

This is totally the same with any python object. If you want to see it you have to print (display) it or (in IPython) make sure it is return as "OUT".

Jakob
  • 19,815
  • 6
  • 75
  • 94
  • What does he mean by `return as "OUT"`? – John Mee Mar 14 '17 at 00:42
  • As IPython (jupyter) behaves like an ordinary python console and displays the returned value from the last statement, i.e. if you enter 1+1 you get the result as returned value directly returned and displayed. In Jupyter the respective output is placed in an OUT block indicated by OUT[xx]. That's what he (I) called "returned as OUT". – Jakob Mar 14 '17 at 08:38
  • Thx. You meant the result is rendered into in the next cell with the prompt/label "OUT" and a number. For a moment there I, mistakenly, thought you might be talking about setting, or returning, a variable named "OUT" containing the something to be displayed. – John Mee Mar 14 '17 at 22:29