简体   繁体   中英

Can I show a plot created in another file on JupyterLab?

I wish to have an interactive map that you can click where, once clicked, a SkewT and Hodograph will be plotted showing the information for that location. I have thus created a class where I add all the necessary informations using the metpy library and I am able to successfully create these graphs:

SkewT and Hodograph plotted
绘制 SkewT 和 Hodograph

The problem comes when I'm trying to import the classes I've created to generate these plots into jupyterlab. Since the code to actually make these plots is quite cumbersome, I'd rather keep the code in a separate file and import my SoundingGraphs class, but it's not working. The graphs never get plotted inside a cell, they instead appear in the logs as a Warning and as an Info and I have no idea why:

Graphs appearing inside logs
出现在日志中的图表

Tried to use plt.show() inside my file, tried returning plt to then use plt.show() inside a cell of the notebook, tried using %matplotlib widget , %matplotlib notebook and %matplotlib inline , tried changing jupyterlab versions, none of these changed anything.

I have found one solution that I disliked, but that does work, which is rather than doing a plt.show() , to instead do this inside my class:

buffer = BytesIO()
plt.savefig(buffer, format='png')
return buffer

And in the notebook I would do:

image = Image()
display(image)

def on_generate_button_clicked(b):
    buffer = SoundingGraphs(infos)
    buffer.seek(0)
    image.value=buffer.read()
    image.format='png'

generate_button.on_click(on_generate_button_clicked)

I don't quite like this approach because further down the line I would like to add interactivity to my plots, like show values of plot when hovered and things like that, thus I don't just want to show an image. So I'd like to know if it is indeed possible to plt.show() a plot created inside another file in a cell.

Using:

Python 3.6.9
jupyterlab==3.2.9
jupyterlab-pygments==0.1.2
jupyterlab-server==2.10.3
jupyterlab-widgets==1.1.0
ipykernel==5.5.6
ipyleaflet==0.14.0
ipympl==0.8.8
ipython==7.16.3
ipython-genutils==0.2.0
ipywidgets==7.7.0
matplotlib==3.3.4

Thanks!

Yes, it is possible after all!

%matplotlib widget needs to be used at the start of the notebook and since the class method will be called from another function (on a button.on_click event), it is possible to use the @out.capture() decorator above it so that the plt.show() gets displayed. It's also possible to make the figure a class attribute to be able to have more control.

So here's a bit of working code if someone would like to replicate:

Notebook

%matplotlib widget
from ipywidgets import Button, Output
from myfile import MyClass

out = Output()

example_button = Button(
    description='Example',
    disabled=False,
    button_style='',
    tooltip='Click me'
)

@out.capture()
def on_example_button_clicked(b):
    example_button.disabled = True
    myclass = MyClass()
    myclass.create_plot()
    out.clear_output(wait=True)
    display(myclass.fig.canvas)
    example_button.disabled = False

example_button.on_click(on_example_button_clicked)

display(example_button)
display(out)

myfile.py

import matplotlib.pyplot as plt

class MyClass():
    def __init__(self):
        plt.ioff()  # otherwise it'll also show inside logs
        plt.clf()
        self.fig = plt.figure()

    def create_plot(self):
        plt.plot([1, 2, 3, 4])
        plt.ylabel('some numbers')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM