Pd.dataframe as dash_table.Datatable?

Hello dear community, I am an engineering student trying hard not to do another excel sheet, but a nice dashboard.
I am trying to create an app to calculate a refrigeration cycle. I managed to just display my results, but I am having trouble integrating user inputs.

At this point all I want to achieve is the following:

  • User Input: Number
    
  • Number from input is used in cycle calculation
    
  • A dataframe is created
    
  • The dataframe is displayed as dash_table.DataTable (and hopefully will be formated later)
    

I am stuck at the error

dash.exceptions.InvalidCallbackReturnValue: The callback for `<Output `output_df.data`>`
            returned a value having type `DataFrame`
            which is not JSON serializable.

Here is my code so far:

from CoolProp.CoolProp import PropsSI
import numpy as np 
import pandas as pd
import dash
import dash_core_components as dcc
import dash_table
import dash_html_components as html
from dash.dependencies import Input, Output


external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
colors = {
    'background':'#283747',
    'text':'#7FDBFF'}
###App layout starts here###
app.layout = html.Div(style={'backgroundColor':colors['background']},
    children=[
    html.H1(
        children='R744 cycle',
        style={
            'textAlign':'center',
            'color':colors['text']}
        ),
    html.H2(
        children='A Dash sandbox',
        style={'textAlign':'center',
               'color':'#e74c3c'}
        ),
 #Here INPUT DATA
    html.Div(["Input: ",
              dcc.Input(id='input_data', value='25', type='number')],
         style={'color':colors['text']}
         ),
    
dash_table.DataTable(id='output_df',
    style_as_list_view=True,

),
##Maybe later: Add a fancy Slider as input 
    ##dcc.Slider(
        ##min=0,
       ## max=8,
       ## step=None,
       ## marks={
       ## 0: '20 °C',
       ## 2: '22 °C',
       ## 4: '24 °C',
       ## 6: '26 °C',
       ## 8: '28 °C'
  ##  },
   ## value=5)  
])
###App layout ends here###

###Callbacks to set calculation value for cycle###
@app.callback(
    Output(component_id='output_df', component_property='data'),
    [Input(component_id='input_data', component_property='value')]
)
def update_output_div(input_value):
     #Kältekreislauf Basic
    T_0=-10+273.15
    T_C= float(input_value) + 273.15  ##input value has to be float for caluclation! 
    eta_is = 0.7
    fluid = 'R744'
        
    delta_T_sh = 5 
    p_0 = PropsSI('P','T',T_0,'Q',0,fluid)
    p_C = PropsSI('P','T',T_C,'Q',0,fluid)
        
    states=4 
    p=np.zeros(states)
    T=np.zeros(states)
    h=np.zeros(states)
    s=np.zeros(states)
        
    #State 1 suction line
    p[0]=p_0
    T[0]=T_0 + delta_T_sh
    h[0]=PropsSI('H','T',T[0],'P',p[0],fluid)
    s[0]=PropsSI('S','T',T[0],'P',p[0],fluid)
    #State 2 Discharge line
    p[1]=p_C
    h_is_1 = PropsSI('H','S',s[0],'P',p[1],fluid)
    h[1]=(h_is_1-h[0])/eta_is+h[0]
    T[1]=PropsSI('T','H',h[1],'P',p[1],fluid)
    #State 3 After Condenser @ Bubble line
    p[2]=p_C
    h[2]=PropsSI('H','P',p[2],'Q',0,fluid)
    T[2]=PropsSI('T','P',p[2],'Q',0,fluid)
    #State 4 After expansion
    p[3]=p_0
    h[3]=h[2]
    T[3]=PropsSI('T','P',p[3],'H',h[2],fluid)


    df = pd.DataFrame (
    {
     'Pressure in bar': p*10**(-5),
     'Temperature in K':T,
     'Specific Enthalphy in kJ/kg':h/1000,     
     },
    index=['State 1','State 2','State 3','State 4']
    )
    df_rounded=df.round(3)
    return df_rounded #Result of function is a pandas dataframe!
                    
if __name__ == '__main__':
    app.run_server(debug=True)

Thank you for your help!

Hi @lariregischa and welcome to the Dash community!

I agree, a Dash app is way better than a spreadhseet.

You are really close… you just need to put the data from the dataframe in a format that can be used in the table. Both the table data and the columns need to be defined. Be sure to check out the dash documentation for more details: https://dash.plotly.com/datatable.

Here is how it would work in your app:

from CoolProp.CoolProp import PropsSI
import numpy as np
import pandas as pd
import dash
import dash_core_components as dcc
import dash_table
import dash_html_components as html
from dash.dependencies import Input, Output

external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
colors = {"background": "#283747", "text": "#7FDBFF"}
###App layout starts here###
app.layout = html.Div(
    style={"backgroundColor": colors["background"]},
    children=[
        html.H1(
            children="R744 cycle",
            style={"textAlign": "center", "color": colors["text"]},
        ),
        html.H2(
            children="A Dash sandbox", style={"textAlign": "center", "color": "#e74c3c"}
        ),
        # Here INPUT DATA
        html.Div(
            ["Input: ", dcc.Input(id="input_data", value="25", type="number")],
            style={"color": colors["text"]},
        ),
        dash_table.DataTable(
            id="output_df",
            style_as_list_view=True,
        ),
        ##Maybe later: Add a fancy Slider as input
        ##dcc.Slider(
        ##min=0,
        ## max=8,
        ## step=None,
        ## marks={
        ## 0: '20 °C',
        ## 2: '22 °C',
        ## 4: '24 °C',
        ## 6: '26 °C',
        ## 8: '28 °C'
        ##  },
        ## value=5)
    ],
)


###App layout ends here###

###Callbacks to set calculation value for cycle###
@app.callback(
    Output(component_id="output_df", component_property="data"),
    Output(component_id="output_df", component_property='columns'),
    [Input(component_id="input_data", component_property="value")],
)
def update_output_div(input_value):
    # Kältekreislauf Basic
    T_0 = -10 + 273.15
    T_C = float(input_value) + 273.15  ##input value has to be float for caluclation!
    eta_is = 0.7
    fluid = "R744"

    delta_T_sh = 5
    p_0 = PropsSI("P", "T", T_0, "Q", 0, fluid)
    p_C = PropsSI("P", "T", T_C, "Q", 0, fluid)

    states = 4
    p = np.zeros(states)
    T = np.zeros(states)
    h = np.zeros(states)
    s = np.zeros(states)

    # State 1 suction line
    p[0] = p_0
    T[0] = T_0 + delta_T_sh
    h[0] = PropsSI("H", "T", T[0], "P", p[0], fluid)
    s[0] = PropsSI("S", "T", T[0], "P", p[0], fluid)
    # State 2 Discharge line
    p[1] = p_C
    h_is_1 = PropsSI("H", "S", s[0], "P", p[1], fluid)
    h[1] = (h_is_1 - h[0]) / eta_is + h[0]
    T[1] = PropsSI("T", "H", h[1], "P", p[1], fluid)
    # State 3 After Condenser @ Bubble line
    p[2] = p_C
    h[2] = PropsSI("H", "P", p[2], "Q", 0, fluid)
    T[2] = PropsSI("T", "P", p[2], "Q", 0, fluid)
    # State 4 After expansion
    p[3] = p_0
    h[3] = h[2]
    T[3] = PropsSI("T", "P", p[3], "H", h[2], fluid)

    df = pd.DataFrame(
        {
            "Pressure in bar": p * 10 ** (-5),
            "Temperature in K": T,
            "Specific Enthalphy in kJ/kg": h / 1000,
        },
        index=["State 1", "State 2", "State 3", "State 4"],
    )
    df_rounded = df.round(3)
    data=df_rounded.to_dict('records')
    columns=[{"name": i, "id": i} for i in df_rounded.columns]

    return data, columns


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

BTW - Your app is cool!

Hello @AnnMarieW,

thank you so much for your quick response! I am baffled! Yes, I looked into the datatable documentation a lot, but I didnt get it.

Thank you so much for helping me to understand dash plotly better and to get this app going! :slight_smile:
I have a lot more for it planned, so eventually there will be more questions. :wink:

1 Like