plotly / dash-table-experiments

NO LONGER SUPPORTED - use https://github.com/plotly/dash-table instead
MIT License
174 stars 57 forks source link

WIP - enable components as cells #11

Closed chriddyp closed 5 years ago

chriddyp commented 6 years ago

render anything inside cells: links, graphs, dropdowns, whatever! enabled by https://github.com/plotly/dash-renderer/pull/26 would fix #6 and #7

usage (requires https://github.com/plotly/dash-renderer/pull/26)

# -*- coding: UTF-8 -*-

import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt
import json
import pandas as pd
import plotly

app = dash.Dash()

app.scripts.config.serve_locally = True

DF_GAPMINDER = pd.read_csv(
    'https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv'
)
sparklines = {
    c: html.Div(style={'height': 100, 'width': '100%'}, children=dcc.Graph(
        id=c,
        figure={
            'data': [{
                'x': DF_GAPMINDER[c],
                'type': 'histogram'
            }],
            'layout': {
                'height': 100,
                'width': 150,
                'margin': {
                    'l': 0, 'r': 0, 't': 0, 'b': 0
                },
                'xaxis': {
                    'showticklabels': False,
                    'showline': False,
                    'showgrid': False,
                },
                'yaxis': {
                    'showticklabels': False,
                    'showline': False,
                    'showgrid': False,
                }
            }
        },
        config={'displayModeBar': False}
    ))
    for c in DF_GAPMINDER.columns
}

app.layout = html.Div([
    html.H1('💖 Dash Sparklines 💖', style={'textAlign': 'center'}),
    html.H2(html.I('Coming Soon'), style={'textAlign': 'center'}),
    dt.DataTable(
        rows=[sparklines] + DF_GAPMINDER.to_dict('records'),
        id='table',
        min_height=1500,
    ),
    html.Div(dcc.Dropdown(), style={'display': 'none'})
], className="container")

app.css.append_css({
    "external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"
})

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

sparklines

richard-muir commented 6 years ago

Yes! This looks incredible :-)

BAjayiobe1 commented 6 years ago

Fantastic! This would be really useful for the project I'm currently working.

jdagdelen commented 6 years ago

I heartily support this feature as well.

gustavengstrom commented 6 years ago

This seems like a great update! I would like to try this out asap... I tried to do a: pip install git+https://github.com/plotly/dash-table-experiments.git@sub-renderer Cannot get the above example to work... Only Error response is: Error loading layout. Any ideas on what I may be doing wrong?!

chriddyp commented 6 years ago

I tried to do a: pip install pip install git+https://github.com/plotly/dash-table-experiments.git@sub-renderer

This repo doesn't contain the necessary JS and CSS bundles. You'll have to build them locally:

git clone https://github.com/plotly/dash-table-experiments
cd dash-table-experiments
git checkout sub-renderer
npm i
npm run prepublish
python setup.py sdist
pip install dist/dash_table_experiments-0.5.0.tar.gz # or whatever version it is

and you'll need to build the dash-renderer package

git clone https://github.com/plotly/dash-renderer
cd dash-renderer
git checkout  components-as-props
npm i
npm run prepublish
python setup.py sdist
pip install dist/dash_renderer-0.11.1.tar.gz # or whatever version it is

and then you'll need to make sure that it's assets are loaded locally with

app.scripts.serve_locally=True
gustavengstrom commented 6 years ago

Thanks for the quick reply! I followed these instructions but I still get: Error loading layout. You wrote that usage (requires plotly/dash-renderer#26). Do I also need to build dash-renderer locally??

chriddyp commented 6 years ago

Do I also need to build dash-renderer locally??

Yeah, that one too. Same steps for that repo as well

chriddyp commented 6 years ago

I have just updated this PR to support a new prototype of dash-renderer: https://github.com/plotly/dash-renderer/pull/32.

The same functionality as mentioned in https://github.com/plotly/dash-table-experiments/pull/11#issue-265994253 still applies, this is just a more performant and generic solution.

chriddyp commented 6 years ago

Updated Examples

Sparklines image

import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt
import json
import pandas as pd
import numpy as np
import plotly

app = dash.Dash()
server = app.server

app.scripts.config.serve_locally = True
app.css.config.serve_locally = True

DF_GAPMINDER = pd.read_csv(
    'https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv'
)

ROW_HEIGHT = 40

sparklines = {
    c: html.Div(style={'height': 100, 'width': '100%'}, children=dcc.Graph(
        id=c,
        figure={
            'data': [{
                'x': DF_GAPMINDER[c],
                'type': 'histogram',
            }],
            'layout': {
                'height': ROW_HEIGHT,
                'margin': {
                    'l': 0, 'r': 0, 't': 0, 'b': 0
                },
                'xaxis': {
                    'showticklabels': False,
                    'showline': False,
                    'showgrid': False,
                },
                'yaxis': {
                    'showticklabels': False,
                    'showline': False,
                    'showgrid': False,
                },
                'hovermode': 'closest'
            }
        },
        config={'displayModeBar': False}
    ))
    for c in DF_GAPMINDER.columns
}

ROWS = [sparklines] + DF_GAPMINDER.to_dict('records')

app.layout = html.Div([
    dt.DataTable(
        rows=ROWS,

        row_selectable=True,
        filterable=True,
        sortable=True,
        selected_row_indices=[],
        id='datatable',

        row_height=ROW_HEIGHT
    ),
    html.Div(id='selected-indexes'),
    dcc.Graph(
        id='graph-gapminder'
    ),
], className="container")

app.css.append_css({
    "external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"
})

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

Conditional Formatting image

import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt

import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randn(50, 4), columns=list('ABCD'))

COLORS = [
    {
        'background': '#fef0d9',
        'text': 'rgb(30, 30, 30)'
    },
    {
        'background': '#fdcc8a',
        'text': 'rgb(30, 30, 30)'
    },
    {
        'background': '#fc8d59',
        'text': 'rgb(30, 30, 30)'
    },
    {
        'background': '#d7301f',
        'text': 'rgb(30, 30, 30)'
    },
]

def is_numeric(value):
    try:
        float(value)
        return True
    except ValueError:
        return False

def cell_style(value, min_value, max_value):
    style = {}
    if is_numeric(value):
        relative_value = (value - min_value) / (max_value - min_value)
        if relative_value <= 0.25:
            style = {
                'backgroundColor': COLORS[0]['background'],
                'color': COLORS[0]['text']
            }
        elif relative_value <= 0.5:
            style = {
                'backgroundColor': COLORS[1]['background'],
                'color': COLORS[1]['text']
            }
        elif relative_value <= 0.75:
            style = {
                'backgroundColor': COLORS[2]['background'],
                'color': COLORS[2]['text']
            }
        elif relative_value <= 1:
            style = {
                'backgroundColor': COLORS[3]['background'],
                'color': COLORS[3]['text']
            }
    return style

def ConditionalTable(dataframe):
    max_value = df.max(numeric_only=True).max()
    min_value = df.min(numeric_only=True).max()
    rows = []
    for i in range(len(dataframe)):
        row = {}
        for col in dataframe.columns:
            value = dataframe.iloc[i][col]
            style = cell_style(value, min_value, max_value)
            row[col] = html.Div(
                value,
                style=dict({
                    'height': '100%'
                }, **style)
            )
        rows.append(row)

    return rows

app = dash.Dash()

app.scripts.config.serve_locally = True
app.css.config.serve_locally = True

app.layout = html.Div([
    dt.DataTable(
        rows=ConditionalTable(df),

        row_selectable=True,
        filterable=True,
        sortable=True,
        selected_row_indices=[],
        id='datatable',
    )
], className='container')

if __name__ == '__main__':
    app.run_server(debug=True)
chriddyp commented 6 years ago

I just published some prerelease versions of this code. Try out the example above by installing these packages:

pip install dash==0.19.0
pip install dash-core-components==0.16.0rc1
pip install dash-html-components==0.9.0rc1
pip install dash-renderer==0.13.0rc2
pip install dash-table-experiments==0.6.0rc1
gustavengstrom commented 6 years ago

Nice! I have tested adding images which works great! Could the above script be used to also change column widths conditionally?! I think this is would be an important feature to add...

gustavengstrom commented 6 years ago

Noticed a problem in the above prelease. The header row became scrollable and partially hided the first column header when running the above code with: app.css.config.serve_locally = False. While searching for the error I noticed that the following dash_table_experiments.css is not being served as it should at:

https://unpkg.com/dash-table-experiments@0.6.0rc1/dash_table_experiments/dash_table_experiments.css

chriddyp commented 6 years ago

Could the above script be used to also change column widths conditionally

It can't, but I just added this in #33 and #32 🍻

annitrolla commented 6 years ago

Does not seem to render links properly: href attribute goes missing. I took the example from https://github.com/plotly/dash-table-experiments/pull/11#issuecomment-352106827 and swapped the graph-drawing part to

sparklines = {
    c: html.Div(style={'height': 100, 'width': '100%'}, children=[
        dcc.Link('Navigate to "/"', href="http://www.google.com")
    ])
    for c in DF_GAPMINDER.columns
}

the resulting HTML inside a cell is

<a>Navigate to "/"</a>
chriddyp commented 6 years ago

@annitrolla - Use html.A instead for links that are for 3rd party websites. dcc.Link is only used for links within Dash, and it has to be used with a dcc.Location component (see https://plot.ly/dash/urls for more examples).

annitrolla commented 6 years ago

@chriddyp The external links with html.A worked, thanks! However, I try to render table cells as links within Dash, but I keep getting Error loading dependencies. The only modified parts are:

sparklines = {
    c: html.Div(children=[dcc.Link(
        'Navigate to "/page-2"', href='/page-2'
    ),
        dcc.Location(id='url', refresh=False),
        html.Div(id='page-content')
    ])
    for c in DF_GAPMINDER.columns
}

and

@app.callback(Output('page-content', 'children'),
              [Input('url', 'pathname')])
def display_page(pathname):
    return html.Div([
        html.H3('You are on page {}'.format(pathname))
    ])
gustavengstrom commented 6 years ago

@chriddyp: Any plans for when this branch will be merged?! My project needs both the column width adjustment of 0.5.3 and the ability to enable components as cells but the above prerelease came prior to 0.5.3. If not ready to merge yet perhaps an update to the prerelease?! Thanks!

mankensin commented 6 years ago

@chriddyp, Thanks for the great improvements on DataTable. I am also new to Dash and trying to implement the Conditional Formatting in your example above. Everything works fine but the Filter rows does not work. Is there anything I am missing? capture

chriddyp commented 6 years ago

Everything works fine but the Filter rows does not work. Is there anything I am missing?

I don't think that you are missing anything. My guess is that this just doesn't work yet. There is quite a lot of work required to tie everything together.

mankensin commented 6 years ago

@chriddyp, thanks for your prompt response. That was highly appreciated!

mankensin commented 6 years ago

I have an html file rendered from DataFrame, is there a way I can open this html directly on Dash?

mankensin commented 6 years ago

Please can someone help me with how to render html file directly on Dash? e.g

app.layout = html.Div( html.Iframe(src='/home/makinde/test2.html') )

chriddyp commented 6 years ago

@mankensin - These questions are not related to this particular PR. Please ask these questions on the community forum: https://community.plot.ly/c/dash

FarrandTom commented 6 years ago

Hey @chriddyp,

Any idea of a timeline on when this will be merged with the master branch?

This functionality is too good to pass up for my app!

Cheers, Tom!

chriddyp commented 6 years ago

Any idea of a timeline on when this will be merged with the master branch?

It's going to be a long time still. This PR is just a POC, to bring this into production will require a lot of deeper changes across Dash

FarrandTom commented 6 years ago

Ok 👌. Thanks for getting back to me, looks like a brilliant future feature!

On Feb 26, 2018 5:02 PM, "Chris Parmer" notifications@github.com wrote:

Any idea of a timeline on when this will be merged with the master branch?

It's going to be a long time still. This PR is just a POC, to bring this into production will require a lot of deeper changes across Dash

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/plotly/dash-table-experiments/pull/11#issuecomment-368572510, or mute the thread https://github.com/notifications/unsubscribe-auth/AfesU1bNQbMBYhbrS_p2MM2Et2hUmJKfks5tYuOagaJpZM4P7leg .

pbosavage commented 6 years ago

@chriddyp - I'm learning dash right now -- I'm very impressed and looking forward to what I can construct once proficient. I'm very interested in the Conditional Formatting example shown above. That particular feature would really help. I can't, however, get out of the gate when it comes to upgrading the packages. I've taken a working dash application that constructs a DTE DataTable to apply the conditional formatting to. I started by upgrading the packages -

pip install dash==0.19.0 pip install dash-core-components==0.16.0rc1 pip install dash-html-components==0.9.0rc1 pip install dash-renderer==0.13.0rc2 pip install dash-table-experiments==0.6.0rc1

Error: Minified React error #137; visit http://facebook.github.io/react/docs/error-decoder.html?invariant=137&args[]=br&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings. at r (react-dom.min.js:15) at o (react-dom.min.js:13) at h.mountComponent (react-dom.min.js:13) at Object.mountComponent (react-dom.min.js:14) at performInitialMount (react-dom.min.js:13) at p.mountComponent (react-dom.min.js:13) at Object.mountComponent (react-dom.min.js:14) at performInitialMount (react-dom.min.js:13) at p.mountComponent (react-dom.min.js:13) at Object.mountComponent (react-dom.min.js:14)

There are no errors on the application console. It seems like simply installing the new packages causes the problem. Are there other packages that need to be installed or upgraded that I am missing?

Thanks & regards,

Update - I found that I also get the following on the javascript console:

Refused to apply style from 'https://unpkg.com/dash-table-experiments@0.6.0rc1/dash_table_experiments/dash_table_experiments.css' because its MIME type ('text/plain') is not a supported stylesheet MIME type, and strict MIME checking is enabled.

@chriddyp - Is there anything new on this front? It would be a huge benefit.

rmarren1 commented 6 years ago

^ I am having the same problem, this seems only usable with app.css.config.serve_locally = True at the moment.

Pastryman commented 6 years ago

Hi! I have taken a look at the example code, but don't immediately see if this could be the solution to my problem. My situation is as follows:

Would this be possible?

udhayasankari commented 6 years ago

@chriddyp I was using this feature to add colors to cell based on values. I tried using the pre-release version specified by you as below.

pip install dash==0.19.0 pip install dash-core-components==0.16.0rc1 pip install dash-html-components==0.9.0rc1 pip install dash-renderer==0.13.0rc2 pip install dash-table-experiments==0.6.0rc1

Example given above works like charm. I would also need arguments in dash-table-experiments column_widths. Also enable_drag_and_drop isn't working in above versions.

But when I use dash-table-experiments==0.6.0 , column_widths and drap_and_drop features are working. But my color code is not rendering. Could

Is there any option to get both ? :(

nevenpiculjan commented 6 years ago

When I install dependencies written below, everything is rendered well inside the table cells and above table examples from the post work well, but that combination of dependencies makes plots not rendered well (lines are missing from the last plot in subplot).

pip install dash==0.19.0 pip install dash-core-components==0.16.0rc1 pip install dash-html-components==0.9.0rc1 pip install dash-renderer==0.13.0rc2 pip install dash-table-experiments==0.6.0rc1

When do you plan to make this part stable?

popohoma commented 6 years ago

Hi Chris,

I have followed your Conditional Formatting 100% in Python but it's giving me following error in IE.

Error Loading Dependencies

Is this related to my Python 3.6 version?

Thanks,

Allen

northcuttc52 commented 6 years ago

Hi Chris,

I am not able to set the column_widths=[] or use resizable=True for my DataTable. I have tried:

pip install dash-renderer==0.13.0rc2 pip install dash-table-experiments==0.6.0rc1

and

pip install dash-renderer==0.13.0 pip install dash-table-experiments==0.6.0

The later version of data-table-experiments lets me use the column_widths option, however, the columns aren't actually resized. I am rendering html.Div elements within the DataTable. I also started getting some dependency errors on the later versions above.

Really great stuff you guys are doing here!!

osmancakir commented 6 years ago

I am also having this 'Error loading Dependencies' problem as @popohoma. Aprreciate the effort loved your conditional formatting!

Edit : after retrying to install

pip install dash-core-components==0.16.0rc1 pip install dash-html-components==0.9.0rc1 pip install dash-renderer==0.13.0rc2 pip install dash-table-experiments==0.6.0rc1

it worked!

marknuzz commented 6 years ago

It seems like this feature is going to take a very long time. I need to have a straightforward way to detect a click or selection of a cell. Very simple. But I came across this post, which suggests that this feature needs to be done first? https://community.plot.ly/t/dash-datatable-support-for-click-events/7878

I'm open to any workarounds, suggestions, other Dash components, jQuery hacks, anything. But I think users should have the option to interact with a table.

Tasselmi commented 6 years ago

I have some problems in running the code above. THE code error is : "error loading layout". THERE is something wrong with your code . BUT i am new , i do not know where is wrong, crying......

bcliang commented 6 years ago

@Mnuzz once this feature is merged you'll be able to insert components (dcc, html) into each table cell. That means, for example, that navigation cells could be made using a component of type html.A and "clickable" cells could be made of the html.Button component.

something like the following ..

def prep_dataframe_for_datatable(dataframe):
    rows = []
    for i in range(len(dataframe)):
        row = dataframe.iloc[i].to_dict()
        row['Link'] = html.A('Link', href='/route/to/{}'.format(row['href'])) # assume there is a dataframe column named href
        rows.append(row)
    return rows

The recommendation was to use the class html.Button, which would require you to dynamically handle callbacks for the buttons. If html.A or dcc.Link would suffice that might be easier.

If you need this feature urgently, you could use the code from this PR directly. Just follow the pip install ... for the code versions listed above.

marknuzz commented 6 years ago

@bcliang You miss the point. This is essentially a major revision release, containing a very large amount of changes. My point was that there are common use cases which are not covered, such as selecting a row from a list. Very common use case. However, users are expected to wait for this major revision, which a large set of complex changes, many of which are out of scope for what most users are looking to do.

Sure, you could cover this common use case after the release. But this PR has been up for 10 months. I understand that it's a complex issue. But to put on indefinite hold, the fixes to address common use cases, especially if they are likely straightforward to implement in the current framework, is not something I understand.

I'm not even asking the dev team to implement the said fix. It's one thing to ask a user to submit a PR (and perhaps spending a couple extra minutes explaining the gist of how to implement a new event). It's an entirely different thing to tell the user "You'll have to wait until this 10 month PR is accepted. We don't know when it will be accepted, but sorry, you'll have to wait. But hey, you're welcome to use the unmerged code in the meantime!"

chriddyp commented 6 years ago

"You'll have to wait until this 10 month PR is accepted. We don't know when it will be accepted, but sorry, you'll have to wait. But hey, you're welcome to use the unmerged code in the meantime!"

I'm sorry there has been confusion with these types of prereleases. They are really targeted towards other Dash developers and serve as a way to get feedback about future, prototypical architectures. It's a way for us to explore the boundaries of Dash and to do so in a way that other community members can provide feedback on.

We're split our time about 70%-30% between engineering that has short-term improvements (see https://github.com/orgs/plotly/projects) and projects that are more theoretical and exploratory and push the boundaries of Dash and inform what Dash 2.0 would look like (like this original PR).

This PR likely won't actually get merged anytime soon, but it did a lot to inform me on some different possibilities and what community members would like out of a feature like this. Many aspects of this feedback has been incorporated into a new version of an interactive table component which we have been writing from scratch. These features include dropdowns inside cells, single and multi row selections, conditional formatting, cell and column formatting, data types in the table, and more. Thanks to some organizations that have sponsored the work, we are looking to release this towards the end of the month.

Again, I'm sorry to get people's hopes up by sharing these prototypes through exploratory pull requests like these. I'll try to do a better job in the feature of declaring up-front whether a PR is a candidate for immediate release or whether it is a candidate for feedback and discovery. In both cases, the community's feedback has been very helpful, and I really appreciate it. ❤️

marknuzz commented 6 years ago

Thanks @chriddyp that makes sense.

Harsha-Nori commented 6 years ago

Thanks for all your hard work @chriddyp! Will the upcoming interactive table component support sparklines to some degree (plotly graphs within cells)?

AsmitAdgaonkar commented 5 years ago

Thanks @chriddyp and team. Do we know if conditional formatting is released/merged yet ?

I am currently on dash 0.28.1 dash-core-components 0.30.2 dash-html-components 0.13.2 dash-renderer 0.14.1 dash-table-experiments 0.6.0

Let me know if you suggest a minor change/pull in any of the libraries to accommodate background color for dash datatable ?

alexcjohnson commented 5 years ago

Closing as this repo is deprecated in favor of dash-table. This feature still requires work on the dash-renderer side, but from the table side you can follow progress at eg https://github.com/plotly/dash-table/issues/292, https://github.com/plotly/dash-table/issues/222