dash_table显示空白行

时间:2019-02-14 18:03:35

标签: python pandas plotly-dash

我正在创建一个仪表板应用程序,该应用程序显示一个数据表,该数据表在更新日期时间选择器值时得到更新,显然可以成功检索到行,但是它们显示为空白,如下所示:

dash_table displaying blank rows

这是我的代码:

# Importa las librerías necesarias para la encripción de datos
from hmac import new
from hashlib import md5

# Importa la librerías necesarias para realizar consultas web
from requests import get, post

# Importa la librería necesaria para manipular objetos de tipo fecha-tiempo
from datetime import datetime, timedelta

# Importa la librería necesaría para manipular datos
from pandas import read_json

# Importa las librerías necesarias para crear una web app de tipo dashboard para visualización de datos
from dash import Dash
from dash.dependencies import Input, Output
from dash_html_components import Div, H2, Img
from dash_core_components import Dropdown, DatePickerRange
from dash_table import DataTable

# crea las variables necesarias para conectarse al servicio web de future time
url = 'some_url'
usr = 'some_user'
pwd = 'some_pwd'
pwdh = pwd.encode()
ts = str(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'))  # ; del datetime
msg = (usr + pwd + ts).encode()

# crea la firma hash HMAC MD5 utilizando la contraseña como llave y la guarda en la variable digest
digest = new(pwdh, msg, md5).hexdigest()

# Crea los argumentos necesarios para acceder al webservice y los asigna a la variable argumentos
arg = {'LoginName': usr,
       'Signature': digest,
       'TimeStamp': ts}

# Establece la conexión al web service, utiliza el recurso /System/LoginUser y autentica al usuario,
# guarda en la variable r el resultado de la conexión.
r = post(url, arg)

# Obtiene el UserID
UserId = str(r.json()['Result'][11:13])

# Crea las variable necesarias para consumir el servicio de Working Day
url = 'some_url'
Keywords = ''
StartDate = str((datetime.today() - timedelta(1)).strftime('%Y-%m-%d')) + ' 00:00:00'
EndDate = str((datetime.today() - timedelta(1)).strftime('%Y-%m-%d')) + ' 23:59:59'
Filter = 'todos'
OrderBy = ''

# Construye el nuevo mensaje a ser firmado
msg = (Keywords + StartDate + EndDate + Filter + OrderBy + UserId).encode()

# Crea la firma hash HMAC MD5
digest = new(pwdh, msg, md5).hexdigest()  # ; del new, pwdh, msg, md5

# Crea los argumentos necesarios para acceder al webservice y los asigna a la variable argumentos
arg = {'Keywords': '',
       'StartDate': StartDate,
       'EndDate': EndDate,
       'Filter': Filter,
       'OrderBy': '',
       'UserID': UserId,
       'Signature': digest}  # ; del Keywords, StartDate, EndDate, Filter, OrderBy, UserId, digest

# Invoca mediante get el recurso /WorkingDay/Get
r = get(url, arg)  # ; del url, arg

# Convierte la cadena json del webservice a dataframe de pandas
df = read_json(r.json()['Result'])  # ; del r; read_json

# Filtra las columnas necesarias para el reporte de faltas injustificadas
df = df.filter(items=['ExportId', 'Name', 'OU5', 'Date', 'TimeGroup', 'Exceptions'])

# Renombra las columnas del reporte
df.columns = ['Código de empleado', 'Nombre del empleado',
              'Departamento', 'Fecha', 'Horario', 'Excepción']

# Inicializa la aplicación web
app = Dash('BI-UYEDA')

# Define las hojas de estilos externas a utilizar   
external_css = [
    "https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.min.css",  # Normalize the CSS
    "https://fonts.googleapis.com/css?family=Open+Sans|Roboto",  # Fonts
    "https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css",
    "https://cdn.rawgit.com/TahiriNadia/styles/faf8c1c3/stylesheet.css",
    "https://cdn.rawgit.com/TahiriNadia/styles/b1026938/custum-styles_phyloapp.css"
]

# Añade las hojas de estilos a la aplicación
for css in external_css:
    app.css.append_css({"external_url": css})

server = app.server

# Define la estructura de la aplicación
app.layout = Div([
    Div([
        H2("Inteligencia de negocios UYEDA"),
        Img(src="some_url")],
        className="banner"),
    Div([
        Div([
        ], style={
            'margin': '5px',
            'text-align': 'center',
            'vertical-align': 'middle',
            'width': '48%',
            'display': 'inline-block'
        }),
        Div([
            DatePickerRange(
                id='fechas',
                start_date=str((datetime.today() - timedelta(1)).strftime('%Y-%m-%d')),
                end_date=str((datetime.today() - timedelta(1)).strftime('%Y-%m-%d')),
                display_format='DD/MM/YYYY',
                max_date_allowed=str((datetime.today() - timedelta(1)).strftime('%Y-%m-%d')),
                min_date_allowed='2018/01/01'
            ),
        ], style={
            'margin': '5px',
            'text-align': 'center',
            'vertical-align': 'middle',
            'width': '48%',
            'display': 'inline-block'
        })

    ],
        className="container"
    ),
    Div([
        DataTable(id='table',
                  columns=[{'name': i, 'id': i} for i in df.columns],
                  data=[{}], #df.to_dict('rows'),
                  sorting=True,
                  style_table={'overflowX': 'scroll'},
                  style_cell={'minWidth': '0px',
                              'maxWidth': '180px',
                              'whiteSpace': 'normal'},
                  css=[{
                      'selector': '.dash-cell div.dash-cell-value',
                      'rule': 'display: inline; white-space: inherit; overflow: inherit; text-overflow: inherit;'
                  }],
                  virtualization=True,
                  pagination_mode=True,
                  n_fixed_rows=1,
                  merge_duplicate_headers=True
                  )
    ],
        className="container")
])


# Crea las llamadas a la aplicación para actualizar las filas
@app.callback(
    Output('table', 'data'),
    [Input('fechas', 'start_date'),
     Input('fechas', 'end_date')]
)
# Crea la función que actualiza las filas de la tabla
def act_filas(start_date, end_date):
    """
    Esta función actualiza las filas de un datatable
    :param start_date: Cadena de caracteres que indica la fecha inicial del reporte
    :param end_date: Cadena de caracteres que indica la fehca final del reporte
    :return: Retorna las filas que actualizaran las filas del datatable
    """
    # crea las variables necesarias para conectarse al servicio web de future time
    url = 'some_url'
    usr = 'some_usr'
    pwd = 'some_pwd'
    pwdh = pwd.encode()
    ts = str(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'))  # ; del datetime
    msg = (usr + pwd + ts).encode()

    # crea la firma hash HMAC MD5 utilizando la contraseña como llave y la guarda en la variable digest
    digest = new(pwdh, msg, md5).hexdigest()

    # Crea los argumentos necesarios para acceder al webservice y los asigna a la variable argumentos
    arg = {'LoginName': usr,
           'Signature': digest,
           'TimeStamp': ts}

    # Establece la conexión al web service, utiliza el recurso /System/LoginUser y autentica al usuario,
    # guarda en la variable r el resultado de la conexión.
    r = post(url, arg)

    # Obtiene el UserID
    UserId = str(r.json()['Result'][11:13])

    # Crea las variable necesarias para consumir el servicio de Working Day
    url = 'some_url'
    Keywords = ''
    StartDate = start_date + ' 00:00:00'
    EndDate = end_date + ' 23:59:59'
    Filter = 'todos'
    OrderBy = ''

    # Construye el nuevo mensaje a ser firmado
    msg = (Keywords + StartDate + EndDate + Filter + OrderBy + UserId).encode()

    # Crea la firma hash HMAC MD5
    digest = new(pwdh, msg, md5).hexdigest()  # ; del new, pwdh, msg, md5

    # Crea los argumentos necesarios para acceder al webservice y los asigna a la variable argumentos
    arg = {'Keywords': '',
           'StartDate': StartDate,
           'EndDate': EndDate,
           'Filter': Filter,
           'OrderBy': '',
           'UserID': UserId,
           'Signature': digest}  # ; del Keywords, StartDate, EndDate, Filter, OrderBy, UserId, digest

    # Invoca mediante get el recurso /WorkingDay/Get
    r = get(url, arg)  # ; del url, arg

    # Convierte la cadena json del webservice a dataframe de pandas
    df = read_json(r.json()['Result'])  # ; del r; read_json

    # Reemplaza los valores nulos por caracter vacio
    df.fillna('', None, None, True)

    # Descarta los registros correspondientes a practicantes, del cómputo de faltas
    df.drop(df[df['TimeGroup'] == 'Practicantes'].index, inplace=True)

    # Descarta los registros correspondientes a horarios libres, del cómputo de faltas
    df.drop(df[df['TimeGroup'] == 'Libre'].index, inplace=True)

    # Descarta los registros correspondientes a descansos, del cómputo de faltas
    df.drop(df[df['ProjectedTimeToWork'].str.contains('00:00:00')].index, inplace=True)

    # Descarta los registros correspondientes a trabajadores borrados, del cómputo de faltas
    df.drop(df[df['Name'].str.contains('Borrado')].index, inplace=True)

    # Descarta los registros correspondientes a visitantes, del cómputo de faltas
    df.drop(df[df['Name'].str.contains('Visitante')].index, inplace=True)

    # Descarta los registros correspondientes a personal directivo, del cómputo de faltas
    df.drop(df[df['Name'].str.contains('Director')].index, inplace=True)

    # Descarta los registros correspondientes a trabajadores borrados, del cómputo de faltas
    df.drop(df[df['Name'].str.contains('New node')].index, inplace=True)

    # Descarta los registros correspondientes a personal de soporte y pruebas, del cómputo de faltas
    df.drop(df[df['Name'].str.contains('Soporte y Pruebas')].index, inplace=True)

    # Descarta los registros correspondientes a Incapacidad IMSS Riesgo de Trabajo, del cómputo de faltas
    df.drop(df[df['Exceptions'].str.contains('[057]')].index, inplace=True)

    # Descarta los registros correspondientes a permiso sin goce de sueldo 069, del cómputo de faltas
    df.drop(df[df['Exceptions'].str.contains('Permiso Sin Goce de Sueldo')].index, inplace=True)

    # Descarta los registros correspondientes a Día de castigo 069, del cómputo de faltas
    df.drop(df[df['Exceptions'].str.contains('Día de castigo')].index, inplace=True)

    # Descarta los registros correspondientes a vacaciones, del cómputo de faltas
    df.drop(df[df['Exceptions'].str.contains('[801]')].index, inplace=True)

    # Descarta los registros correspondientes a falta con goce de sueldo 800, del cómputo de faltas
    df.drop(df[df['Exceptions'].str.contains('falta con goce de sueldo')].index, inplace=True)

    # Descarta los registros correspondientes a dias feriados, del cómputo de faltas
    df.drop(df[df['Exceptions'].str.contains('Dia No Laborable General de Ley día feriado')].index, inplace=True)

    # Descarta los registros correspondientes a Incapacidad IMSS Enfermedad General 060, del cómputo de faltas
    df.drop(df[df['Exceptions'].str.contains('Incapacidad IMSS Enfermedad General')].index, inplace=True)

    # Descarta los registros correspondientes a omisión de registro de entrada
    df.drop(df[df['InHour'].str[11:16] > '00:00'].index, inplace=True)

    # Filtra las columnas necesarias para el reporte de faltas injustificadas
    df = df.filter(items=['ExportId', 'Name', 'OU5', 'Date', 'TimeGroup', 'Exceptions'])

    # Renombra las columnas del reporte
    df.columns = ['Código de empleado', 'Nombre del empleado',
                  'Departamento', 'Fecha', 'Horario', 'Excepción']

    # Envía los resultados del DataFrame a las filas del data table
    data = [{'name': i, 'id': i} for i in df.to_dict('rows')]

    # Retorna los registros para actualizar la tabla
    return data


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

这是我用于仪表板应用程序的组件:

attrs==19.1.0
certifi==2018.11.29
chardet==3.0.4
Click==7.0
Cython==0.29.6
dash==0.39.0
dash-core-components==0.44.0
dash-html-components==0.14.0
dash-renderer==0.20.0
dash-table==3.6.0
decorator==4.3.2
Flask==1.0.2
Flask-Compress==1.4.0
gunicorn==19.9.0
idna==2.8
ipython-genutils==0.2.0
itsdangerous==1.1.0
Jinja2==2.10
jsonschema==3.0.1
jupyter-core==4.4.0
lxml==4.3.2
MarkupSafe==1.1.1
nbformat==4.4.0
numpy==1.16.2
pandas==0.24.1
pandas-datareader==0.7.0
plotly==3.6.1
pyrsistent==0.14.11
python-dateutil==2.8.0
pytz==2018.9
requests==2.21.0
retrying==1.3.3
six==1.12.0
traitlets==4.3.2
urllib3==1.24.1
Werkzeug==0.14.1
wrapt==1.11.1

什么可能导致此行为?

1 个答案:

答案 0 :(得分:0)

我多次遇到dash_table的相同问题。 最终,在所有这些时间里,它是以下之一:

  1. 您可能不正确地传递了数据。也许df.to_dict('rows')应该是df.to_dict('rows')?另外,为什么还要对此进行迭代并将其用作值?检查您的数据类型,这很可能是您的问题。参见https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_dict.html,您可以简单地将df.to_dict('records')作为响应传递给

        # Envía los resultados del DataFrame a las filas del data table
        # data = [{'name': i, 'id': i} for i in df.to_dict('rows')]
        return df.to_dict('records')
    

        # Envía los resultados del DataFrame a las filas del data table
        data = [{'name': i['name'], 'id': i['id']} for i in df.to_dict('records')]
        return data
    

    这也可以进一步简化。

  2. 您的布局可能有问题。我在那里没有发现任何问题,因此我无法提供任何建议。尝试使用[{'name':'test1', 'id': 'test2'}]之类的小型模拟数据对其进行测试,看看是否可行。

  3. 编辑刚刚回想起,冻结表可能还会出现一个问题,该表停止响应那些被错误数据馈送的冻结表。例如,当您加载破折页时,将自动触发所有回调。您可能还想检查一下。

祝你好运!