I’m working in Pycharm which seems to pick up errors as they should and my app won’t even run if I have syntax errors, etc.
But now it is running but my callbacks stop working as soon as I uncomment my new callback called update_nutrients_table()
It’s failing silently which makes it tough to track down the error.
# -*- coding: utf-8 -*-
"""
"""
import re
from dash import Dash
from dash.dependencies import Input, Output, State
from Dashboard.utils.Dash_fun import apply_layout_with_auth
import dash_core_components as dcc
import dash_bootstrap_components as dbc
import dash_html_components as html
import dash_table
from mongoengine import connect
#from app import db
from app.models import (
CNFFoodName, CNFConversionFactor, CNFNutrientAmount,
CNFYieldAmount, CNFRefuseAmount
)
from app.models.model_nutrients import (
ElementsRDI, VitaminsRDI, ElementsUpperRDI,
VitaminsUpperRDI, MacronutrientsDistRange
)
from app.models.model_infantsRDI import (
InfantsElementsRDI, InfantsVitaminsRDI, InfantsMacroRDI, InfantsElementsUpperRDI,\
InfantsVitaminsUpperRDI
)
from app.models.model_childrenRDI import (
ChildrenElementsRDI, ChildrenVitaminsRDI, ChildrenMacroRDI, ChildrenElementsUpperRDI,\
ChildrenVitaminsUpperRDI
)
from app.models.model_malesRDI import (
MalesElementsRDI, MalesVitaminsRDI, MalesMacroRDI, MalesElementsUpperRDI, MalesVitaminsUpperRDI
)
from app.models.model_femalesRDI import (
FemalesElementsRDI, FemalesVitaminsRDI, FemalesMacroRDI, FemalesElementsUpperRDI,\
FemalesVitaminsUpperRDI
)
from app.models.model_pregnancyRDI import (
PregnancyElementsRDI, PregnancyVitaminsRDI, PregnancyMacroRDI, PregnancyElementsUpperRDI,\
PregnancyVitaminsUpperRDI
)
from app.models.model_lactationRDI import (
LactationElementsRDI, LactationVitaminsRDI, LactationMacroRDI, LactationElementsUpperRDI,\
LactationVitaminsUpperRDI
)
cnf_modelnames_arr = ['MacronutrientsDistRange',
'InfantsElementsRDI', 'InfantsVitaminsRDI', 'InfantsMacroRDI', 'InfantsElementsUpperRDI', \
'InfantsVitaminsUpperRDI',
'ChildrenElementsRDI', 'ChildrenVitaminsRDI', 'ChildrenMacroRDI', 'ChildrenElementsUpperRDI',\
'ChildrenVitaminsUpperRDI',
'MalesElementsRDI', 'MalesVitaminsRDI', 'MalesMacroRDI', 'MalesElementsUpperRDI',
'MalesVitaminsUpperRDI',
'FemalesElementsRDI', 'FemalesVitaminsRDI', 'FemalesMacroRDI', 'FemalesElementsUpperRDI',\
'FemalesVitaminsUpperRDI',
'PregnancyElementsRDI', 'PregnancyVitaminsRDI', 'PregnancyMacroRDI', 'PregnancyElementsUpperRDI',\
'PregnancyVitaminsUpperRDI',
'LactationElementsRDI', 'LactationVitaminsRDI', 'LactationMacroRDI', 'LactationElementsUpperRDI',\
'LactationVitaminsUpperRDI'
]
# import the rdi csv table names and filenames arrs
from Dashboard.utils.Dash_App_utils import (table_names_arr,csv_names_arr, make_dataframes,
make_table, make_figure)
import pandas as pd
import re
connect('cnf')
url_base = '/dash/shiny/'
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
colors={
'background': 'white',
'text': 'black'
}
# todo: use this for cumulation
rdi_nutrients = {'water': "", "fat":"", 'fiber': "", 'linoleicAcid':"", 'alphaLinolenicAcid': "", 'carbohydrate': "", 'protein': "",
'calcium': "", 'chromium': "", 'copper': "", 'fluoride': "", 'iodine': "", 'iron': "", 'magnesium': "",
'manganese': "", 'molybdenum': "", 'phosphorus': "", 'selenium': "", 'zinc': "", 'potassium': "",
'sodium': "", 'chloride': "",
'vitaminA': "", 'vitaminC': "", 'vitaminD': "", 'vitaminE': "", 'vitaminK': "", 'thiamin': "",
'riboflavin': "", 'niacin': "", 'vitaminB6': "", 'folate': "", 'vitaminB12': "",
'pantothenicAcid': "",'biotin': "", 'choline': ""}
# more global variables
food_name_query_set = CNFFoodName.objects(description__exists=True)
food_names_arr = []
food_ids = []
food_groups = []
food_sources = []
food_dict = {}
for food in food_name_query_set:
'''
# dict with description as key, values: id, group, source
food_dict[food['description']] = [food['id'], food['food_group'],
food['food_source'],
food['scientific_name']]
'''
food_names_arr.append(food['description'])
food_ids.append(food['id'])
#assert len(food_names_arr) == len(food_ids)
food_to_id_dict = dict(zip(food_names_arr, food_ids))
# gets allocated in function, {ingredient: measure_name}
foodnameDict = {}
# these get values in functions for make_tables()
# conversions for selected food
#global helper fn
#helper fn
#helper fn
def get_unit_names(food_id):
"""
class_collection: one of the CNF collections
get the unit names and return after cleaning and keeping only unique
"""
# get units
conversions = CNFConversionFactor.objects.filter(food=str(food_id))
unit_names = []
for c in conversions:
unit_names.append(c.measure.name)
print(f'unit_names {unit_names}')
# take out the numbers and whitespace
# todo: pattern has to include all non-alpha
pattern = '[0-9]'
temp_arr = [re.sub(pattern, '', x) for x in unit_names]
unit_names = [x.strip() for x in temp_arr]
# only keep the unique measure names
measure_set = set(unit_names)
unit_names = list(measure_set)
return unit_names
def make_conversions_df(food_id):
"""
param
"""
food = CNFFoodName.objects.get(id=str(food_id))
conversions = CNFConversionFactor.objects.filter(food=food)
measure_names = []
measure_vals = []
for c in conversions:
measure_names.append(c.measure.name)
measure_vals.append(c.value)
conversions_df = pd.DataFrame(
{'Name': measure_names,
'Multiplier': measure_vals
})
return conversions_df
#global helper fn
def make_nutrients_df(food_id):
food = CNFFoodName.objects.get(id=str(food_id))
nutrients = CNFNutrientAmount.objects.filter(food=food, nutrient_value__gt=0)
nutrient_names = []
nutrient_vals = []
nutrient_units = []
for n in nutrients:
nutrient_names.append(n.nutrient_name.name)
nutrient_vals.append(n.nutrient_value)
nutrient_units.append(n.nutrient_name.unit)
nutrients_df = pd.DataFrame(
{"Name": nutrient_names,
"Value": nutrient_vals,
"Units": nutrient_units
})
return nutrients_df
# make a dummy table so references in callbacks don't have issues
dummy_food = food_names_arr[0]
dummy_food_id = food_to_id_dict[dummy_food]
conversions_df = make_conversions_df(dummy_food_id)
#
nutrients_df = make_nutrients_df(dummy_food_id)
#list of lists of dicts for cum ingredients
cum_ingredients = [{'ingredient': "", "amt": "", "units": ""}]
layout=html.Div([
html.Label(
"Enter age and select gender or pregnant/lactating"
),
html.Div([
dcc.Input(
id="age-input", type="number", value='30',
autoComplete=False, debounce=True
),
dcc.RadioItems(
options=[
{'label': 'male', 'value': 'Males'},
{'label': 'female', 'value': 'Females'},
{'label': 'pregnant', 'value': 'Pregnancy'},
{'label': 'lactating', 'value': 'Lactation' }
],
value='Females'
),
]),
#todo: show if over RDI and display red if over upper RDI
html.Div( # todo: output table here
dash_table.DataTable(
id='cumulative-ingredients',
columns=[{
'ingredient': '',
'amount': '',
'units': '',
'deletable': True,
'renamable': True
}],
data=[None],
editable=True,
row_deletable=True
)
),
html.Label(
"1. Choose Ingredient"
),
html.Div([
dcc.Input(
id="search-ingredient",
list="food_names", placeholder=food_names_arr[3333],
debounce=True,
style={'width': '80%'}
),
],
),
html.Datalist(
id="food_names", children=[
html.Option(value=food) for food in food_names_arr
]
),
html.Br(),
html.Label(
"2. Amount Units"
),
html.Div([
dcc.Dropdown(
id="units-dropdown",
),
]),
html.Br(),
html.Label(
"3. Quantity"
),
dcc.Input(
id="numerical-amount", type="number",
autoComplete=False, debounce=True
),
html.Br(),
html.Button(
"Add Ingredient", id='add-ingredient', n_clicks=0
),
html.Button(
"Remove Ingredient", id="remove-ingredient", n_clicks=0
),
html.Br(),
#todo: separate layouts
html.Div(
dcc.RadioItems(
options=[
{'label': 'tables for ingredient', 'value': 'cnf-tables-1'},
{'label': 'vs RDI for ingredient', 'value': 'rdi-graphs-1'},
{'label': 'tables for cumulative', 'value': 'cnf-tables-cum'},
{'label': 'vs RDI for ingredient', 'value': 'rdi-graphs-cum'},
],
value='cnf-tables-1'
),
),
html.Br(),
html.Div(
id="chosen-food" # shows full name in <H3>
),
html.Div(
id="table-foodgroup-source"
),
html.Div(
html.H5("Conversions Multipliers")
),
html.Div(
id="conversion-table"
),
html.Div(
html.H5("Nutrients")
),
html.Div(
id="nutrients-table"
),
html.Br(),
html.Div(
dcc.Graph(
id="cnf-vs-rdi"
)
),
])
def Add_Dash(server):
app = Dash(server=server, url_base_pathname=url_base,
external_stylesheets=external_stylesheets)
#application = app.server
# external_stylesheets=[dbc.themes.BOOTSTRAP])
apply_layout_with_auth(app, layout)
@app.callback(
Output('chosen-food', 'children'),
Output('units-dropdown', 'options'),
Input('search-ingredient', 'value')
)
def update_dropdown(ingredient):
food_name = html.H3(f"{ingredient}")
#get food_id
food_id = food_to_id_dict[ingredient]
# get units
measure_names = get_unit_names(food_id)
# make dict to return options for dropdown
foodnameDict={ingredient:measure_names}
return food_name, [{'label':unit, 'value':unit} for unit in foodnameDict[ingredient]]
# call back to show conversions table, nutrients table and food group/src table
# for currently selected ingredient
@app.callback(
Output('table-foodgroup-source', 'children'),
Output('conversion-table', 'children'),
Output('nutrients-table', 'children'),
Input('search-ingredient', 'value')
)
def show_tables(ingredient):
'''
return top table, conversions table, nutrients table, yield table,
refuse table
'''
food_id = food_to_id_dict[ingredient]
food = CNFFoodName.objects.get(id=str(food_id))
food_grp = food.food_group.name
food_src = food.food_source.description
food_sci_name = "n/a"
if food.scientific_name:
food_sci_name = food.scientific_name
# table for food group, source, scientific name
food_group_table = html.Table([
html.Thead([
html.Tr([html.Th("Group"), html.Th("Source"), html.Th("Scientific Name")])
]),
html.Tbody([
html.Tr([
html.Td(food_grp),html.Td(food_src),html.Td(food_sci_name)
])
])
])
conversions_df = make_conversions_df(food_id)
conversions_table = make_conversions_table(conversions_df)
nutrients_df = make_nutrients_df(food_id)
nutrients_table = make_nutrients_table(nutrients_df)
return food_group_table, conversions_table, nutrients_table
def make_conversions_table(conversions_df):
conversions_table = dash_table.DataTable(
id='conversions_table',
columns=[{"name": i, "id": i} for i in conversions_df.columns],
data=conversions_df.to_dict('records'),
style_cell={'textAlign': 'left'},
style_data_conditional=[{
'if': {'row_index': 'odd'},
'backgroundColor': 'rgb(248,248,248)'
}],
style_header={
'backgroundColor': 'rgb(230,230,230)',
'fontWeight': 'bold'
},
)
return conversions_table
def make_nutrients_table(nutrients_df):
nutrients_table = dash_table.DataTable(
id='nutrients_table',
columns=[{"name": i, "id": i} for i in nutrients_df.columns],
data=nutrients_df.to_dict('records'),
style_cell_conditional=[{
'if': {'column_id': c},
'textAlign': 'left'
} for c in ['Name']
],
style_data_conditional=[{
'if': {'row_index': 'odd'},
'backgroundColor': 'rgb(248,248,248)'
}],
style_header={
'backgroundColor': 'rgb(230,230,230)',
'fontWeight': 'bold'
},
)
return nutrients_table
#return app.server
#todo:
# also show graph of elements, vitamins and macronutrients as % of RDI
# for graph each nutrient is shown against its own RDI as %
# for macro need to sum total calories and divide that by intake of each macro
@app.callback(
Output("nutrients-table", "children"),
Input("add-ingredient", "n_clicks"),
State("numerical-amount", "value"),
State('units-dropdown', 'value'),
)
def update_nutrients_table(num_clicks, amount, units):
'''
get multiplier from conversions table for correct units,
multiply by each nutrient by correct amount
conv_cols of Conversions: Name, Multiplier
'''
curr_nutrients_df = nutrients_df.copy()
# todo: if n_clicks reset to zero check for <0 for remove ingredient
if num_clicks > 0:
measure_name = ''
measure_num = -1
curr_multiplier = ''
for index, row in conversions_df.iterrows():
if units in str(row['Name']):
# get number
measure_name = str(row['Name'])
measure_num = float(re.findall("\d+", measure_name)[0])
curr_multiplier = row['Multiplier']
break
#divide amount/measure_num
multiplier_factor = (float(amount))/measure_num
new_multiplier = multiplier_factor * curr_multiplier
#multiply all nutrients by new_multiplier
for index, row in curr_nutrients_df.iterrows():
for col in curr_nutrients_df.columns:
curr_nutrients_df.iloc[row, col] *= new_multiplier
updated_nutrients_table = make_nutrients_table(curr_nutrients_df)
return updated_nutrients_table
return make_nutrients_table(curr_nutrients_df)
return app.server
"""
# todo: user clicks add ingredient, show on "cumulative ingredients"
# [name, amount, units]
# https://dash.plotly.com/datatable/editable
@app.callback(
Output('cumulative-ingredients', "children"),
Input("add-ingredient", "n_clicks"),
[State("search-ingredient", 'value'),
State("numerical-amount", 'value'),
State('units-dropdown', 'value'),
State('cumulative-ingredients', 'data'),
State('cumulative-ingredients', 'columns')]
)
def update_cum_ingredients(num_clicks, ingredient, amount, units, rows, cols):
if num_clicks > 0:
rows.append({cols['ingredient']: ingredient, cols['amount']: amount,
cols['units']: units})
return rows
pass
"""
#return app.server
I raised an issue, feature request: [Feature Request] Need error messages on fail · Issue #1452 · plotly/dash · GitHub
Does the Enterprise version come with error messages?
Is that a paid feature???