0

I am using Matplotlib in a class to view 3-Dimensional physical data.

I have a fiew sliders and radiobuttons, in which I can update the view on the data (eg. which layer, or what scale to use). This works perfectly fine in Pycharm when running a script. But when I use IPython in Pycharm, to work dynamically on my data, the widgets are either buggy (one of the sliders) or don't respond at all (all the other widgets). The tools of matplotlib for zooming and panning work totally fine though.

I am not quite sure, how to adress this problem, and what I can do for debugging. I beleave in both cases the backend is PyQt5.

There is one more difference, that might be a hint to a solution: the new opened matplotlib window, doesn't show the matplotlib logo, and is just white when run in Ipython.

Here is the minimal code, that reproduces the error. When run from pycharm, all is fine. When run in Pycharm debugger, aka IPython, the error.

import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, RadioButtons

def plot():
    def create_axes():
        ax_slider1 = plt.axes([0.1, 0.1, 0.3, 0.1])
        slider1 = Slider(label="", ax=ax_slider1, valmin=0, valmax=10)

        ax_slider2 = plt.axes([0.1, 0.25, 0.3, 0.1])
        slider2 = Slider(ax=ax_slider2, label="", valmin=0, valmax=10)

        ax_button = plt.axes([0.1, 0.5, 0.15, 0.1])
        button = RadioButtons(ax=ax_button, labels=["a", "b"])

        return slider1, slider2, button

    def update_axes():
        good_slider.ax.set_xlim(1, 2)
        fig.canvas.draw_idle()

    def update_good_slider(offset):
        print(offset)
        update_axes()

    def update_buttons(vlim_type):
        print(vlim_type)
        update_axes()

    def update_bad_slider(factor):
        print(factor)
        update_axes()

    fig, z_ax = plt.subplots()
    fig.subplots_adjust(left=0.5)

    good_slider, bad_slider, buttons = create_axes()

    good_slider.on_changed(update_good_slider)
    buttons.on_clicked(update_buttons)
    bad_slider.on_changed(update_bad_slider)
    plt.show()

plot()

Update I eventually got it working with help from here, and reprogramming my code to be more object orientated, and saving the plot() into a variable (see the commment from @medium-dimensional).

Jonathanthesailor
  • 159
  • 1
  • 1
  • 8
  • Could you please provide a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example)? :) – medium-dimensional May 31 '22 at 18:16
  • 1
    Hi, I added a minimal code, needed some time to figure it out. It appears, that the command "good_slider.ax.set_xlim(1, 2)" enables the widget to work, at least for a small amount of time, then it stops. I don't now if the fig.canvas.draw_idle() makes any difference, but I needed that in my main code for something (can't remember exactly what). – Jonathanthesailor Jun 10 '22 at 13:53

1 Answers1

0

To make Matplotlib interactive in Jupyter Notebook, you need ipympl.

Once installed, you can use %matplotlib widget right after importing all the required package in your script.

Storing the class instance plot() in a variable might help keeping the reference to interactive widget alive.

The following code worked in JupyterLab for me:

import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, RadioButtons

%matplotlib widget

def plot():
    def create_axes():
        ax_slider1 = plt.axes([0.1, 0.1, 0.3, 0.1])
        slider1 = Slider(label="", ax=ax_slider1, valmin=0, valmax=10)

        ax_slider2 = plt.axes([0.1, 0.25, 0.3, 0.1])
        slider2 = Slider(ax=ax_slider2, label="", valmin=0, valmax=10)

        ax_button = plt.axes([0.1, 0.5, 0.15, 0.1])
        button = RadioButtons(ax=ax_button, labels=["a", "b"])

        return slider1, slider2, button

    def update_axes():
        good_slider.ax.set_xlim(1, 2)
        fig.canvas.draw_idle()

    def update_good_slider(offset):
        print(offset)
        update_axes()

    def update_buttons(vlim_type):
        print(vlim_type)
        update_axes()

    def update_bad_slider(factor):
        print(factor)
        update_axes()

    fig, z_ax = plt.subplots()
    fig.subplots_adjust(left=0.5)

    good_slider, bad_slider, buttons = create_axes()

    good_slider.on_changed(update_good_slider)
    buttons.on_clicked(update_buttons)
    bad_slider.on_changed(update_bad_slider)
    plt.show()

w = plot()

Jupyter Core packages on my machine:

IPython          : 8.0.1
ipykernel        : 6.9.1
ipywidgets       : 7.6.5
jupyter_client   : 7.1.2
jupyter_core     : 4.9.2
jupyter_server   : 1.13.5
jupyterlab       : 3.2.9
nbclient         : 0.5.11
nbconvert        : 6.4.2
nbformat         : 5.1.3
notebook         : 6.4.8
qtconsole        : not installed
traitlets        : 5.1.1
medium-dimensional
  • 1,974
  • 10
  • 19
  • Thanks! This makes the second slider work as well. But the button doesn't do anything. Is that the same on your mashine? – Jonathanthesailor Jun 13 '22 at 13:15
  • Yes, @Jonathanthesailor! Sorry, I didn't address the effect of radio button on sliders in the code. Do you want to consider changes from slider of A only when radio button A is active i.e., will only one button be active which will make only one slider to change the plot/figure? – medium-dimensional Jun 13 '22 at 16:03
  • Hi, I managed to get everything working now, by making everything a class attribute, and then saving the plot(). Thanks for your help! – Jonathanthesailor Jun 14 '22 at 14:13
  • Good to know!! Please share the answer so others can also benefit from it. Happy coding! :) – medium-dimensional Jun 14 '22 at 19:40
  • 1
    I will add a comment in my post, although I didn't create a minimal version with the class values. I reprogrammed my complete code, to be more object orientated. – Jonathanthesailor Jun 17 '22 at 14:29