Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Python expression in Viz elements more Pythonic in Python API #1379

Open
1 of 2 tasks
FlorianJacta opened this issue Jun 7, 2024 · 9 comments
Open
1 of 2 tasks
Assignees
Labels
💬 Discussion Requires some discussion and decision Gui: Back-End ✨New feature 🟧 Priority: High Must be addressed as soon 🔒 Staff only Can only be assigned to the Taipy R&D team

Comments

@FlorianJacta
Copy link
Member

FlorianJacta commented Jun 7, 2024

Description

Make Python expressions inside the Python API more Pythonic.

Markdown text is hard to debug, with no autocompletion, syntax coloring, etc. It is error-prone and is not easy to use when using for loops (see below).

for key in list_of_keys:
    tgb.text("{str(message['"+key+"'])}")
    # don't forget the ' otherwise this will not work, and Python autocompletion, correction won't help you
    # you cannot also use the " as it is already used; this is really error-prone and this is a simple expression

Solution Proposed

Use lambda function instead of Python inside Markdown text.

from taipy.gui import Gui 
import taipy.gui.builder as tgb
from math import cos, exp
import pandas as pd

value: int = 10
data: pd.DataFrame = compute_data(value)


def compute_data(decay:int)->pd.DataFrame:
    return pd.DataFrame({"Cos":[cos(i/6) * exp(-i*decay/600) for i in range(100)]})

def on_slider(state):
    state.data: pd.DataFrame = compute_data(state.value)

with tgb.Page() as page:
    tgb.text(value="Python")
    tgb.text(value="Taipy Demo", class_name="h1")
    tgb.text(value=lambda value: f"Value: {value}")
    tgb.slider(value="{value}", on_change=on_slider)
    tgb.chart(data=lambda data: data[:50], y="Cos") 

    with tgb.part(render=lambda value: value>=50) as page:
        tgb.table(lambda data: data.drop_na())


Gui(page=page).run(title="Frontend Demo")

A vast improvement is that you can tell Taipy which variables are interactive inside the lambda function, making creating this kind of code easy.

Current version:

for key in list_of_keys:
    tgb.text("{str(message['"+key+"'])}")
    # don't forget the ' otherwise this will not work, and Python autocompletion, correction won't help you
    # you cannot also use the " as it is already used; this is really error-prone

This is much better:

for key in list_of_keys:
    tgb.text(lambda message: str(message[key]))

message here is the bound variable of the Taipy expression, key is not and can be present in the state without a problem.

Impact of Solution

This could impact the product, but we should keep Python expressions inside Markdown as they are done now.

Code of Conduct

  • I have checked the existing issues.
  • I am willing to work on this issue (optional)
@FlorianJacta FlorianJacta added 🖰 GUI Related to GUI 🟨 Priority: Medium Not blocking but should be addressed ✨New feature 💬 Discussion Requires some discussion and decision labels Jun 7, 2024
@FredLL-Avaiga
Copy link
Member

we don't support function as variable
we do support function calls
How is this supposed to work ?

@FlorianJacta
Copy link
Member Author

You can introspect the variable names of the lambda function so you know data is a bound variable then call the function with the state variables bound to it.

I don't say it is possible now obviously.

@FlorianJacta
Copy link
Member Author

FlorianJacta commented Jun 7, 2024

A vast improvement is that you can tell Taipy which variables are interactive inside the lambda function, making it easy to create this kind of code.

Current version:

for key in list_of_keys:
    tgb.text("{str(message['"+key+"'])}")
    # don't forget the ' otherwise this will not work, and Python autocompletion, correction won't help you
    # you cannot also use the " as it is already used; this is really error-prone

This is much better:

for key in list_of_keys:
    tgb.text(lambda message: str(message[key]))

message here is the bound variable of the Taipy expression, key is not and can be present in the state without a problem.

This is a huge improvement in Taipy with the Python API, as I and users have encountered it frequently.

@FlorianJacta FlorianJacta added 🟧 Priority: High Must be addressed as soon and removed 🟨 Priority: Medium Not blocking but should be addressed labels Jun 21, 2024
@jrobinAV
Copy link
Member

I like the idea. It is less error-prone than coding into strings.

@jrobinAV jrobinAV added Gui: Back-End 🔒 Staff only Can only be assigned to the Taipy R&D team and removed 🖰 GUI Related to GUI labels Jun 21, 2024
@FredLL-Avaiga FredLL-Avaiga self-assigned this Jul 1, 2024
@FredLL-Avaiga
Copy link
Member

From what I understand, one would need to generate intermediate code that would look like:

message = {"aa": 1, "bb": 2}

for key in message:
    l_fn = lambda message: str(message[key])
    tgb.text(l_fn(message))

@FredLL-Avaiga
Copy link
Member

FredLL-Avaiga commented Jul 2, 2024

good news: we can support lambdas

`tgb.text(lambda message: str(message))`

Which will translate into the equivalent of

state.fn_x = lambda message: str(message))
<{fn_x(message)}|text|>

bad news: I don"t think there's a way that we can support using external variables in lambda (it works but it is always the last value that is used)

message = {"a": "value A", "b": "value B"}

for key in message:
    tgb.text(lambda message: str(message[key]))

Will render as

value B
value B

This because the render is not synchronous with the declaration ie at render time key's value is the last value it got.

In that case, I wonder if the lambda support is still interesting ?
@FabienLelaquais @FlorianJacta @jrobinAV

@FredLL-Avaiga
Copy link
Member

PS: I can push the code in a branch if someone wants to play with it

@FabienLelaquais
Copy link
Member

That's wonderful @FredLL-Avaiga.

The limitation is pretty bad though.
An investigation path would be to provide the generation function with the variable scope then lookup the variables in the locals... at build time.
That sounds a bit fuzzy at this point. The property value, defined as a function where are parameters would be state variables, would be partially bound at creation time...

@FredLL-Avaiga
Copy link
Member

I'm afraid we cannot render at build time :-(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💬 Discussion Requires some discussion and decision Gui: Back-End ✨New feature 🟧 Priority: High Must be addressed as soon 🔒 Staff only Can only be assigned to the Taipy R&D team
Projects
None yet
Development

No branches or pull requests

4 participants