Announcing Dash Bio 1.0.0 🎉 : a one-stop-shop for bioinformatics and drug development visualizations.

Can Dash chained callback inputs be a file or filename?

After a day of researching how to ensure my functions execute in the right sequence, I have realized Dash really is not designed to run applications, though it makes powerful interactive graphics and dashboards.

Apparently, the only way to execute my functions in the proper order is to chain them together with “chained callbacks” via Input/Outputs. In other words, the Output of one function triggers the execution of the next function provided it is the input of the next function. That is my current understanding at least. If not, I stand corrected.

In my case, those Inputs/Outputs are text files.

One function creates a text file the next function needs to perform its duties. This is true until the application produces an editable graph for the user to edit/approve before final processing. Dash does not seem designed for this sort of process. There does not seem to be a way to use files or filenames as the Input or Output of a callback. Even if this were possible, there are other steps along the way that seem to defy Dash logic.

I hope I am wrong. I would love to be wrong, but I don’t want to waste more time. If I am wrong, how can I use chained callbacks to force my functions to trigger in sequence given that the Inputs are text files. Is that possible?

Can you please provide an example?

Thank you.

Hi @robertpfaff

Could you provide more information about your goal?
I do not understand what is the issue that you can avoid, how is the process and the interaction with the user or any axpalnation that can clarify the problem you are facing.

1 Like

I agree with @Eduardo that it is not complete clear what your issue is. If the process is fixed, I guess you could to all the work in a single callback? If user interaction is needed between the steps, you would of course need to use multiple callbacks. But a clear outline of the desired control flow would make it easier for people to help.

2 Likes

I would love to. Thank you for reaching out.

The code below produces this error message:

 "File "C:\Users\rober\ings\clean_recipe_text.py", line 14, in clean_recipe_text        
    with open("temp/fraction_free_recipe.txt", "r", encoding='utf-8') as decimal_recipe:
FileNotFoundError: [Errno 2] No such file or directory: 'temp/fraction_free_recipe.txt' 
PS C:\Users\rober\ings> "

Fraction_free_recipe is the next to last text file produced by this series of functions.

The first function works fine. It produces the text file “recipe_contents.txt,” but the chain-of-events ends there.

The second function depends on_recipe_contents.txt to produce vulgar_free_recipe.txt (with vulgar meaning unicode).

The third function depends on vulgar_free to produce fraction_free_recipe.txt. The fourth functions depends on fraction_free, meaning all fractions and preceding integers - if they exist - are now converted into decimals.

There just are not any videos or examples in the docs with comparable requirements. And I have reviewed as many as possible, dozens at this point. I would appreciate some instruction on how to proceed. I should note I imported the Python code for convert_unicode_fractions(), convert_regular_fractions() and clean_recipe_text() from modules I wrote that work fine in other contexts. Any constructive feedback would be greatly appreciated.

Thank you.

app = dash.Dash(__name__)

app.layout = html.Div([

    dcc.Textarea(

        id='textarea-state-example',

        value='',

        style={'width': '100%', 'height': 200},

        placeholder='Please note: Information inside brackets or parantheses will be deleted.'

    ),

    html.Button('Submit', id='textarea-state-example-button', n_clicks=0),

    html.Div(id='textarea-state-example-output',

             style={'whiteSpace': 'pre-line'})

])

@app.callback(

    Output('textarea-state-example-output', 'children'),

    Input('textarea-state-example-button', 'n_clicks'),

    State('textarea-state-example', 'value')

)

def update_recipe(n_clicks, value):

    if n_clicks > 0:

        with open("temp/recipe_contents.txt", "w", encoding='utf-8') as recipe_contents:

            recipe = value.split('\n')

            for line in recipe:

                print(line)

                recipe_contents.write(line)

                recipe_contents.write('\n')

            return "Recipe contents written to file."

@app.callback(

    Output('textarea-state-example-output', value='vulgar_free_recipe.txt'),

    Input('textarea-state-example-output', 'children'),

)

def convert_unicode_fractions():

    if os.path.exists('temp/recipe_contents.txt'):

        print("Recipe_contents.txt exists.")

        print("Now converting unicode fractions to decimals.")

        unicode_fractions = convert_unicode_fractions()

        print("Output: Convert Unicode Fractions")

        print(unicode_fractions())

        print(" ")

        return "Recipe cleared of unicode fractions."

@app.callback(

    Output('textarea-state-example-output', value='fraction_free_recipe.txt'),

    Input('textarea-state-example-output', value='vulgar_free_recipe.txt'),

)

def convert_regular_fractions():

    if os.path.exists('temp/vulgar_free_recipe.txt'):

        print("Vulgar_free_recipe.txt exists")

        common_fractions = convert_regular_fractions()

        print("Output: Convert Unicode Fractions")

        print(common_fractions())

        print(" ")

        return "Recipe cleared of regular fractions."

@app.callback(

    Output('textarea-state-example-output', value='prepared_recipe.txt'),

    Input('textarea-state-example-output', value='fraction_free_recipe.txt'),

)

def clean_recipe_textacy():

    if os.path.exists('temp/fraction_free_recipe.txt'):

        print("Fraction_free_recipe.txt exists")

        clean_text = clean_recipe_text()

        print("Output: Clean Recipe Text")

        print(clean_text())

        print(" ")

        print("Recipe text cleaned by textacy.")

        return "Text prepared for NLP tagging."

if __name__ == '__main__':

    app.run_server(debug=True)

Please see my response to Eduardo and thanks for reaching out.

Hey @robertpfaff, please read this post that explains how to get more answers from the Community members:

Do not expect that others will try to review your code trying to understand your issue. :smiley:

1 Like

I really do not appreciate this. His response asked for a clear outline of the problem, the desired flow of events. I did that and I included the code in case he wanted greater detail. I have also reviewed dozens of questions and responses from others on this forum that delve deeply into the code. Many of them involve requests from staff for that code, and that at least seemed to be what he wanted. My response was polite and thorough. I don’t expect anyone to do my work, and that’s why I did not include it in the first round. I do not need your input at all. I certainly don’t need lessons in online etiquette.

And I should stop now before I commit a violation.

Ok. have a nice day :grinning:

My first question on this forum and it involved multiple exchanges with staff and detailed discussion about code. There is more code shared and discussed in this exchange as in the response that bothers you.

@robertpfaff I am not staff. I am just a developer using some of my spare time to answer questions. My intention was only to help you towards solving your issue :slight_smile:

1 Like

I am only explaining why I shared that much code. I have no way of knowing whether you are staff or not, not to my knowledge. I appreciate your reaching out, but I don’t want to impose.

Hey @robertpfaff, we are all Dash users that takes time trying to help others, specially new Dash users, do not take our answers as “lessons of online etiquette”, we are trying to help you.

The idea behind my suggestion was to let you improve the way you submit your question in order to get more answers, if you facilitate the work of the other users they will easily solve your issues.

I taked your code and try to run it but some errors arised:

First callback: if the file “temp/recipe_contents.txt” do not exist the first time the code is executed the app do not work, only when I added a file with this name the code worked and let me save the text entered into that file.

Second callback: the second element of the input or output must be a property (could be “value” or “children” or any other properties, but you cant use such things like value=‘vulgar_free_recipe.txt’ (at list as I understand)

Also the output can’t be (‘textarea-state-example-output’, ‘value’) because this id element is an html.Div and this component do not have any “value” property.
It also can’t be “children”, because you can’t use the same property as input and output in the same callback (because any time the callback updates the optput will trigger the callback again and again.

also I do not see in the code the function called in this callback:

 unicode_fractions = convert_unicode_fractions()

Then I can´t follow your code to try to gess where your problem is.

Hope it helps. :grinning:

1 Like

Hey @robertpfaff I’m the one who helped you in that post and I’m not staff either. I’m just a huge Dash fan and part of the Dash community who like helping people. :slight_smile:

1 Like

Sorry. Not that calling someone staff is an insult in any way. Last night, I received a message from Adam in response to a deleted question, wanting to help me understand callbacks. I was honestly surprised in a good way. There was also someone else who went out her way to help me out in a similar fashion. In fact, the reception has been so positive and welcoming, I really was beginning to think that staff must be responding to the questions. That was an active thought in my head. Getting a message from Adam himself just kinda confirmed it. So that is the context for my misconception on that score.

But I never intend to impose or take advantage.

@AnnMarieW , @Emil , @Eduardo Thank you all for trying to help @robertpfaff with their questions.

@robertpfaff let’s continue to communicate via Private Message to see if we can solve this. If we find a solution, we’ll post it here.