plotly / plotly.py

The interactive graphing library for Python :sparkles: This project now includes Plotly Express!
https://plotly.com/python/
MIT License
16.04k stars 2.54k forks source link

updatemenu button moves on 2nd click #3575

Open janosh opened 2 years ago

janosh commented 2 years ago

Adding an updatemenu button to toggle the legend, the button shifts to the left on 2nd click under certain conditions.

https://user-images.githubusercontent.com/30958850/151654960-7786bdbb-3949-44a2-922a-a9e4cb045629.mp4

Minimal Example

import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species")

legend = dict(
    x=1, y=1, xanchor="right", yanchor="top", groupclick="toggleitem"
)

legend_toggle = dict(
    args=["showlegend", True],
    args2=["showlegend", False],
    label="Toggle legend",
    method="relayout",
)

fig.update_layout(
    legend=legend,
    updatemenus=[
        dict(type="buttons", buttons=[legend_toggle], showactive=True, x=1, y=1)
    ],
)

fig.update_xaxes(range=[0, 10])

fig.show()
stangelandm1 commented 7 months ago

I'm getting this too (using Plotly v5.15.0). Any progress or workaround?

Coding-with-Adam commented 7 months ago

hi @stangelandm1 I tried the code above on my windows machine, Firefox browser, and Plotly 5.18, and I can't replicate the error. It works fine for me. Can you please share your code so I can try to run it on my computer?

Cayt-Schlichting-SOLV commented 5 months ago

I run into this issue on a regular basis and have been unable to reliably narrow down when it occurs. I can't provide the full code or attach an html, but here is a video and some notes on behavior: ButtonMoving2.webm

1) The movement isn't necessarily on the second click for me. It most often occurs on all clicks of a updatemenus button with args2 functionality. Generally I see it on my y-limit toggle button which is created with this:

def create_ylim_toggle(yrange=None, nonnegative=False):
    """
    Given a y limit range, creates a y-limit toggle button that can be placed in the upper-right corner of the figure

    :param yrange: List (of two numbers. EX: [1, 10])
    :param nonnegative: Boolean
    :return: Dictionary (for inclusion in updatemenus list)
    """
    if nonnegative:
        # Set button to toggle non-negative rangemode
        buttons = [dict(args=["yaxis.rangemode", "nonnegative"],
                        args2=["yaxis.rangemode", "normal"],
                        label="Toggle Y range",
                        method='relayout')]
    else:
        # Use provided yrange
        buttons = [dict(args=["yaxis.range", yrange],
                        args2=["yaxis.autorange", True],
                        label="Toggle Y range",
                        method='relayout')]
    um_dict = dict(buttons=buttons, type='buttons', active=-1,
                   x=1, xanchor='left',
                   y=1, yanchor='bottom',
                   pad=dict(b=5, l=5))
    return um_dict

2) The button can move a few pixels, or halfway across the screen, but it always moves left to right for me. If I don't recreate the file or resize the screen, it most often moves back and forth between the two locations. In the example file, I am getting no movement of the button when sized to the full screen (2560 x 1440), however when I reshape it smaller, it toggles back and forth. If I chose somewhere in the middle, the button doesn't move on the first click, then disappears on the second click (off screen?). This is the first time I have noticed that particular behavior. On rare occasion, interacting with the legend will also cause that button to move.

3) I have my Plotly default template set like this:

pio.templates['performance'] = go.layout.Template(
        # LAYOUT
        layout={
            # Make default Font a bit darker
            'font': {
                'color': '#000000',
                'family': 'Arial'
            },
            'title': {
                'font': dict(size=16, family='Arial Black, Arial'),
                'xref': 'paper',
                'x': 0,
                'xanchor': 'left',
                'yref': 'paper',
                'y': 1,
                'yanchor': 'bottom',
                'pad': dict(b=15)
            },
            'modebar': {
                'add': ['hoverclosest', 'hovercompare']
            },
            'updatemenudefaults': {
                'x': 1, 'xanchor': "right",
                'y': 1, 'yanchor': 'bottom',
                'pad': dict(t=7, b=7, r=5, l=5)
            },
            # Add border around plot using mirror
            'xaxis': {
                'showline': True,
                'linecolor': '#CCCCCC',
                'mirror': True,
                'ticks': 'outside'
            },
            'yaxis': {
                'showline': True,
                'linecolor': '#CCCCCC',
                'mirror': True,
                'ticks': 'outside'
            },
            'hoverlabel': {
                'namelength': -1
            }
        }

Plotly: 5.9.0 Python: 3.9.13 Chrome: 123.0.6312.123 (Official Build) (64-bit) (It happens in Edge as well)

A selection of info from the Figure in the video:

'layout': {'annotations': [{'align': 'left',
                                'borderpad': 5,
                                'font': {'family': 'Arial Black, Arial'},
                                'showarrow': False,
                                'text': ("<span style='color:rgb(230, 11" ... "b(127, 56, 236)'>Sunset</span>"),
                                'x': 0,
                                'xanchor': 'left',
                                'xref': 'paper',
                                'y': 1,
                                'yanchor': 'top',
                                'yref': 'paper'},
                               {'showarrow': False,
                                'text': '06:24',
                                'textangle': 0,
                                'x': Timestamp('2024-04-04 06:24:05.172915712'),
                                'xanchor': 'right',
                                'y': 0,
                                'yanchor': 'top',
                                'yshift': -5},
                               {'showarrow': False,
                                'text': '12:45',
                                'textangle': 0,
                                'x': Timestamp('2024-04-04 12:45:00'),
                                'xanchor': 'right',
                                'y': 0.0,
                                'yanchor': 'top',
                                'yshift': -5},
                               {'showarrow': False,
                                'text': '19:04',
                                'textangle': 0,
                                'x': Timestamp('2024-04-04 19:04:03.104234496'),
                                'xanchor': 'right',
                                'y': 0.95,
                                'yanchor': 'top',
                                'yshift': -5}],
               'legend': {'title': {'text': 'variable'}, 'tracegroupgap': 0},
               'shapes': [{'line': {'color': 'rgb(230, 116, 81)', 'dash': 'dash'},
                           'opacity': 0.5,
                           'type': 'line',
                           'x0': Timestamp('2024-04-04 06:24:05.172915712'),
                           'x1': Timestamp('2024-04-04 06:24:05.172915712'),
                           'xref': 'x',
                           'y0': 0,
                           'y1': 1,
                           'yref': 'y domain'},
                          {'line': {'color': 'rgb(209, 169, 14)', 'dash': 'dash'},
                           'opacity': 0.5,
                           'type': 'line',
                           'x0': Timestamp('2024-04-04 12:45:00'),
                           'x1': Timestamp('2024-04-04 12:45:00'),
                           'xref': 'x',
                           'y0': 0,
                           'y1': 1,
                           'yref': 'y domain'},
                          {'line': {'color': 'rgb(127, 56, 236)', 'dash': 'dash'},
                           'opacity': 0.5,
                           'type': 'line',
                           'x0': Timestamp('2024-04-04 19:04:03.104234496'),
                           'x1': Timestamp('2024-04-04 19:04:03.104234496'),
                           'xref': 'x',
                           'y0': 0,
                           'y1': 1,
                           'yref': 'y domain'}],
               'template': '...',
               'title': {'text': 'Some Title'},
               'updatemenus': [{'active': -1,
                                'buttons': [{'args': [yaxis.rangemode,
                                                      nonnegative],
                                             'args2': [yaxis.rangemode, normal],
                                             'label': 'Toggle Y range',
                                             'method': 'relayout'}],
                                'pad': {'b': 5, 'l': 5},
                                'type': 'buttons',
                                'x': 1,
                                'xanchor': 'left',
                                'y': 1,
                                'yanchor': 'bottom'},
                               {'active': 0,
                                'buttons': [{'args': [{'visible': True}], 'label': 'All', 'method': 'restyle'},
                                            {'args': [{'visible': [True,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   True,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   True,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   True, True]}],
                                             'label': 'some label1',
                                             'method': 'restyle'},
                                            {'args': [{'visible': [legendonly,
                                                                   True,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   True,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   True,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   legendonly,
                                                                   True, True]}],
                                             'label': 'some label2',
                                             'method': 'restyle'}],  # I removed some of the other buttons here
                                'direction': 'down',
                                'type': 'dropdown'}],
               'xaxis': {'anchor': 'y', 'domain': [0.0, 1.0], 'title': {'text': ''}},
               'yaxis': {'anchor': 'x', 'domain': [0.0, 1.0], 'title': {'text': '°C'}}}
})