0

My situation is this: I am developing a Jupyter-lab notebook to exemplify engineering topics. I find myself in the need of plotting something in an axes object within a figure, and then using a slider interact changing a value to update the plot.

Here is a MWE (or at least a shorter Working Example):

import ipywidgets as widgets
from ipywidgets import interact
import numpy as np
import matplotlib.pyplot as plt

global ax1
global fig
fig, (ax1) = plt.subplots(ncols=1, subplot_kw=dict(projection='polar'))

RAD = np.array([0.85, 0.85, 0.85])
ANG = np.array([np.pi/2, np.pi*(2/3+1/2), np.pi*(1/2-2/3)])
c = ax1.scatter(ANG, RAD)

ax1.set_ylim([0, 1])
ax1.set_yticklabels([])

def h(rh):   
    RADp = np.array([rh, rh, rh])
    ANGp = np.array([-np.pi/2, np.pi*(2/3-1/2), np.pi*(-1/2-2/3)])
    cp = ax1.scatter(ANGp, RADp)
    ax1.add_artist(cp)
    plt.show()

    return (rh)

interact(h, rh = widgets.FloatSlider(min=0, max=1, step=0.001, value=1));

In this example I create the figure fig and its axes ax1 declared as global variables (so that they will be available within function h. Then using RAD and ANG I create a scatter plot c.

Afterwards using the interact widget I would like to have three crosses change position along the r axis by changing the value of rh with the slider.

I don't get any error, but neither get I any crosses at all.

In the actual code I use pcolormesh instead of scatter.

I hope I made myself clear. I had got ti working by creating the figure and ax1 each time the function is called, but then I added some more suff thath don't need to be plotted each time.

Thanks for taking the time to read!

2 Answers 2

1

A very limited answer is that you function should return fig not rh.

Also note that you don't need the lines with global, and plt.show()

import ipywidgets as widgets
from ipywidgets import interact
import numpy as np
import matplotlib.pyplot as plt


fig, (ax1) = plt.subplots(ncols=1, subplot_kw=dict(projection='polar'))

RAD = np.array([0.85, 0.85, 0.85])
ANG = np.array([np.pi/2, np.pi*(2/3+1/2), np.pi*(1/2-2/3)])
c = ax1.scatter(ANG, RAD)

ax1.set_ylim([0, 1])
ax1.set_yticklabels([])


def h(rh):   
    RADp = np.array([rh, rh, rh])
    ANGp = np.array([-np.pi/2, np.pi*(2/3-1/2), np.pi*(-1/2-2/3)])
    cp = ax1.scatter(ANGp, RADp)
    ax1.add_artist(cp)
    # plt.show()

    return fig

interact(h, rh = widgets.FloatSlider(min=0, max=1, step=0.001, value=1));

I say limited because I think you want to update rather than add point?

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your reply! Yes in the actual code I have a colormesh that I want to update as the slider changes its value. I will implement your suggestions.
1

A version which is hopefully more in line with what you want

the key point being the use of set_offsets method to update the positions.

import ipywidgets as widgets
from ipywidgets import interact
import numpy as np
import matplotlib.pyplot as plt

fig, (ax1) = plt.subplots(ncols=1, subplot_kw=dict(projection='polar'))

RAD = np.array([0.85, 0.85, 0.85])
ANG = np.array([np.pi/2, np.pi*(2/3+1/2), np.pi*(1/2-2/3)])
c = ax1.scatter(ANG, RAD)

ax1.set_ylim([0, 1])
ax1.set_yticklabels([])


def h(rh):   
    new = [
        [-np.pi/2, rh],
        [np.pi*(2/3-1/2), rh],
        [np.pi*(-1/2-2/3), rh],
    ]
    c.set_offsets(new)

    return fig

interact(h, rh = widgets.FloatSlider(min=0, max=1, step=0.001, value=1));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.