0

In a Jupyter Notebook, I make use of a Jupyter Widget to interact with a function. The widget gives me a dropdown that can cycle through some plots, and its options are retrieved from a dataframe. Underneath the pseudocode that does work:

def plot_option(x):
    plot(x)  
        
        
option = widgets.Dropdown(
               options=[ df[column].iloc[i]) for i in range(10)])
        
        
interact(plot_option,x=option)

But in the actual implementation it would be better for the value of option to be i, the rank in the (sorted) dataframe. However rearranging the code as underneath raises an error:

option = widgets.Dropdown(
                options=[i for i in range(10)])
            
            
interact(plot_option,x=df[column].iloc[option.value]))

with the error:

step must be >= 0, not -2

Shouldn't the value of option just be an integer?

Why can't I slice in the interact definition?

traceback:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[332], line 11
      8 def plot_tiles_option(board,free_coords,coord):
      9     plot_tiles(board,free_coords,local_tiles(coord,2),coord=coord)
---> 11 interact(plot_tiles_option,board=fixed(Board),free_coords=fixed(Free_coords),coord=top10['coordinates'].iloc[int(option.value)])

File ~\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\ipywidgets\widgets\interaction.py:536, in _InteractFactory.__call__(self, _InteractFactory__interact_f, **kwargs)
    528     return self
    530 # positional arg support in: https://gist.github.com/8851331
    531 # Handle the cases 1 and 2
    532 # 1. interact(f, **kwargs)
    533 # 2. @interact
    534 #    def f(*args, **kwargs):
    535 #        ...
--> 536 w = self.widget(f)
    537 try:
    538     f.widget = w

File ~\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\ipywidgets\widgets\interaction.py:452, in _InteractFactory.widget(self, f)
    436 def widget(self, f):
    437     """
    438     Return an interactive function widget for the given function.
    439 
   (...)    450         The function to which the interactive widgets are tied.
    451     """
--> 452     return self.cls(f, self.opts, **self.kwargs)

File ~\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\ipywidgets\widgets\interaction.py:187, in interactive.__init__(self, _interactive__interact_f, _interactive__options, **kwargs)
    185     getcallargs(f, **{n:v for n,v,_ in new_kwargs})
    186 # Now build the widgets from the abbreviations.
--> 187 self.kwargs_widgets = self.widgets_from_abbreviations(new_kwargs)
    189 # This has to be done as an assignment, not using self.children.append,
    190 # so that traitlets notices the update. We skip any objects (such as fixed) that
    191 # are not DOMWidgets.
    192 c = [w for w in self.kwargs_widgets if isinstance(w, DOMWidget)]

File ~\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\ipywidgets\widgets\interaction.py:286, in interactive.widgets_from_abbreviations(self, seq)
    284 if isinstance(abbrev, Widget) and (not isinstance(abbrev, ValueWidget)):
    285     raise TypeError("{!r} is not a ValueWidget".format(abbrev))
--> 286 widget = self.widget_from_abbrev(abbrev, default)
    287 if widget is None:
    288     raise ValueError("{!r} cannot be transformed to a widget".format(abbrev))

File ~\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\ipywidgets\widgets\interaction.py:302, in interactive.widget_from_abbrev(cls, abbrev, default)
    299     return abbrev
    301 if isinstance(abbrev, tuple):
--> 302     widget = cls.widget_from_tuple(abbrev)
    303     if default is not empty:
    304         try:

File ~\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\ipywidgets\widgets\interaction.py:382, in interactive.widget_from_tuple(o)
    380 step = o[2]
    381 if step <= 0:
--> 382     raise ValueError("step must be >= 0, not %r" % step)
    383 min, max, value = _get_min_max_value(o[0], o[1], step=step)
    384 if all(isinstance(_, Integral) for _ in o):

ValueError: step must be >= 0, not -2
6
  • always put full error message (traceback) because there are other useful information. Commented Nov 4 at 0:04
  • maybe it gives it as string, not integer (maybe it converts it to string when it generates HTML with dropdown). Did you try to use int()? Did you try to run some code which displays what is in option or in type(option)? Commented Nov 4 at 0:07
  • my pseudocode didnt include me stating option.value, and I did check it is an int. Updated the post Commented Nov 4 at 0:30
  • maybe send it as x=option and use df[column].iloc[x] inside def plot_option(x) Commented Nov 4 at 0:31
  • Did try that too, unfortunately the same result. Commented Nov 4 at 0:39

1 Answer 1

1

The issue is that interact() evaluates df[column].iloc[option.value] at creation time, not when the dropdown changes. It tries to interpret the result as widget parameters, causing the error.

Solution:

def plot_option(i):
    coord = df['coordinates'].iloc[i]
    plot_tiles(Board, Free_coords, local_tiles(coord, 2), coord=coord)

option = widgets.Dropdown(options=list(range(10)))

interact(plot_option, i=option)

Pass the widget to interact(), not the dereferenced value. Your function receives the integer i directly, which you can then use to slice the dataframe.

With custom labels:

option = widgets.Dropdown(
    options=[(f"Rank {i}", i) for i in range(10)]
)

interact(plot_option, i=option)

This displays "Rank 0", "Rank 1", etc. in the dropdown but passes the integer to your function.

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

1 Comment

Very clear, thanks for the clear explanation!

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.