Skip to content

Using raw.plot in JupyterLab or Colab #8080

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
gurasog opened this issue Aug 3, 2020 · 11 comments
Closed

Using raw.plot in JupyterLab or Colab #8080

gurasog opened this issue Aug 3, 2020 · 11 comments
Milestone

Comments

@gurasog
Copy link

gurasog commented Aug 3, 2020

Is there any recommendation how to use MNE plot() functions such as raw.plot() in JupyterLab and Google Colab?

When i run these functions they aren't interactive. None of %matplotlib %matplotlib qt works in these environment...

So, is there any way to use these graphs interactively in these tools?

Thanks!

@larsoner
Copy link
Member

larsoner commented Aug 3, 2020

What do you get for mne.sys_info() or mne sys_info on those platforms? Maybe xvfb+Qt5Agg backend would work

@drammock
Copy link
Member

drammock commented Aug 3, 2020

I am able to get interactive raw.plot() windows using %matplotlib qt or %matplotlib qt5 in JupyterLab (it pops open a separate window, not an inline figure).

Google Colab is "not officially supported" at the moment, though mainly because of problems with 3D visualization. For 2D visualization it is expected to work the same as Jupyter Notebooks. I tried to get Colab 3D viz working in June, and kept hitting segfaults (there is some discussion of this on the Gitter channel, search for "colab").

@larsoner
Copy link
Member

Closing since it seems like it works at least in JupyterLab but let's reopen if it doesn't actually

@larsoner
Copy link
Member

larsoner commented Sep 2, 2021

@drammock @agramfort @GuillaumeFavelier do one of you want to try what they suggest doing for custom widgets in colab as of a couple of days ago?

googlecolab/colabtools#498 (comment)

I have never used Colab but if it's easy to tell people how to make our IPython widgets work we should do it...

@larsoner larsoner added this to the 0.24 milestone Sep 2, 2021
@larsoner larsoner reopened this Sep 2, 2021
@GuillaumeFavelier
Copy link
Contributor

I can give a try tomorrow. In any case, I'll update #8704 with this. Thanks for the update!

@GuillaumeFavelier
Copy link
Contributor

GuillaumeFavelier commented Sep 3, 2021

I managed to reproduce the minimal example using ipympl :

image

!pip install -q ipympl
%matplotlib widget
from IPython.display import Javascript
import matplotlib.pyplot as plt
import numpy as np

# This enables custom widgets in the current cell's output.
# Currently this must be included in each cell using custom widgets but this
# should be a temporary restriction.
display(Javascript('''
  google.colab.widgets.installCustomManager('http://127.0.0.1:9897/manager.dev.js');
'''))

from mpl_toolkits.mplot3d import axes3d

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# Grab some test data.
X, Y, Z = axes3d.get_test_data(0.05)

# Plot a basic wireframe.
ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)

plt.show()

but not the one using ipycanvas (clock.ipynb):

!pip install ipycanvas
from IPython.display import Javascript

display(Javascript('''
  google.colab.widgets.installCustomManager('http://127.0.0.1:9897/manager.dev.js');
'''))

from ipycanvas import Canvas, hold_canvas
import numpy as np

CLOCK_RADIUS = 100

canvas = Canvas(width=CLOCK_RADIUS*2.5, height=CLOCK_RADIUS*2.5)
canvas.translate(CLOCK_RADIUS * 1.2, CLOCK_RADIUS * 1.2)
display(canvas)

def clear_drawing():
    canvas.clear_rect(-CLOCK_RADIUS * 1.2, -CLOCK_RADIUS * 1.2, canvas.width, canvas.height)

def minutes_vec(minutes):
    a = minutes * np.pi/30
    return [np.sin(a), -np.cos(a)]

def draw_dial():
    ht = 10
    mt = 6
    ho = 20
    mo = 10

    canvas.text_align = 'center'
    canvas.text_baseline = 'middle'

    canvas.line_width = 2
    canvas.stroke_circle(0, 0, CLOCK_RADIUS)

    for m in range(60):
        a = m * np.pi/30
        x, y = np.sin(a), -np.cos(a)

        canvas.line_width = 1
        if m % 5 == 0:
            canvas.stroke_line(x * (CLOCK_RADIUS - ht), y * (CLOCK_RADIUS - ht), x * CLOCK_RADIUS, y * CLOCK_RADIUS)
            canvas.font = '12px serif'
            canvas.stroke_text(str(m), x * (CLOCK_RADIUS + mo), y * (CLOCK_RADIUS + mo))
            canvas.font = '16px serif'
            canvas.stroke_text(str(m//5 if m > 0 else 12), x * (CLOCK_RADIUS - ho), y * (CLOCK_RADIUS - ho))
        else:
            canvas.stroke_line(x * (CLOCK_RADIUS - mt), y * (CLOCK_RADIUS - mt), x * CLOCK_RADIUS, y * CLOCK_RADIUS)

def draw_hands(minutes):
    ms = 35
    hs = 50

    hrs = minutes // 60
    mins = minutes % 60

    mv = minutes_vec(mins)
    hv = minutes_vec(hrs * 5 + (mins / 12))

    canvas.line_width = 5
    canvas.stroke_line(0, 0, mv[0] * (CLOCK_RADIUS - ms), mv[1] * (CLOCK_RADIUS - ms))
    canvas.stroke_line(0, 0, hv[0] * (CLOCK_RADIUS - hs), hv[1] * (CLOCK_RADIUS - hs))

def draw_clock(hours, minutes):
    with hold_canvas(canvas):
        clear_drawing()
        draw_dial()
        draw_hands((hours % 12) * 60 + minutes)

import datetime
import ipywidgets as widgets

now = datetime.datetime.now()

hour_text = widgets.IntText(value = now.hour, continuous_update=True, layout={'width': '50px'})
minute_text = widgets.IntText(value = now.minute, continuous_update=True, layout={'width': '50px'})

def on_text_change(change):
    draw_clock(int(hour_text.value), int(minute_text.value))

hour_text.observe(on_text_change, names='value')
minute_text.observe(on_text_change, names='value')

display(widgets.HBox([hour_text, widgets.Label(value=':'), minute_text]))

on_text_change(0)

So the basic example using ipyvtklink did not work either:

!pip install vtk
!pip install ipyvtklink
from IPython.display import Javascript
import vtk
from ipyvtklink.viewer import ViewInteractiveWidget

# This enables custom widgets in the current cell's output.
# Currently this must be included in each cell using custom widgets but this
# should be a temporary restriction.
display(Javascript('''
  google.colab.widgets.installCustomManager('http://127.0.0.1:9897/manager.dev.js');
'''))

# Create some data
cylinder = vtk.vtkCylinderSource()
cylinder.SetResolution(8)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cylinder.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)

# Set up render window
ren = vtk.vtkRenderer()
ren_win = vtk.vtkRenderWindow()
ren_win.SetOffScreenRendering(1)
ren_win.SetSize(600, 600)
ren_win.AddRenderer(ren)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(ren_win)
style = vtk.vtkInteractorStyleTrackballCamera()
iren.SetInteractorStyle(style)

# Add actor to scene
ren.AddActor(actor)
ren.ResetCamera()

# Display
ViewInteractiveWidget(ren_win)

They both do not give any output.

My bad, I was focused on the 3d plots. I did not try raw.plot 😅

@larsoner
Copy link
Member

larsoner commented Sep 3, 2021

In the issue linked above they state:

Please feel free to open specific bugs in https://github.com/googlecolab/colab-cdn-widget-manager/issues.

Can you see if this has been reported in https://github.com/googlecolab/colab-cdn-widget-manager/issues and if not, add this information there? Seems like useful debugging for them!

@GuillaumeFavelier
Copy link
Contributor

The related issue is opened in googlecolab/colab-cdn-widget-manager#8 !

@larsoner
Copy link
Member

larsoner commented Sep 8, 2021

Sounds like they've fixed it: googlecolab/colab-cdn-widget-manager#8 (comment)

@larsoner
Copy link
Member

Bumping the milestone of this to the next release, hopefully all (or at least more) bugs will be ironed out by then

@larsoner larsoner modified the milestones: 0.24, 0.25 Oct 22, 2021
@larsoner larsoner modified the milestones: 1.0, 1.1 Feb 11, 2022
@larsoner
Copy link
Member

larsoner commented Mar 9, 2022

I'll close this as upstream bug(s), but people feel free to comment if it's fixed yet (or not)!

@larsoner larsoner closed this as completed Mar 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants