Flet's DataTable has a show_edit_icon property, but I don't know how do something when the icon is pressed.
This is an example code:
import flet as ft
def main(page: ft.Page):
page.add(
ft.DataTable(
columns=[
ft.DataColumn(ft.Text("First name")),
ft.DataColumn(ft.Text("Last name")),
],
rows=[
ft.DataRow(
cells=[
ft.DataCell(ft.Text("John"), show_edit_icon=True),
ft.DataCell(ft.Text("Smith")),
],
),
],
),
)
ft.app(target=main, view=ft.WEB_BROWSER)
I see the edit icon, but how do I connect it to some function that receives the cell that is being edited?
As per the doccumentation, In FLET data table, show_edit_icon This will only enable you to see the cell's icon. nonetheless, You must create a new function and connect it to the cell on on_tap functionality.
Note:
Add property on_tap to the the cell
implement a new function
Update the page after change inside the new function
import flet as ft
def main(page: ft.Page):
# this is the function that controls the value of the cell
# returns value on tap
def updateOnTap(e):
e.control.content.value = "Hello John"
page.update()
page.add(
ft.DataTable(
columns=[
ft.DataColumn(ft.Text("First name")),
ft.DataColumn(ft.Text("Last name")),
],
rows=[
ft.DataRow(
cells=[
ft.DataCell(ft.Text("John"), show_edit_icon=True, on_tap=updateOnTap),
ft.DataCell(ft.Text("Smith")),
],
),
],
),
)
ft.app(target=main, view=ft.WEB_BROWSER)
Related
How can I process when I have 2 callbacks functions with the same output (in that case : a graph) knowing that the first callback function returns a graph and a slider, whereas the input of 2nd callback function is the value of the new slider (created thanks to the first slider ) and returns also a graph (by adding new traces on the old traces)
The code is like that :
# Create Div to place a conditionally visible element inside
myslider = html.Div(
id='slider-container',
children=[
# Create a slider to hide/show
dcc.Slider(0,5,
step=1,
value=0,
id="newslider"
)
],
hidden=True,
)
mygraph = html.Div(dcc.Graph(id="graph", figure=go.Figure(go.Scattergeo())))
mydropdown = html.Div(dcc.Dropdown(['NYC', 'MTL', 'SF'], id="dropdown",
multi=True,
clearable=False))
layout = dbc.Container([mydropdown, mygraph, myslider,html.Div(id='slider-output-container',hidden=True)])
#app.callback(Output(component_id='graph', component_property='figure'),
Output(component_id='newslider', component_property='max'),
Output("newslider", "marks"),
Output(component_id='slider-container', component_property='hidden'),
Input(component_id='dropdown', component_property='value'),
Input(component_id='timeslider', component_property='value'),
State(component_id='newslider', component_property='max'),
State("newslider", "marks"),
prevent_initial_call=True
)
def create_graph_and_slider(dropdown,value,maxi,marks):
#created the initial traces of the graph associated to the newslider thanks to the value of dropdown
return fig, maxi, marks, False
#app.callback(Output(component_id='slider-output-container', component_property='children'),
Output(component_id='slider-output-container', component_property='hidden'),
Output(component_id='graph', component_property='figure'),
Input(component_id='newslider', component_property='value'),
prevent_initiall_call=True
)
def update_graph_from_extrapolation_slider(value):
#add new traces in the graph thanks to the value of new slider
return 'You have selected "{}"'.format(value), False, fig
I created a form with Ipywidget, but got some problems to "link" the chosen drop-down option with the "naïve" function f1.
import warnings
warnings.filterwarnings('ignore')
from ipywidgets import Layout, Button, Box, FloatText, Textarea, Dropdown, Label, IntSlider, widgets
form_item_layout = Layout(
display='flex',
flex_flow='row',
justify_content='space-between'
)
form_items = [
Box([Label(value='Material 1'),
Dropdown(options=crude.columns)], layout=form_item_layout),
Box([Label(value='Material 2'),
Dropdown(options=refinery['Material'].unique())], layout=form_item_layout)
]
form = Box(form_items, layout=Layout(
display='flex',
flex_flow='column',
border='solid 2px',
align_items='stretch',
width='30%'
))
def f1(material):
print(material)
w = interact(f1, material=form._trait_values['children'][1])
display(w)
I've been trying to open the methods and attributes, but got no success for while...
How can I put the selected box' item into the function?
I have a 2D plotly graph with a hover feature. When you hover over each point, the label (e.g. 'image 2, cluster 1') associated with that point appears. I'd like for label to be appended onto an existing list if I were to click on the point (rather than just hover over it). The reason why is that I'd later like to use the data of this point to perform another task. Is there an example online that demonstrates how to do this-- have looked through the documentation but haven't found something for this yet. Thanks!
The hoverData that is available to you by default, with some sample data, is this:
{
"points": [
{
"curveNumber": 1,
"pointNumber": 7,
"pointIndex": 7,
"x": 1987,
"y": 74.32,
"bbox": {
"x0": 420.25,
"x1": 426.25,
"y0": 256,
"y1": 262
}
}
]
}
I'm not quite sure what you mean by 'label', so I can only assume that it would be the name of a trace or something similar, like in this example from the Plotly docs:
But as you can see, that's not readily available in the hoverData dict. This means that you'll have to use this information to reference your figure structure as well, so that you end up with something like this:
[['New Zealand', 2002, 79.11]]
And that's not a problem as long as you're willing to use Plotly Dash. I've made a complete setup for you that should meet your requirements. In the app in the image below you'll find a figure along with two output fields for strings. The first field shows the info from that last point you've clicked in the figure. On every click, a new element is added to a list named store. The last fields shows the complete information from the same click.
The answer to your question is, yes, there is a way to save the data of a clicked point in a list. And one way to do so is through the following callback that uses clickdata to reference your figure object, store those references in a list, and append new elements every time you click a new element.
App
Complete code:
import json
from textwrap import dedent as d
import pandas as pd
import plotly.graph_objects as go
import numpy as np
import dash
from dash import dcc
import dash_html_components as html
import plotly.express as px
from dash.dependencies import Input, Output
from jupyter_dash import JupyterDash
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
# app info
app = JupyterDash(__name__)
styles = {
'pre': {
'border': 'thin lightgrey solid',
'overflowX': 'scroll'
}
}
# data
df = px.data.gapminder().query("continent=='Oceania'")
# plotly figure
fig = px.line(df, x="year", y="lifeExp", color="country", title="No label selected")
fig.update_traces(mode="markers+lines")
app.layout = html.Div([
dcc.Graph(
id='figure1',
figure=fig,
),
html.Div(className
='row', children=[
html.Div([
dcc.Markdown(d("""Hoverdata using figure references""")),
html.Pre(id='hoverdata2', style=styles['pre']),
], className='three columns'),
html.Div([
dcc.Markdown(d("""
Full hoverdata
""")),
html.Pre(id='hoverdata1', style=styles['pre']),
], className='three columns')
]),
])
# container for clicked points in callbacks
store = []
#app.callback(
Output('figure1', 'figure'),
Output('hoverdata1', 'children'),
Output('hoverdata2', 'children'),
[Input('figure1', 'clickData')])
def display_hover_data(hoverData):
if hoverData is not None:
traceref = hoverData['points'][0]['curveNumber']
pointref = hoverData['points'][0]['pointNumber']
store.append([fig.data[traceref]['name'],
fig.data[traceref]['x'][pointref],
fig.data[traceref]['y'][pointref]])
fig.update_layout(title = 'Last label was ' + fig.data[traceref]['name'])
return fig, json.dumps(hoverData, indent=2), str(store)
else:
return fig, 'None selected', 'None selected'
app.run_server(mode='external', port = 7077, dev_tools_ui=True,
dev_tools_hot_reload =True, threaded=True)
You need to use callbacks to perform this type of action (register on_click()). Have defined clicked as a list of clicked points. Demonstrated how this can be achieved with ipwidgets or dash
ipwidgets
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
import ipywidgets as widgets
from pathlib import Path
import json
x = np.random.uniform(-10, 10, size=50)
y = np.sin(x)
clicked = []
# construct figure that has holders for points, interpolated line and final lines
fig = go.FigureWidget(
[
go.Scatter(x=x, y=y, mode="markers", name="base_points"),
]
)
fig.update_layout(template="simple_white")
out = widgets.Output(layout={"border": "1px solid black"})
out.append_stdout("Output appended with append_stdout\n")
# create our callback function
#out.capture()
def base_click(trace, points, selector):
global clicked
clicked.append(points.__dict__)
fig.data[0].on_click(base_click)
widgets.HBox([fig, out])
dash
from jupyter_dash import JupyterDash
import dash
from dash.dependencies import Input, Output, State
import numpy as np
import json
clicked = []
# Build App
app = JupyterDash(__name__)
app.layout = dash.html.Div(
[
dash.dcc.Graph(
id="fig",
figure=go.Figure(go.Scatter(x=x, y=y, mode="markers", name="base_points")),
),
dash.html.Div(id="debug"),
]
)
#app.callback(
Output("debug", "children"),
Input("fig", "clickData"),
)
def point_clicked(clickData):
global clicked
clicked.append(clickData)
return json.dumps(clickData)
# Run app and display result inline in the notebook
app.run_server(mode="inline")
I have a navbar where i want the links in the center. I have them now on the right using classname 'ml-auto' but i cant' manage them to move to the center. Anyone who can help? Below my code.
nav_item = dbc.Nav(
[
dbc.NavItem(dbc.NavLink("World Map", active= True, href="/page-1")),
dbc.NavItem(dbc.NavLink("Table", active= True, href="/page-2")),
dbc.NavItem(dbc.NavLink("Moran's l", active= True, href="/page-3")),
dbc.NavItem(dbc.NavLink("Scatter Plots", active= True, href="/page-4"))
],
fill= True
)
navbar = dbc.Navbar(
[
html.A(
# Use row and col to control vertical alignment of logo / brand
dbc.Row(
[
dbc.Col(html.Img(src= oord_logo, height="100px"), className="ml-5"),
],
align="center",
no_gutters=True,
),
href="https://plot.ly",
),
dbc.NavbarToggler(id="navbar-toggler"),
dbc.Nav([nav_item], navbar=True, className="ml-auto",)
],
color="white",
dark=False,
className = "mb-5"
)
Use mr-auto instead of ml-auto.
With mr-auto you get margin on the right. This is what you want since you want the element with this class (the Nav component) displayed on the left.
Unrelated to the problem, but you nest one Nav component in another which seems unnecessary. Also you've put the NavbarToggler component in the middle which means the hamburger button generated by this component will also be displayed in the middle.
I've started learning Dash(after using R-Shiny for ~3months). During which I've tried to make an app, which will have two Sliders, one of whose values(min, max, step) are fixed and values of the other Slider will be updated based on the input from first Slider. And I couldn't update values of second Slider.
Here's what I've done and tried:
from dash import Dash
import dash_html_components as dash_html
import dash_core_components as dash_core
from dash.dependencies import Input, Output
from flask import Flask
# initiate the dash app with Flask server
app = Dash(__name__, server=Flask(__name__))
# code the ui now
app.layout = dash_html.Div(children=[
dash_core.Slider(id="first_slider",
min=10, max=110, value=10, step=10,
marks={i : '{}'.format(i) for i in range(10,110,10)},
# marks={i : 'Level {}'.format(i) for i in range(10,110,10)}
),
dash_html.Hr(), dash_html.Hr(),
# second slider
dash_core.Slider(id="second_slider"),
# # dash_html.Hr(),
# print values from both sliders
dash_html.Div(id="display_selected_values"),
])
# take the input from first and update second slider
#app.callback(Output(component_id='second_slider', component_property=['min','max']),
# component_property='children'),
# component_property='value'),
[Input(component_id='first_slider', component_property='value')])
def print_the_value_from_slider(value_from_slider):
# update the values of second slider. ex: if input is 10, second slider will have 11 to 20
# return value_from_slider
return list((value_from_slider+1, value_from_slider+1+10))
# #app.callback(Output(component_id="second_slider", component_property='options'),
# [Input(component_id='second_slider', component_property='value')])
# def fill_second_slider(value_from_first_slider):
# return range(value_from_first_slider+1, value_from_first_slider+1+10, 1)
# #app.callback(Output('display_selected_values', 'children'),
# [Input('first_slider', 'value'),
# Input('second_slider', 'value')])
# def set_display_children(first_input, second_input):
# return '{} from {}s range'.format(second_input, first_input)
if __name__ == '__main__':
app.run_server(debug=True)
and the error is:
dash.exceptions.NonExistentPropException:
Attempting to assign a callback with
the property "['min', 'max']" but the component
"second_slider" doesn't have "['min', 'max']" as a property.
Here are the available properties in "second_slider":
['id', 'marks', 'value', 'className', 'disabled', 'dots', 'included', 'min', 'max', 'tooltip', 'step', 'vertical', 'updatemode', 'loading_state']
But, Slider does have min and max properties and they are listed in error too. I don't know what I'm doing wrong. But, the second slider is not getting updated.
The slider does have the min and max props, but you are trying to set a single prop [min, max] which does not exist. You need two outputs on your callback, one to each prop.
#app.callback([Output(component_id='second_slider', component_property='min'),
Output(component_id='second_slider', component_property='max')]
[Input(component_id='first_slider', component_property='value')])
That should work.