Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.

Dash Tabs component #74

Closed
wants to merge 86 commits into from
Closed

Dash Tabs component #74

wants to merge 86 commits into from

Conversation

chriddyp
Copy link
Member

No description provided.

@chriddyp
Copy link
Member Author

tabs

@chriddyp
Copy link
Member Author

Fixes plotly/dash#36

@chriddyp
Copy link
Member Author

Try it out on the pre-release channel with

pip install dash-core-components==0.13.0-rc4

That example above:

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

app = dash.Dash()

app.scripts.config.serve_locally = True

app.layout = html.Div([
    dcc.Tabs(
        tabs=[
            {'label': 'Tab {}'.format(i), 'value': i} for i in range(1, 5)
        ],
        value=3,
        id='tabs'
    ),
    html.Div(id='tab-output')
], style={
    'width': '80%',
    'fontFamily': 'Sans-Serif',
    'margin-left': 'auto',
    'margin-right': 'auto'
})


@app.callback(Output('tab-output', 'children'), [Input('tabs', 'value')])
def display_content(value):
    data = [
        {
            'x': [1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
                  2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012],
            'y': [219, 146, 112, 127, 124, 180, 236, 207, 236, 263,
                  350, 430, 474, 526, 488, 537, 500, 439],
            'name': 'Rest of world',
            'marker': {
                'color': 'rgb(55, 83, 109)'
            },
            'type': ['bar', 'scatter', 'box'][int(value) % 3]
        },
        {
            'x': [1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
                  2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012],
            'y': [16, 13, 10, 11, 28, 37, 43, 55, 56, 88, 105, 156, 270,
                  299, 340, 403, 549, 499],
            'name': 'China',
            'marker': {
                'color': 'rgb(26, 118, 255)'
            },
            'type': ['bar', 'scatter', 'box'][int(value) % 3]
        }
    ]

    return html.Div([
        dcc.Graph(
            id='graph',
            figure={
                'data': data,
                'layout': {
                    'margin': {
                        'l': 30,
                        'r': 0,
                        'b': 30,
                        't': 0
                    },
                    'legend': {'x': 0, 'y': 1}
                }
            }
        ),
        html.Div(' '.join(get_sentences(10)))
    ])


if __name__ == '__main__':
    app.run_server(debug=True)

@chriddyp chriddyp changed the title first pass at a Tabs component Dash Tabs component Sep 14, 2017
@chriddyp
Copy link
Member Author

Vertical view
tabs-vertical

@TheoLvs
Copy link

TheoLvs commented Sep 15, 2017

Awesome ! Thank you very much

@richard-muir
Copy link

Hey Chris, looking great! Tabs & Upload have taken Dash to the next level!

How did you get the tabs on the left-hand side? Had a look through the source, but struggling to figure it out.

@chriddyp
Copy link
Member Author

@richard-muir Sorry about that! I forgot to publish my latest commits.
Here is the latest example:

pip install dash-core-components==0.13.0-rc5
pip install loremipsum
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
from loremipsum import get_sentences

app = dash.Dash()

app.scripts.config.serve_locally = True

vertical = True

if not vertical:
    app.layout = html.Div([
        dcc.Tabs(
            tabs=[
                {'label': 'Market Value', 'value': 1},
                {'label': 'Usage Over Time', 'value': 2},
                {'label': 'Predictions', 'value': 3},
                {'label': 'Target Pricing', 'value': 4},
            ],
            value=3,
            id='tabs',
            vertical=vertical
        ),
        html.Div(id='tab-output')
    ], style={
        'width': '80%',
        'fontFamily': 'Sans-Serif',
        'margin-left': 'auto',
        'margin-right': 'auto'
    })

else:
    app.layout = html.Div([
        html.Div(
            dcc.Tabs(
                tabs=[
                    {'label': 'Market Value', 'value': 1},
                    {'label': 'Usage Over Time', 'value': 2},
                    {'label': 'Predictions', 'value': 3},
                    {'label': 'Target Pricing', 'value': 4},
                ],
                value=3,
                id='tabs',
                vertical=vertical,
                style={
                    'height': '100vh',
                    'borderRight': 'thin lightgrey solid',
                    'textAlign': 'left'
                }
            ),
            style={'width': '20%', 'float': 'left'}
        ),
        html.Div(
            html.Div(id='tab-output'),
            style={'width': '80%', 'float': 'right'}
        )
    ], style={
        'fontFamily': 'Sans-Serif',
        'margin-left': 'auto',
        'margin-right': 'auto',
    })


@app.callback(Output('tab-output', 'children'), [Input('tabs', 'value')])
def display_content(value):
    data = [
        {
            'x': [1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
                  2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012],
            'y': [219, 146, 112, 127, 124, 180, 236, 207, 236, 263,
                  350, 430, 474, 526, 488, 537, 500, 439],
            'name': 'Rest of world',
            'marker': {
                'color': 'rgb(55, 83, 109)'
            },
            'type': ['bar', 'scatter', 'box'][int(value) % 3]
        },
        {
            'x': [1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
                  2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012],
            'y': [16, 13, 10, 11, 28, 37, 43, 55, 56, 88, 105, 156, 270,
                  299, 340, 403, 549, 499],
            'name': 'China',
            'marker': {
                'color': 'rgb(26, 118, 255)'
            },
            'type': ['bar', 'scatter', 'box'][int(value) % 3]
        }
    ]

    return html.Div([
        dcc.Graph(
            id='graph',
            figure={
                'data': data,
                'layout': {
                    'margin': {
                        'l': 30,
                        'r': 0,
                        'b': 30,
                        't': 0
                    },
                    'legend': {'x': 0, 'y': 1}
                }
            }
        ),
        html.Div(' '.join(get_sentences(10)))
    ])


if __name__ == '__main__':
    app.run_server(debug=True)

@dotsdl
Copy link

dotsdl commented Sep 19, 2017

Awesome @chriddyp! This is really going to make some incredible things possible with relatively little effort.

@chriddyp
Copy link
Member Author

I have pushed v0.13.0rc8 to include the fixes from v0.12.7

* upload component 🎉 
* integration test
* update circle python requirements
* lint
* ✨ sort imports
@chriddyp
Copy link
Member Author

chriddyp commented Nov 2, 2017

I have rebased this branch off of the latest version. Try this out with pip install dash-core-components==0.15.0rc1

@mtreu
Copy link

mtreu commented Nov 13, 2017

This looks awesome! However, is there a way to change the color of a tab?

@jbrav
Copy link

jbrav commented Nov 15, 2017

Hey, @chriddyp thank you very much. I am trying to actually get different data on each tab. I am quite new in Python, but so far I have tried the following.

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

app = dash.Dash()

app.scripts.config.serve_locally = True





app.layout = html.Div([
    dcc.Tabs(
        tabs=[
            {'label': 'Tab {}'.format(i), 'value': i} for i in range(1, 4)
        ],
        value=4,
        id='tabs',
    ),
    html.Div(id='tab-output')
], style={
    'width': '80%',
    'fontFamily': 'Sans-Serif',
    'margin-left': 'auto',
    'margin-right': 'auto'
})


@app.callback(Output('tab-output', 'children'), [Input('tabs', 'value')])
def display_content(value):
    data = [
        {
            'x': [1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017],
            'y': [42, 41, 64, 54, 12, 54, 69, 12, 76, 35, 68,86, 56, 57, 65, 43, 91,85,12, 59, 76, 14, 16, 28, 40, 56, 52, 78,75, 67, 12, 52, 75, 43, 52, 54, 64, 62, 68],
            'name': 'Schroders',
            'marker': {
                'color': 'rgb(54, 82, 110)'
            },
            'type': ['bar', 'scatter'][int(value) % 2]
        },
        {
            'x': [1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017],
            'y': [52, 51, 74, 64, 22, 44, 59, 32, 16, 65, 18,16, 16, 27, 35, 13, 11,25,72, 19, 96, 64, 96, 68, 10, 96, 82, 18,25, 37, 72, 12, 25, 13, 32, 14, 24, 12, 98],
            'name': 'MSF ',
            'marker': {
                'color': 'rgb(26, 118, 255)'
            },
            'type': ['bar', 'scatter'][int(value) % 2]
        },
        {
            'x': [1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017],
            'y': [32, 11, 84, 94, 62, 14, 79, 52, 16, 15, 98,26, 36, 47, 15, 83, 31,45,22, 69, 16, 74, 46, 98, 70, 16, 22, 38,45, 17, 42, 22, 35, 83, 72, 44, 94, 22, 60],
            'name': 'OMS',
            'marker': {
                'color': 'rgb(55, 83, 109)'
            },
            'type': ['bar', 'scatter'][int(value) % 2]
        },
    ],
def muestra_contenido(value):
    data1 = [
            {
                'x': [1940, 1950, 1960, 1970],
                'y': [1, 2, 3, 4],
                'name': 'test1',
                'marker': {
                'color': 'rgb(60, 41, 200)'
                },
                'type': ['bar', 'scatter'][int(value)%2]
         },
         {
                'x': [1940, 1950, 1960, 1970],
                'y': [5, 6, 7, 8],
                'name': 'test2',
                'marker': {
                'color': 'rgb(61, 42, 201)'
            },
                'type': ['bar', 'scatter'][int(value)%2]
        }
    ],
    return html.Div [(
        dcc.Graph(
            id='graph',
            figure={
                'data': data,
                'layout': {
                    'margin': {
                        'l': 30,
                        'r': 0,
                        'b': 30,
                        't': 0
                    },
                    'legend': {'x': 0, 'y': 1}
                }
            }
        ),
        html.Div('Estoy haciendo una prueba para ver como funcionaria esto')
    )],
    return html.Div([
        dcc.Graph(
            id='graph1',
                figure={
                'data': data1,
                'layout': {
                    'margin': {
                        'l': 30,
                        'r': 0,
                        'b': 30,
                        't': 0
                    },
                    'legend': {'x': 0, 'y': 1}
                }
            }
        ),
        html.Div('Estoy haciendo una prueba para ver como funcionaria esto')
    ])

if __name__ == '__main__':
    app.run_server(debug=True)

I would love if you could point where my error is. I have also tried to create another label, without success as it is apparent .

@chriddyp
Copy link
Member Author

@jbrav - Would you mind asking this implementation question in the dash community forum? https://community.plot.ly/c/dash. That'll keep things a little bit more organized for me and you're likely to get more people to help you out there. Thanks!

@chriddyp
Copy link
Member Author

I've made a new prerelease off of master. Get the latest with:

pip install dash-core-components==0.21.0rc1

And check your version with:

>>> import dash_core_components as dcc
>>> print(dcc.__version__)
0.21.0rc1

@charleyferrari
Copy link

@chriddyp Do you think there's a way for dccs within tabs to remain active even if the tab isn't selected?

Here's a toy example of what I'm thinking:

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

app = dash.Dash(__name__, static_folder='assets')
server = app.server
app.scripts.config.serve_locally=True
app.css.config.serve_locally=True
app.config['suppress_callback_exceptions']=True

app.layout = html.Div([
    dcc.Tabs(tabs = [
        {'label': 'Tab 1', 'value': 1},
        {'label': 'Tab 2', 'value': 2}
    ], id='tabs', value = 1),
    html.Div([], id='tab_output'),
    html.Div([], id='output')
])

@app.callback(
    Output('tab_output', 'children'),
    [Input('tabs', 'value')]
)
def show_dropdowns(value):
    if value == 1:
        return dcc.Dropdown(options = [
            {'label': 'A', 'value': 'A'},
            {'label': 'B', 'value': 'B'}
        ], id='dropdown1', value = 'A')
    if value == 2:
        return dcc.Dropdown(options = [
            {'label': 'C', 'value': 'C'},
            {'label': 'D', 'value': 'D'}
        ], id='dropdown2', value = 'C')

@app.callback(
    Output('output', 'children'),
    [Input('dropdown1', 'value'), Input('dropdown2', 'value')]
)
def format_text(d1, d2):
    return 'Your first dropdown says {} and your second dropdown says {}'.format(d1, d2)

if __name__ == '__main__':
    app.run_server(debug=True)

Ideally I'd like a user to be able to make selections in each tab, and have the main output draw from both tabs.

Something like this doesn't work now because the tabs change the layout, and it's impossible for both dccs to exist at the same time.

@chriddyp
Copy link
Member Author

@charleyferrari - All of the inputs of a callback need to be visible in the layout at the same time in order for them to fire the callback. You could keep them layout by just toggling the visibility, like:

app.layout = html.Div([
     dcc.Tabs(...),
     dcc.Dropdown(id='dropdown1', style={'display': 'none'}, ...)
     dcc.Dropdown(id='dropdown2', style={'display': 'none'}, ...)
])
@app.callback(Output('dropdown1', 'style'), [Input('tabs', 'value')])
def update_dropdown(value):
    return {'display': 'block' if value == 1 else 'none'}

@app.callback(Output('dropdown2', 'style'), [Input('tabs', 'value')])
def update_dropdown(value):
    return {'display': 'block' if value == 2 else 'none'}

@Forander
Copy link

Is there was a way to use Tabs offline? I would like to create an HTML dashboard with plots arranged in tabs which I can email to people who don't have Python installed (due to security requirements I also cannot use Dash server).

This can be done using Bokeh but I would prefer using Plotly as it's much more user friendly. Any help would really be appreciated. Thanks

@chriddyp

@chriddyp
Copy link
Member Author

Is there was a way to use Tabs offline? I would like to create an HTML dashboard with plots arranged in tabs which I can email to people who don't have Python installed (due to security requirements I also cannot use Dash server).

This is a separate issue than what is presented in this PR. In any case, this isn't possible now with Dash but it will be in the future. There is a WIP PR here: plotly/dash-renderer#7

@Forander
Copy link

Thanks for the quick response Chris. What would you suggest if I'm looking to create something like this? Is it possible to arrange something myself by saving Plotly plots as divs?

@chriddyp
Copy link
Member Author

Thanks for the quick response Chris. What would you suggest if I'm looking to create something like this? Is it possible to arrange something myself by saving Plotly plots as divs?

Can you ask this in the community forum? https://community.plot.ly/c/dash. The discussion in this thread should be related to this PR.

@steremma
Copy link

This is an extremely useful PR, congrats @chriddyp ! Can we maybe have a (rough) estimation of when this could be merged? I am interested in using it for a client facing application so I would feel a lot better using master!

@QCTW
Copy link

QCTW commented Apr 19, 2018

Thanks for the great work. @chriddyp

I encountered one problem when I tried to place an upload component (https://dash.plot.ly/dash-core-components/upload) inside a tab, it can not properly display the upload block. If I don't put the upload component (the same codes) in the tab, the upload block can properly display...

Is this normal?

@ghost
Copy link

ghost commented Apr 26, 2018

Hi Chris,
I am using the tabs in the vertical=True mode. (see screen shot) Why is my tab background color not extending past the original screen size - on the scroll down?
Is this a bug? Or, am I doing something wrong? I love the tabs addition, but without this background-color-extension on the scroll-down it makes it look un-professional.
Can you help?
Best regards,
~BB

image

image

@jen0liu
Copy link

jen0liu commented May 2, 2018

@chriddyp for Tabs, it's not included in the latest release (0.22). I had to revert back to an older version 0.21.rc01 which means I can't use some other new cool features people added to dash-core-component. Can you please see if you can merge to the latest branch? Thanks.

@thomasmarshbintel
Copy link

If it can be merged that would be great since scattermapbox doesn't work with this branch and I love the tabs way too much.

@slash31
Copy link

slash31 commented May 12, 2018

+1 on having this re-integrated into the train. Thanks for all of your hard work!

@randiaz95
Copy link

Major firepower with this tab pre release, the programming gods are happy :).

@kyleabeauchamp
Copy link

I too am interested in seeing this PR updated for the latest release.

@chriddyp
Copy link
Member Author

Thank you everyone so much for the reviews and feedback ❤️

We have incorporated this feedback into a new revision of the Tabs component here: #213.

@jogendraKhalsa
Copy link

Hi Chris, ... can you help with a situation wherein i have to update real time using dcc.Interval as component-Interval is not part of 0.21.0rcxx .
Thanks in Advance.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.