How to keep a Dash datatable inside its container? - python

I have a Dash datatable inside a dbc.Col (which is inside a dbc.Row), and I can not figure out how to keep the table inside its container when the screen size is smaller (trying to make it responsive).
If the table is too big for its container, it should have a scroll bar, so I added overflowX:auto to its style, but it still won't work.
Right now it looks like this:
The code is something like:
dbc.Col(dt.DataTable(
id='tabla_req',
style_table={
'overflowX': 'auto',
'width':'100%',
'margin':'auto'},
row_deletable=False,
row_selectable="single",
page_current= 0,
page_size= 10,
fill_width=False,
style_data={
'whiteSpace': 'normal',
'height': 'auto',
},
#editable=False,
data=df.to_dict('records'),
columns=[{"name": i, "id": i} for i in df.columns.tolist()]),
width=12
)

I had similar issue, adding these parameter was helpful
virtualization=True

Related

update information cards with dash and csv

I have a problem, I create a dashboard with dash and python, the cards are fed with the information from a csv, when the information is updated in the file, the dashboard is not updated, if I go to the code and save changes in the code, the web is refreshed and at that moment if the card data is updated in the dashboard, I don't know how to do it.
dashboard
data.cant[4]
data.cant[4] is the variable that gets the data from the csv
#app.callback(
Output("page-content", "children"),
[Input("url", "pathname")]
)
def render_page_content(pathname):
if pathname == "/":
return [
html.A(html.Button('Refresh Page'),href='/'),
#html.H1('The time is: ' + str(datetime.datetime.now())),
html.Div([
#-----------------------
html.Div([
#---------------------
html.Div([
html.H6(children='New',
style={'textAlign': 'center',
'color': 'white',
'fontSize': 22,
'margin-top':'-5px'}),
html.H3("Vulnerabilities",
style={'textAlign': 'center',
'color': 'orange',
'fontSize': 20,
'margin-top':'-10px'}),
html.P(f"{data.cant[4]:,.0f}",
style={'textAlign': 'center',
'color': 'orange',
'fontSize': 60,
'margin-top':'-18px',
'margin-bottom':'-18px'}),
], className='tarjeta_dato two columns'),
], id= 'contenedorMain', style={'display': 'flex', 'flex-direction': 'column' })
]
status.csv
type,status,cant
vul,active,201
I need the information on the dashboard to be updated when the csv information changes
I found that a parameter should be used within the callback but no matter how much I tried or managed to make it work
dcc.Interval(
id='graph-update',
interval=1*1000
),
I understand that this is for graphics not information cards like the ones I have
I also read that you could use something like use_reloader as a parameter but it doesn't work, thanks for your attention

Adjusting the MaxHeight of a Table in Dash Tables Python

I'm trying to adjust the height of a data table in Dash and it should be pretty straight forward, however no matter what I've tried for a value here, it just keeps outputing all available values.
IF anyone has any ideas it'd be so appreciated.
I've tried both maxHeight and height, i've tried using the number and the string representation of that number, i've tried numbers from 0 to 100, i've even tried restarting my computer.
app = dash.Dash()
app.layout = html.Div([dash_table.DataTable(id='raw_data',
data=[],
style_table={
'maxHeight': '5',
'overflowY': 'scroll',
}
),
dcc.Interval(id='interval_component',
interval=60000,
n_intervals=0
)
])
try
{"selector": ".dash-spreadsheet-inner",
"rule":'max-height: "calc(100vh - 226px)"'}],
sometimes it helps
Update
#Ricardo M S
The solution i found is here: Dash components follow the .css rules
In the assets folder of your dash app create a .css file
any name .css
my .css file string about table is:
/* высота таблицы Dash DataTable*/
.dash-spreadsheet.dash-freeze-top, .dash-spreadsheet.dash-virtualized
{ max-height: inherit !important; }
.dash-table-container {max-height: calc(100vh - 225px);}
/*makes the height of the DashTable 225 pix less then the 100% screen */
Cheers
I had the same problem. Adding:
fixed_rows={ 'headers': True, 'data': 0 }
worked for me. In your case:
app.layout = html.Div([
dash_table.DataTable(
id='raw_data',
data=[],
fixed_rows={ 'headers': True, 'data': 0 },
),
dcc.Interval(id='interval_component',
interval=60000,
n_intervals=0
)
])
You can adjust the max-height of rows using css property of the DataTable and use the selector and rule keys to define Custom CSS Rules.
Example:
dash_table.DataTable(
id='raw_data',
data=[],
css=[{"selector": ".dash-table-container tr",
"rule":'max-height: "15px"; height: "15px"; '}])
You have used a string for the maximum height.
'maxHeight': '5',
Also: 5 is probably 5 pixels.
Try instead
'maxHeight': '500',

Dash dataTable conditional cell formatting isn't working

I want to change a color of a cell of a Dash dataTable based on a value. I have tried a minimal example:
html.Div(
children=[
dash_table.DataTable(
id='table_1',
data=df.to_dict('records'),
columns=[{"name": i, "id": i} for i in df.columns],
#conditional cell formating
style_data_conditional=[
{
'if': {
'column_id': 'col1',
'filter': 'col1 > num(15)'
},
'backgroundColor': '#3D9970',
'color': 'white',
},
],
n_fixed_rows=2,
filtering=True,
sorting=True,
sorting_type="multi"
)],
)
After adding the style_conditional, the table is not showing at all, and there is no error message thrown. The table is embedded in html component, and after looking into forums and on github, I am stiil not sure if I have missed anything here, and if I need to write a callback for this. The example provided in the mentioned tutorial is not suggesting the need for a callback.
Update:
Tried to run minimal version with the same code and different data, with same results, that is no change in cell colors. My libraries are up to date, but something in the environment may still be causing problems.
Full code:
import dash
import dash_table
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/solar.csv')
# Having trouble with conditional when column name has spaces
df = df.rename({'Number of Solar Plants': 'Plants'}, axis='columns')
app = dash.Dash(__name__)
app.layout = dash_table.DataTable(
id='table',
columns=[{"name": i, "id": i} for i in df.columns],
style_data_conditional=[{
"if": {'column_id': 'State',
'filter': 'State eq "Nevada"'
},
"backgroundColor": "#3D9970",
"color": "white"
}],
data=df.to_dict('records'),
)
if __name__ == '__main__':
app.run_server(debug=True)
I do not think you will need a callback for this like said in the tutorial. According to the last example of the tutorial I think you have a typo (one ' to much).
Change this line
'filter': 'col1' > num(15)'
to:
'filter': 'col1 > num(15)'
I had the same issue and i found that giving the index directly rather than a condition was a lot easier.
style_data_conditional = [{'if': {'column_id': 'col1',"row_index": x},'backgroundColor': '#3D9970','color': 'white'} for x in df[df['col1']>15].index ]
it's ugly as it has been hard coded but it did the trick for me when the direct filter did not.
I don't know how it was back in 2019, but with recent releases of Dash Datatables:
Column names in filter expressions must be wrapped in curly braces
filter has been renamed to filter_query
style_data_conditional=[{
"if": {
'column_id': 'State',
'filter_query': '{State} eq "Nevada"'
# ^ ^ <-- required braces
},
"backgroundColor": "#3D9970",
"color": "white"
}]
BTW: You can conveniently highlight the entire row by removing the column_id line.

Dash: Creating a dropdown per column, instead of a dropdown per table

I have a data set that looks like this:
cat_id author year publisher country value (dollars)
name1 kunga 1998 D and D Australia 10
name2 siba 2001 D and D UK 20
name3 siba 2001 D and D US 20
name3 shevara 2001 D and D UK 10
name3 dougherty 1992 D and D Australia 20
name4 ken 2011 S and K Australia 10
The aim, to produce a Multi-Select Dropdown menu PER COLUMN, not of all columns (because the per-column filter that i currently do is not sufficient, I need to be able to filter by multiple items per column in one go).
Using the above example, this would add a cell just under cat_id with name1,2,3,4; author would have a dropdown with kunga, siba, shevara and dougherty; year would have a dropdown with 1992,1998,2001,2011 etc.
I wrote the below code:
import dash
from dash.dependencies import Input, Output, State
import dash_table
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
app = dash.Dash(__name__)
df = pd.read_excel('dash_test_doc.xlsx')
app.layout = html.Div([
html.Div([
dcc.Input(
id='adding-rows-name',
placeholder='Enter a column name...',
value='',
style={'padding': 10},),html.Button('Add Column', id='adding-rows-button', n_clicks=0)], style={'height': 50}),
#Need to move this to being within each column?
html.Label('Multi-Select Dropdown'),
dcc.Dropdown(options=[{'label':i,'value':i} for i in df.columns],
value = [i for i in df.columns],
multi=True),
dash_table.DataTable(
id='adding-rows-table',
columns=[{"name": i, "id": i,"deletable":True} for i in df.columns],
# column_conditional_dropdowns=[{'id':i,'dropdowns':df[i]} for i in df.columns],
data = df.to_dict('rows'),
editable=True,
filtering=True,
sorting=True,
sorting_type="multi",
row_selectable="multi",
row_deletable=True,
selected_rows=[],
pagination_mode="fe",
style_cell_conditional=[
{
'if': {'row_index': 'odd'},
'backgroundColor': 'rgb(230, 255, 230)'
}
] + [
{
'if': {'column_id': c},
'textAlign': 'left'
} for c in ['Date', 'Region']
],
style_header={
'backgroundColor': 'white',
'fontWeight': 'bold'
}
),
html.Button('Add Row', id='editing-rows-button', n_clicks=0),
dcc.Graph(id='adding-rows-graph')
])
#app.callback(
Output('adding-rows-table', 'data'),
[Input('editing-rows-button', 'n_clicks')],
[State('adding-rows-table', 'data'),
State('adding-rows-table', 'columns')])
def add_row(n_clicks, rows, columns):
if n_clicks > 0:
rows.append({c['id']: '' for c in columns})
return rows
#app.callback(
Output('adding-rows-table', 'columns'),
[Input('adding-rows-button', 'n_clicks')],
[State('adding-rows-name', 'value'),
State('adding-rows-table', 'columns')])
def update_columns(n_clicks, value, existing_columns):
if n_clicks > 0:
existing_columns.append({
'id': value, 'name': value,
'editable_name': True, 'deletable': True
})
return existing_columns
#app.callback(
Output('adding-rows-graph', 'figure'),
[Input('adding-rows-table', 'data'),
Input('adding-rows-table', 'columns')])
def display_output(rows, columns):
return {
'data': [{
'type': 'heatmap',
'z': [[row.get(c['id'], None) for c in columns] for row in rows],
'x': [c['name'] for c in columns]
}]
}
if __name__ == '__main__':
app.run_server(debug=True)
There are two specific issues with this method:
The dropdown is being done at the table level, not the per-column level.
I want to then filter the table to only display what is in the dropdown bar, which is currently not being done.
I know that the parts of the code that are the issue are:
#Need to move this to being within each column?
html.Label('Multi-Select Dropdown'),
dcc.Dropdown(options=[{'label':i,'value':i} for i in df.columns],
value = [i for i in df.columns],
multi=True),
and that there is no callback, but I'm new to dash, and I'm struggling to understand what specifically I should do. If someone could show me how to fix these two issues in this code, I would appreciate it.
As a side note/disclaimer, I had originally asked this question as part of a much bigger question here, but I have realised that I need to make my questions more code-specific, and more specific in general, so I'm going to work through each issue individually.
Thanks, Kela, for making this question a little more specific. This still a good size bite, so I'll see if I can help with all of it.
First thing is you need to change the column defintion in the table to have 'presentation': 'dropdown' in the dictionary for each column you want to show up as a dropdown. The current dropdown isn't working inside the table because you've used the dcc.Dropdown component, which is a separate component from the table. You'll need to use column_static_dropdown or column_conditional_dropdowns (which I see you've commented out) if you want them to work inside the table.
I'm not sure that the dropdowns inside the table can be used as part of a callback, though. I tried to hook one up, and the ID of the dropdown was not recognized as part of the layout. To do what you want would - I think - require setting up multiple dropdowns using dcc.Dropdown and hooking those values up as input to the callback that updates the table's data prop.
Here is a little example that I've confirmed works, with some limitations:
app = dash.Dash(__name__)
df = pd.DataFrame(np.arange(30).reshape(5, 6))
app.layout = html.Div([
html.Div([
dcc.Input(
id='adding-rows-name',
placeholder='Enter a column name...',
value='',
style={'padding': 10}, ),
html.Button('Add Column', id='adding-rows-button', n_clicks=0)], style={'height': 50}),
# Need to move this to being within each column?
html.Label('Multi-Select Dropdown'),
dcc.Dropdown(
id='test-dropdown',
options=[{'label': i, 'value': i} for i in df[0]],
value=[i for i in df[0]],
multi=True),
dash_table.DataTable(
id='adding-rows-table',
columns=[{"name": i, "id": i, "deletable": True} for i in df.columns],
data=df.to_dict('rows'),
editable=True,
filtering=True,
sorting=True,
sorting_type="multi",
row_selectable="multi",
row_deletable=True,
selected_rows=[],
pagination_mode="fe",
style_cell_conditional=[
{
'if': {'row_index': 'odd'},
'backgroundColor': 'rgb(230, 255, 230)'
}
] + [
{
'if': {'column_id': c},
'textAlign': 'left'
} for c in ['Date', 'Region']
],
style_header={
'backgroundColor': 'white',
'fontWeight': 'bold'
}
),
html.Button('Add Row', id='editing-rows-button', n_clicks=0),
dcc.Graph(id='adding-rows-graph'),
])
#app.callback(
Output('adding-rows-table', 'data'),
[Input('editing-rows-button', 'n_clicks'),
Input('test-dropdown', 'value')],
[State('adding-rows-table', 'data'),
State('adding-rows-table', 'columns')])
def add_row(n_clicks, dropdown_value, rows, columns):
if n_clicks > 0:
rows.append({c['id']: '' for c in columns})
df = pd.DataFrame.from_dict(rows)
try:
df_filtered = df[df['0'].isin(dropdown_value)]
except TypeError:
df_filtered = df[df['0'].eq(dropdown_value)]
return df_filtered.to_dict(orient='records')
There is only one dropdown right now, and it works with the values in the first column. You would need to add more, and it would get complicated quickly. You could probably style the dropdowns so they're more clearly associated with the related columns .
There is also the problem of what to do with rows once you've filtered them out. The callback pulls in the State data from the table but, if a row was filtered out, then it's not in the state and can't be added back in by making that selection in the dropdown again. You would need a different way to handle storing the data for the table so that rows aren't erased this way.

Is there a python plotly/dash image widget that can render numpy array data?

I'm in the process of evaluating python plotly and/or dash as an alternative to bokeh/holoviews for linked plots that update images.
Requirements:
linking data point to image:
I have scatter plots and heatmaps in which individual data points represent values derived from images. I would like to link back from a data point in a scatterplot to the image that the numerical value for this data point was derived from.
The image data is in a numpy array or can be provided by a callback function. I would like to avoid writing a .png file to disk and embedding the png file in a html element.
linking image selections to data points:
e.g. Display an image. Update a plot according to the selection in the image (e.g. a simple histogram).
However, I can't seem to find any widget for image display in plotly/dash. Am I missing something or is there really no such thing?
I would like to link back from a data point in a scatterplot to the image that the numerical value for this data point was derived from.
See https://plot.ly/dash/interactive-graphing. You can assign a callback to selectedData, hoverData, or clickData property of the dash_core_components.Graph.
linking image selections to data points: e.g. Display an image. Update a plot according to the selection in the image (e.g. a simple histogram).
You could display a background image on a plotly graph and then use the same selectedData tools to update callbacks based off of the selected region. Here is a simple example:
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import base64
import json
app = dash.Dash()
app.css.append_css({'external_url': 'https://codepen.io/chriddyp/pen/dZVMbK.css'})
RANGE = [0, 1]
def InteractiveImage(id, image_path):
encoded_image = base64.b64encode(open(image_path, 'rb').read())
return dcc.Graph(
id=id,
figure={
'data': [],
'layout': {
'xaxis': {
'range': RANGE
},
'yaxis': {
'range': RANGE,
'scaleanchor': 'x',
'scaleratio': 1
},
'height': 600,
'images': [{
'xref': 'x',
'yref': 'y',
'x': RANGE[0],
'y': RANGE[1],
'sizex': RANGE[1] - RANGE[0],
'sizey': RANGE[1] - RANGE[0],
'sizing': 'stretch',
'layer': 'below',
'source': 'data:image/png;base64,{}'.format(encoded_image)
}],
'dragmode': 'select' # or 'lasso'
}
}
)
app.layout = html.Div([
html.Div(className='row', children=[
html.Div(InteractiveImage('image', 'dash_app.png'), className='six columns'),
html.Div(dcc.Graph(id='graph'), className='six columns')
]),
html.Pre(id='console')
])
# display the event data for debugging
#app.callback(Output('console', 'children'), [Input('image', 'selectedData')])
def display_selected_data(selectedData):
return json.dumps(selectedData, indent=2)
#app.callback(Output('graph', 'figure'), [Input('image', 'selectedData')])
def update_histogram(selectedData):
x_range = selectedData['range']['x']
x_range = selectedData['range']['y']
# filter data based off of selection in here
# for simple example purposes, we'll just display the selected RANGE
return {
'data': [{
'x': x_range,
'y': x_range,
'mode': 'markers',
'marker': {
'size': 20
}
}],
'layout': {
'xaxis': {'range': RANGE},
'yaxis': {'range': RANGE, 'scaleanchor': 'x', 'scaleratio': 1},
'height': 600
}
}
if __name__ == '__main__':
app.run_server(debug=True)
If you are still interested in the answer:https://plotly.com/python/imshow/, if you scroll to the bottom, you will see how to apply it to Dash

Categories