Тире - Динамическая разметка не распространяет размеры измененного графика, пока размер окна не изменит - PullRequest
3 голосов
/ 01 апреля 2019

В приведенном ниже примере приложения Dash я пытаюсь создать динамический макет с переменным количеством строк и столбцов.Этот динамический макет в виде сетки будет заполнен различными графиками, которые могут быть изменены с помощью раскрывающихся списков и т. Д.

Основная проблема, с которой я столкнулся до сих пор, связана с единицами просмотра и попыткой стилизовать отдельные графики соответствующим образом.приспособить динамический макет.Например, я изменяю стиль компонентов dcc.Graph() через единицы просмотра, где размеры (например, height и width могут быть 35vw или 23vw в зависимости от количества столбцов).Например, когда я изменяю количество столбцов с 3 на 2, height и width компонента dcc.Graph() явно изменяются, однако это изменение не отражается в фактическом отображаемом макете до тех пор, пока размер окна не изменится физически.(см. изображения ниже примера кода).

Как заставить компоненты dcc.Graph() распространять эти изменения без изменения размера окна?

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config.suppress_callback_exceptions = True

app.layout = html.Div([

    html.Div(className='row', children=[

        html.Div(className='two columns', style={'margin-top': '2%'}, children=[

            html.Div(className='row', style={'margin-top': 30}, children=[

                html.Div(className='six columns', children=[

                    html.H6('Rows'),

                    dcc.Dropdown(
                        id='rows',
                        options=[{
                            'label': i,
                            'value': i
                        } for i in [1,2,3,4]],
                        placeholder='Select number of rows...',
                        clearable=False,
                        value=2
                    ),

                ]),

                html.Div(className='six columns', children=[

                    html.H6('Columns'),

                    dcc.Dropdown(
                        id='columns',
                        options=[{
                            'label': i,
                            'value': i
                        } for i in [1,2,3]],
                        placeholder='Select number of columns...',
                        clearable=False,
                        value=3
                    ),

                ])

            ]),

        ]),

        html.Div(className='ten columns', id='layout-div', style={'border-style': 'solid', 'border-color': 'gray'}, children=[])

    ])

])

@app.callback(
    Output('layout-div', 'children'),
    [Input('rows', 'value'),
    Input('columns', 'value')])
def configure_layout(rows, cols):

    mapping = {1: 'twelve columns', 2: 'six columns', 3: 'four columns', 4: 'three columns'}
    sizing = {1: '40vw', 2: '35vw', 3: '23vw'}

    layout = [html.Div(className='row', children=[

        html.Div(className=mapping[cols], children=[

            dcc.Graph(
                id='test{}'.format(i+1+j*cols),
                config={'displayModeBar': False},
                style={'width': sizing[cols], 'height': sizing[cols]}
            ),

        ]) for i in range(cols)

    ]) for j in range(rows)]

    return layout

#Max layout is 3 X 4
for k in range(1,13):

    @app.callback(
        [Output('test{}'.format(k), 'figure'),
        Output('test{}'.format(k), 'style')],
        [Input('columns', 'value')])
    def create_graph(cols):

        sizing = {1: '40vw', 2: '35vw', 3: '23vw'}

        style = {
            'width': sizing[cols],
            'height': sizing[cols],
        }

        fig = {'data': [], 'layout': {}}

        return [fig, style]

if __name__ == '__main__':
    app.server.run()

Соответствующие снимки экрана (Изображение 1- загрузка страницы, изображение 2 - изменить столбцы на 2):

enter image description here

enter image description here

1 Ответ

1 голос
/ 23 апреля 2019

Поведение выглядит как ошибка Plotly для меня.

Вот возможное временное решение / краткосрочное решение.

Есть хорошая библиотека visdcc, которая разрешает обратные вызовы с Javascript . Вы можете установить его через

pip install visdcc

Добавьте это к своему div:

visdcc.Run_js(id='javascript'),

и добавить обратный вызов

@app.callback(
    Output('javascript', 'run'),
    [Input('rows', 'value'),
     Input('columns', 'value')])
def resize(_, __): 
    return "console.log('resize'); window.dispatchEvent(new Event('resize'));"

Plotly выдаст ошибку в консоли после события resize (это также происходит, когда окна изменяются вручную), но графики отображаются правильно.

Полный код

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import visdcc

SIZING = {1: '40vw', 2: '35vw', 3: '23vw'}

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config.suppress_callback_exceptions = True

app.layout = html.Div([
    visdcc.Run_js(id='javascript'),
    html.Div(className='row', children=[

        html.Div(className='two columns', style={'margin-top': '2%'}, children=[

            html.Div(className='row', style={'margin-top': 30}, children=[

                html.Div(className='six columns', children=[

                    html.H6('Rows'),

                    dcc.Dropdown(
                        id='rows',
                        options=[{
                            'label': i,
                            'value': i
                        } for i in [1,2,3,4]],
                        placeholder='Select number of rows...',
                        clearable=False,
                        value=2
                    ),

                ]),

                html.Div(className='six columns', children=[

                    html.H6('Columns'),

                    dcc.Dropdown(
                        id='columns',
                        options=[{
                            'label': i,
                            'value': i
                        } for i in [1,2,3]],
                        placeholder='Select number of columns...',
                        clearable=False,
                        value=3
                    ),

                ])

            ]),

        ]),

        html.Div(className='ten columns', id='layout-div', style={'border-style': 'solid', 'border-color': 'gray'}, children=[])

    ])

])


@app.callback(
    Output('layout-div', 'children'),
    [Input('rows', 'value'),
    Input('columns', 'value')])
def configure_layout(rows, cols):

    mapping = {1: 'twelve columns', 2: 'six columns', 3: 'four columns', 4: 'three columns'}

    layout = [html.Div(className='row', children=[

        html.Div(className=mapping[cols], style={'width': SIZING[cols], 'height': SIZING[cols]}, children=[

            dcc.Graph(
                id='test{}'.format(i+1+j*cols),
                config={'displayModeBar': False},
                style={'width': SIZING[cols], 'height': SIZING[cols]}
            ),

        ]) for i in range(cols)

    ]) for j in range(rows)]
    return layout

@app.callback(
    Output('javascript', 'run'),
    [Input('rows', 'value'),
     Input('columns', 'value')])
def resize(_, __): 
    return "console.log('resize'); window.dispatchEvent(new Event('resize'));"


#Max layout is 3 X 4
for k in range(1,13):

    @app.callback(
        [Output('test{}'.format(k), 'figure'),
         Output('test{}'.format(k), 'style')],
        [Input('columns', 'value')])
    def create_graph(cols):

        style = {
            'width': SIZING[cols],
            'height': SIZING[cols],
        }

        fig = {'data': [], 'layout': {}}
        return [fig, style]

if __name__ == '__main__':
    app.server.run()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...