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

Can you help me figure out how and where to print the final results of the analysis?

I pasted all the code below. I hope its not too much.

It is just all relevant to the question below. Its highlighted to save you time.

The first callback works fine. It takes the number of clicks from the submit button as the Input. For the Ouput, it returns the value of the initial processing and populates the corresponding editable datatable. There’s no issues here - the resultant datatable provides the user with editable data so that the user can make final edits and hit submit (again).

There is also no problem with the submit button. It takes the data edited by the user for final processing, and triggers the corresponding function which performs its job successfully. The problem seems to lie in the second Ouput statement, which is supposed to present the output of the final analysis. Specifically, it is supposed to render the results of the final analysis and present it in the div “html.Div(id=‘final-nutritional-profile-output’, ‘children’)”

I think I am confused by the word children, and how and when to use it. How can I direct the results of the final results of the last function to that area? By any chance, does DASH provide a separate reporting div where final report data can be displayed in an ordered way? What’s the best way to display text in the browser?

This is the final technical hurdle to completing the project. I would greatly appreciate any sincere feedback.

Here is the code. I highlighted the relevant areas.

Thank you very much for reviewing my question.

Robert

app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])

app.layout = html.Div([
   
*# Text area where the user pastes the raw materials or a cooking recipe in this case.*
 dcc.Textarea(
        id='recipe-textarea',
        value='',
        style={'width': '100%', 'height': 200},
        placeholder="Please note: All information in brackets or parentheses will be deleted."
    ),
    html.Button('Submit Recipe', id='recipe-textarea-submit-button', n_clicks=0),
    html.Div(id="msg"),

#After initial processing, the nutritional elements (ingredients, amounts and so forth...) appear in this datatable for user review and editing.
    
dash_table.DataTable(
        id='nutrients-review-datatable', 
        columns=[{'id': i, 'name':i} for i in ['Index', 'ID', 'Grams', 'Total Grams', 'Amounts', 'Modifiers', 'Units', 'Ings', 'Multiplier']],
        style_cell={'textAlign': 'left', 'padding': '10px', 'fontSize':14, 'font-family':'sans-serif'},
        style_header={'backgroundColor': '6eafde', 'fontWeight': 'bold', 'fontSize':14, 'border': '1px solid black','align': 'left'},
        style_data_conditional=[{'if':{'row_index': 'odd'}, 'backgroundColor': 'rgb(248, 248, 248)'}],
        data=None, 
        editable=True,
        row_deletable=True,
        hidden_columns=['Index','ID','Grams', 'Total Grams', 'Multiplier' ],
        sort_action='native',
        page_action='native',
        page_size=10,
        style_table={'height':'400px', 'overflowY':'auto'}
        ),''
    html.Button('Submit Edits', id='nutrients-review-datatable-submit-button', n_clicks=0),
    html.Div(id='final-nutritional-profile-output', 'children')

])

# This callback and function accepts and processes the recipe,
# producing an editable table of amounts, units of measurement,
# ingredients and modifier essential to a nutritional profile.

@app.callback(
    Output('nutrients-review-datatable', 'value'),
    Input('recipe-textarea-submit-button', 'n_clicks'),
    State('recipe-textarea', 'value')
)
def update_output(n_clicks, value):
    if n_clicks > 0:
        print("Recipe submitted")
        with open("temp/recipe_contents.txt", "w", encoding='utf-8') as recipe_contents:
            recipe = value.split('\n')
            for line in recipe:
                recipe_contents.write(line)
                recipe_contents.write('\n')
        convert_unicode_fractions()
        convert_regular_fractions()
        prepare_recipe_text()
        parse_recipe_ner()
        validate_recipe_ents()
        prepare_data_for_table()

        with open("./json/recipe_ents_list.json", "r") as final_recipe_file:
            data = json.loads(final_recipe_file.read())

            return data

# This function and callback accept the user's edits to the nutritional
# elements in the table and produce a nutritional profile. In the future, check boxes
# allow the user to tailor the report, tracking 50+ nutrients.

# The Output line below is the problem. It is supposed to return the final results of the nutritional analysis and place it in # the div "(id='final-nutritional-profile-output'. " But this does not produce the correct results. I receive the error message: # "SyntaxError: positional argument follows keyword argument" Can someone point me in the right direct?

@app.callback(
    **Output('final-nutritional-profile-output', 'children'),**
    Input('nutrients-review-datatable-submit-button', 'n_clicks'),
    State('nutrients-review-datatable', 'data'),
    prevent_initial_call=True
)

def create_nutritional_profile(n_clicks, data):
    if n_clicks > 0:
        finalize_ing_dicts(data)
        create_match_idslist()
        create_nutrient_dicts()
        merge_nutrient_to_ing_dicts()
        
        return (final_conversions())

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

Bottom line, I want to print the final data - finial report results - to the screen.

How can I do that?

Hi @robertpfaff ,

Which type does final_conversion() returns? “children” expects another Dash component, a list of them or a str/number.

Please also note that wrapping the return of final_conversion() in parenthesis transforms your return into a tuple, which will lead to undesirable results if it does return a type accepted as “children”.

It depends on the text you have. All html components allow to write very flexible markups, but you must do it manually.

As an example, say that final_conversions() returns something like {"fat": "12g", "calories": "500kcal", "salt": "2g" }… You could return as “children” something like:

@app.callback(
    Output('final-nutritional-profile-output', 'children'),
    Input('nutrients-review-datatable-submit-button', 'n_clicks'),
    State('nutrients-review-datatable', 'data'),
    prevent_initial_call=True
)
def create_nutritional_profile(n_clicks, data):
    if n_clicks > 0:
        finalize_ing_dicts(data)
        create_match_idslist()
        create_nutrient_dicts()
        merge_nutrient_to_ing_dicts()
        
        results = final_conversions()

        return [
            html.H2("Nutritional Profile"),
            html.P(f"Calories: {results['calories']}",
            html.P(f"Salt: {results['salt']}",
            html.P(f"Fat: {results['fat']}",
        ]

Of course, each div can be further nested and styled properly. Here I am just using a heading and paragraphs to quickly explain the idea.

Another option is to use dcc.Markdown. Then if you have a string formatted as Markdown, it will create the format automatically. It is an alternative if you are familiar with the Markdown syntax and not with html.

Thanks for responding (again). I very much appreciate it.

1. The final function " final_conversions()" returns a list of ONE dictionary for the current test recipe that looks like the truncated one below (there are about 50 micronutrients and their totals in the dictionary):

[{‘Total Calories’: 1653.5795, ‘Total Fat’: 29.4402, ‘Total Protein’: 91.76070000000001, ‘Total Carbohydrates’: 284.6794, ‘Total Sugar’: 24.9604, ‘Total Fiber’: 63.1683, ‘Cholesterol’: 0.0, ‘Total Saturated Fat’: 0.0,…]

2. I currently receive a DASH error message like this one below:

An object was provided as children instead of a component, string, or number (or list of those). Check the children “property that looks something like:
{
“Total Calories”: 1653.5795,
“Total Fat”: 29.4402,
“Total Protein”: 91.76070000000001,
“Total Carbohydrates”: 284.6794,
“Total Sugar”: 24.9604,
“Total Fiber”: 63.1683,
“Cholesterol”: 0,”

**3. The function now looks like this. If you have any thoughts on how to “publish” this list of one dictionary, or thoughts on how to better restructure the data, I think that’s all I am missing, and I am not finding much guidance online.

I would love to know! Thank you.**


@app.callback(
    Output('final-nutritional-profile-output', 'children'),
    Input('nutrients-review-datatable-submit-button', 'n_clicks'),
    State('nutrients-review-datatable', 'data'),
    prevent_initial_call=True
)

def create_nutritional_profile(n_clicks, data):
    if n_clicks > 0:
        finalize_ing_dicts(data)
        create_match_idslist()
        create_nutrient_dicts()
        merge_nutrient_to_ing_dicts()
        final_conversions()

        with open ('./json/final_totals_list.json', 'r') as recipe_info:
            results = json.loads(recipe_info.read())

            print(results)

            return results

If I structure the return statement like this:

with open ('./json/final_totals_list.json', 'r') as recipe_info:
            results = json.loads(recipe_info.read())

            string_results = str(results)
            
            return string_results

It prints the whole object to the browser. So that’s some progress and I can hopefully figure out how to manipulate it further, so that it looks good. But at least the fundamentals are working.

It is a start at least.

[{'Total Calories': 1653.5795, 'Total Fat': 29.4402, 'Total Protein': 91.76070000000001, 'Total Carbohydrates': 284.6794, 'Total Sugar': 24.9604, 'Total Fiber': 63.1683, 'Cholesterol': 0.0, 'Total Saturated Fat': 0.0, 'Total Calcium': 810.6999000000002, 'Total Iron': 50.0797, 'Total Potassium': 4964.6402, 'Total Magnesium': 522.7068999999999, 'Total Vitamin A IUs': 34471.563, 'Total Vitamin A RAEs': 575.7111000000001, 'Total Vitamin C': 111.79920000000001, 'Total Vitamin B12': 0.0, 'Total Vitamin D': 0.0, 'Total Vitamin E': 15.1711, 'Total Added Sugar': 0.0, 'Total Omega Three': 1209.4569999999999, 'Total Omega Six': 3958.0817, 'Total Trans Fats': 0.0027, 'Total Sugars Alcohol': 0.0, 'Total Phosphorus': 1283.9295999999997, 'Total Sodium': 2510.2866999999997, 'Total Zinc': 17.090700000000002, 'Total Copper': 5.3233999999999995, 'Total Manganese': 20.397799999999997, 'Total Selenium': 14.7974, 'Total Flouride': 0.084, 'Total Molybdenum': 0.0, 'Total Choline': 106.2713, 'Total Vitamin B1': 2.1736999999999993, 'Total Vitamin B2': 0.9227999999999998, 'Total Vitamin B3': 12.3157, 'Total Vitamin B5': 2.7998, 'Total Vitamin B6': 2.5844, 'Total Vitamin B7': 0.0, 'Total Folate': 0.0, 'Total Folic Acid': 0.0, 'Total Betaine': 82.3803, 'Total Retinol': 0.0, 'Total Beta Carotene': 6819.1033, 'Total Alpha Carotene': 12.26, 'Total Lycopene': 20424.0, 'Total Lutein': 11021.9077, 'Total Vitamin D2': 0.0, 'Total Vitamin D3': 0.0, 'Total Vitamin K': 633.9924000000001, 'Total Monounsaturated Fats': 0.12260000000000001, 'Total Polyunsaturated Fats': 0.12260000000000001}]

Please refer to my answer, where I gave an example of how to transform a dictionary to a list of components that can be returned as children.

The truth is I tried your approach many times, without much success. Then, I realized I had not added a return statement to the final imported function (“final conversions”). Hence, I was getting a value of None! Duh.

I made that change, tried again, and everything fell into place.

Thank you!

def create_nutritional_profile(n_clicks, data):
    if n_clicks > 0:
        finalize_ing_dicts(data)
        create_match_idslist()
        create_nutrient_dicts()
        merge_nutrient_to_ing_dicts()
        results = final_conversions()

        for each_dict in results:
            for k,v in each_dict.items():
                print(k, v)

        return [
            html.H2("Nutritional Profile"),
            html.P(f"Calories: {each_dict['Total Calories']}"),
            html.P(f"Fat: {each_dict['Total Fat']}"),
            html.P(f"Protein: {each_dict['Total Protein']}"),
            html.P(f"Carbohydrates: {each_dict['Total Carbohydrates']}"),
            html.P(f"Sugar: {each_dict['Total Sugar']}"),
            html.P(f"Fiber: {each_dict['Total Fiber']}"),
            html.P(f"Cholesterol: {each_dict['Cholesterol']}"),
            html.P(f"Saturated Fat: {each_dict['Total Saturated Fat']}"),
            html.P(f"Calcium: {each_dict['Total Calcium']}"),
            html.P(f"Iron: {each_dict['Total Iron']}"),
            html.P(f"Magbesium: {each_dict['Total Magnesium']}"),
            html.P(f"Vitamin A IUs: {each_dict['Total Vitamin A IUs']}"),
            html.P(f"Vitamin A RAEs: {each_dict['Total Vitamin A RAEs']}"),
            html.P(f"Vitamin C: {each_dict['Total Vitamin C']}"),
            html.P(f"Vitamin B12: {each_dict['Total Vitamin B12']}"),
            html.P(f"Vitamin D: {each_dict['Total Vitamin D']}"),
            html.P(f"Vitamin E: {each_dict['Total Vitamin E']}"),
            html.P(f"Added Sugar: {each_dict['Total Added Sugar']}"),
            html.P(f"Omega Three: {each_dict['Total Omega Three']}"),
            html.P(f"Omega Six: {each_dict['Total Omega Six']}"),
            html.P(f"Trans Fats: {each_dict['Total Trans Fats']}"),
            html.P(f"Sugars Added: {each_dict['Total Added Sugar']}"),
            html.P(f"Phosphorus: {each_dict['Total Phosphorus']}"),
            html.P(f"Sodium: {each_dict['Total Sodium']}"),
            html.P(f"Zinc: {each_dict['Total Zinc']}"),
            html.P(f"Copper: {each_dict['Total Copper']}"),
            html.P(f"Manganese: {each_dict['Total Manganese']}"),
            html.P(f"Selenium: {each_dict['Total Selenium']}"),
            html.P(f"Flouride: {each_dict['Total Flouride']}"),
            html.P(f"Molybdenum: {each_dict['Total Molybdenum']}"),
            html.P(f"Choline: {each_dict['Total Choline']}"),
            html.P(f"Vitamin B1: {each_dict['Total Vitamin B1']}"),
            html.P(f"Vitamin B2: {each_dict['Total Vitamin B2']}"),
            html.P(f"Vitamin B3: {each_dict['Total Vitamin B3']}"),
            html.P(f"Vitamin B5: {each_dict['Total Vitamin B5']}"),
            html.P(f"Vitamin B6: {each_dict['Total Vitamin B6']}"),
            html.P(f"Vitamin B7: {each_dict['Total Vitamin B7']}"),
            html.P(f"Folate: {each_dict['Total Folate']}"),
            html.P(f"Folic Acid: {each_dict['Total Folic Acid']}"),
            html.P(f"Betaine: {each_dict['Total Betaine']}"),
            html.P(f"Retinol: {each_dict['Total Retinol']}"),
            html.P(f"Beta Carotene: {each_dict['Total Beta Carotene']}"),
            html.P(f"Alpha Carotene: {each_dict['Total Alpha Carotene']}"),
            html.P(f"Lycopene: {each_dict['Total Lycopene']}"),
            html.P(f"Lutein: {each_dict['Total Lutein']}"),
            html.P(f"Vitamin D2: {each_dict['Total Vitamin D2']}"),
            html.P(f"Vitamin D3: {each_dict['Total Vitamin D3']}"),
            html.P(f"Vitamin K: {each_dict['Total Vitamin K']}"),
            html.P(f"Monounsaturated Fats: {each_dict['Total Monounsaturated Fats']}"),
            html.P(f"Polyunsaturated Fats: {each_dict['Total Polyunsaturated Fats']}"),

            ]

Here is an example of some of the output.

(The numbers need to be round and explained, but it all adds up).