Complex header column titles as ladders in child rows created by responsive

Complex header column titles as ladders in child rows created by responsive

RaidekRaidek Posts: 69Questions: 7Answers: 0

Description of problem:
I am using the pandas.DataFrame.to_html method, which you can find here. My backend is Flask so I can use Pandas.

Since it creates the HTML code of the dataframe in execution, aspects such as the style of the table are managed with the classes parameter. What you can see in the return you can see how I have put the responsive directly with dt-responsive nowrap and a custom CSS table-style which I will talk about later, plus Bootstrap 5 styles.
In my backend there is this:

#PYHTON-FLASK
my_dict = {
        ' ': {'Tecnología': ['PROSA', 'JAVA', 'C', 'JAVA', 'PROSA', 'C', 'Python'],
              'Tipo de cambio': ['Correctivo', 'Nuevo', 'Nuevo', 'Evolutivo', 'Evolutivo', 'Correctivo', 'Correctivo'],
              'Metodología': ['Waterfall', 'Agile', 'Waterfall', 'Agile', 'Waterfall', 'Agile', 'Agile'],
              'Centro': ['TGSS', 'INSS', 'GISS', 'ISM', 'ISM', 'GISS', 'INSS'],
              'Lote': ['LOTE6', 'LOTE6', 'LOTE6', 'LOTE4', 'LOTE5', 'LOTE4', 'LOTE5'],
              'Aplicación': ['RASS', 'ACAR', 'TRHA', 'SIGE', 'GEMA', 'FRIN', 'RARI'],
              'Version': ['01.12.16', '01.12.16', '01.02.03', '03.12.16', '01.14.16', '01.00.16', '01.12.20']},
        'Pruebas de vulnerabilidad': {'Recomendación': ['SI', 'NO', 'NO', 'NO', 'SI', 'SI', 'SI'],
                                      'Decisión': ['SI', 'SI', 'PDTE', 'SI', 'SI', 'NO', 'PDTE']},
        'Pruebas de accesibilidad': {'Recomendación': ['SI', 'NO', 'NO', 'NO', 'SI', 'SI', 'SI'],
                                     'Decisión': ['SI', 'SI', 'PDTE', 'SI', 'SI', 'NO', 'PDTE']},
        'Pruebas de rendimiento': {'Recomendación': ['SI', 'NO', 'NO', 'NO', 'SI', 'SI', 'SI'],
                                   'Decisión': ['SI', 'SI', 'PDTE', 'SI', 'SI', 'NO', 'PDTE']},
        'Pruebas funcionales': {'Excepciones CONF predichas': ['0-0.4', '0.4-1', '1+', '0.5-0.9', '0.3-1', '1+', '0.1-0.2'],
                                   'Excepciones DEV predichas': ['0.5-3', '0.5-3', '3+', '1+', '0.5-1', '2+', '0.6-3'],
                                   'Decisión': ['SI', 'SI', 'PDTE', 'SI', 'SI', 'NO', 'PDTE']}
    }

    reform = {(level1_key, level2_key): values
              for level1_key, level2_dict in my_dict.items()
              for level2_key, values in level2_dict.items()
              }
    df = pd.DataFrame(reform)

    return render_template('template.html', data=df.to_html(index=False, justify='center', classes=['table', 'table-striped', 'table-bordered', 'table-hover', 'table-condensed', 'dt-responsive nowrap','table-style'], table_id='ultimoAnalisis'))

And in the future I will receive tables from a SQL Server that I will have to pass to a dataframe to make some modifications. That is why I have harcoded an exact dataframe with 7 rows for testing.

In order to create a table with a complex header I had to create the dictionary that way. At first you can see that I put several simple columns inside an empty complex column. This is basically so that the code immediately following the dictionary works and creates a dataframe with a complex header.

Another problem that I found is that logically I could not paint the headers, and that I could not justify the text of the entire table in the center since when I put:

columnDefs: [
        {
          targets:"_all",
          className: 'dt-center'
        },

the JavaScript part was focused on everything except the complex header content.
On the other hand, the .to_html method put a

style="width: 1800px;"

in the <table> tag that got into the ```element.style{ width: 1800px;}. This caused the responsiveness of the table to not work well.
To fix these 3 things (header color, center-justify complex header text and fix responsiveness) create a CSS template with this:

.table-style thead { 
    background-color: #5f5f5f;
    color: #fff;
    text-align:center;
}

.table-style {
    width: 100% !important;
}

My template.html currently looks like this (removing the imports and a <nav>):

<div style="margin-left: 0.9%; margin-right: 0.9%">
  {{data | safe}}
</div>

{{data | safe}} it's how Jinja2 saves things returned to it from the backend (roughly). You can see more here. This is where the HTML generated by .to_html will be pasted.

<script>
  
  $(document).ready(function () {
    $("#ultimoAnalisis").DataTable({ //Parte DataTable

      language: {//Pone en español todo lo referente a datatables
        url: "../static/dataTables/es-ES.json"
      },

      searchPanes: { //Activa los filtros
        cascadePanes: true, //Activa filtros en cascada
        viewTotal: true, //Muestra el total de registros en los filtros
        initCollapsed: true, //Filtros cerrados de manera inicial
        order: [//Orden de los filtros
          "Centro",
          "Lote",
          "Aplicación",
          "Tecnología",
          "Tipo de cambio",
          "Metodología",
        ], 
      },
      dom: "Plfrtip",
      columnDefs: [
        {
          //Alineamos el texto de las columnas en el centro en la zona de filas. (En el caso de las cabeceras se controla por CSS en tabla.css)  
          targets:"_all",
          className: 'dt-body-center'
        },
        {
          //Ocultar las filtros de: 'Version', 'Pruebas de vulnerabilidad','Pruebas de accesibilidad','Pruebas de rendimiento','Pruebas de funcionales'
          targets: [6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
          searchPanes: {
            show: false,
          },
        },
        {
          //Forzar a que se muestren los filtros de la columna 'Aplicación'
          targets: [5],
          searchPanes: {
            show: true,
          },
        },
        {
          //Ocultar las columnas: 'Centro', 'Lote','Tecnología','Tipo de cambio','Metodología'
          targets: [0, 1, 2, 3, 4],
          visible: false,
        },
      ],
    });
  });
</script>

El resultado de mi tabla es este:

But when it comes to responsiveness, look at this video that I made in 20 seconds. (Sorry about the music... I recorded with Windows+G and I thought I was listening to music).
So several questions:

  1. What happens in the second 12 can be fixed.
  2. During the video you can see how childrows are created as they are hidden. In them appears the name of the column in bold and the value. But the name of the complex column does not appear anywhere. That is, I want it to look something like this (I make a sketch with colors):

THANKS

Answers

  • colincolin Posts: 15,240Questions: 1Answers: 2,599

    Without seeing, it's hard to say if there's a quick fix. I suspect the issue is the colspan header cells. It would be worth looking at our Responsive plugin, as that does something similar, but again, that wouldn't support the double header rows with colspan,

    Colin

  • RaidekRaidek Posts: 69Questions: 7Answers: 0

    Yes, that is the extension I am using. I activate it by passing dt-responsive nowrap to <table> with the classes parameter to .to_html. You can see it in the return of the first block of code in my post (line 27).

    Here you can see some of the code that generates .to_html, in this case the table part. On line 10 is the complex header part and on line 18 is the simple header part:

    <table
      border="1"
      class="dataframe table table-striped table-bordered table-hover table-condensed dt-responsive nowrap table-style dataTable no-footer dtr-inline collapsed"
      id="ultimoAnalisis"
      aria-describedby="ultimoAnalisis_info"
      style="width: 1599px"
    >
      <thead>
        <tr>
    ===========COMPLEX HEADER===========
          <th colspan="2" halign="left" rowspan="1"></th>
          <th colspan="2" halign="left" rowspan="1">Pruebas de vulnerabilidad</th>
          <th colspan="2" halign="left" rowspan="1">Pruebas de accesibilidad</th>
          <th colspan="2" halign="left" rowspan="1">Pruebas de rendimiento</th>
          <th colspan="3" halign="left" rowspan="1">Pruebas funcionales</th>
        </tr>
        <tr>
    ===========SIMPLE HEADER===========
          <th
            class="dt-body-center sorting"
            tabindex="0"
            aria-controls="ultimoAnalisis"
            rowspan="1"
            colspan="1"
            style="width: 79px"
            aria-label="Aplicación: Activar para ordenar la columna de manera ascendente"
          >
            Aplicación
          </th>
          <th
            class="dt-body-center sorting"
            tabindex="0"
            aria-controls="ultimoAnalisis"
            rowspan="1"
            colspan="1"
            style="width: 56px"
            aria-label="Version: Activar para ordenar la columna de manera ascendente"
          >
            Version
          </th>
          <th
            class="dt-body-center sorting"
            tabindex="0"
            aria-controls="ultimoAnalisis"
            rowspan="1"
            colspan="1"
            style="width: 120px"
            aria-label="Recomendación: Activar para ordenar la columna de manera ascendente"
          >
            Recomendación
          </th>
          <th
            class="dt-body-center sorting"
            tabindex="0"
            aria-controls="ultimoAnalisis"
            rowspan="1"
            colspan="1"
            style="width: 64px"
            aria-label="Decisión: Activar para ordenar la columna de manera ascendente"
          >
            Decisión
          </th>
          <th
            class="dt-body-center sorting"
            tabindex="0"
            aria-controls="ultimoAnalisis"
            rowspan="1"
            colspan="1"
            style="width: 120px"
            aria-label="Recomendación: Activar para ordenar la columna de manera ascendente"
          >
            Recomendación
          </th>
          <th
            class="dt-body-center sorting"
            tabindex="0"
            aria-controls="ultimoAnalisis"
            rowspan="1"
            colspan="1"
            style="width: 64px"
            aria-label="Decisión: Activar para ordenar la columna de manera ascendente"
          >
            Decisión
          </th>
          <th
            class="dt-body-center sorting"
            tabindex="0"
            aria-controls="ultimoAnalisis"
            rowspan="1"
            colspan="1"
            style="width: 120px"
            aria-label="Recomendación: Activar para ordenar la columna de manera ascendente"
          >
            Recomendación
          </th>
          <th
            class="dt-body-center sorting"
            tabindex="0"
            aria-controls="ultimoAnalisis"
            rowspan="1"
            colspan="1"
            style="width: 64px"
            aria-label="Decisión: Activar para ordenar la columna de manera ascendente"
          >
            Decisión
          </th>
          <th
            class="dt-body-right sorting"
            tabindex="0"
            aria-controls="ultimoAnalisis"
            rowspan="1"
            colspan="1"
            style="width: 215px"
            aria-label="Excepciones CONF predichas: Activar para ordenar la columna de manera ascendente"
          >
            Excepciones CONF predichas
          </th>
          <th
            class="dt-body-right sorting"
            tabindex="0"
            aria-controls="ultimoAnalisis"
            rowspan="1"
            colspan="1"
            style="width: 203px"
            aria-label="Excepciones DEV predichas: Activar para ordenar la columna de manera ascendente"
          >
            Excepciones DEV predichas
          </th>
          <th
            class="dt-body-center sorting"
            tabindex="0"
            aria-controls="ultimoAnalisis"
            rowspan="1"
            colspan="1"
            style="width: 64px; display: none"
            aria-label="Decisión: Activar para ordenar la columna de manera ascendente"
          >
            Decisión
          </th>
        </tr>
      </thead>
      <tbody>
        <tr class="odd dt-hasChild parent">
          <td class="dt-body-center dtr-control" tabindex="0" style="">TRHA</td>
          <td class="dt-body-center">01.02.03</td>
          <td class="dt-body-center">NO</td>
          <td class="dt-body-center">PDTE</td>
          <td class="dt-body-center">NO</td>
          <td class="dt-body-center">PDTE</td>
          <td class="dt-body-center">NO</td>
          <td class="dt-body-center">PDTE</td>
          <td class="dt-body-right">1+</td>
          <td class="dt-body-right">3+</td>
          <td class="dt-body-center" style="display: none">PDTE</td>
        </tr>
        <tr class="child">
          <td class="child" colspan="10">
            <ul data-dtr-index="2" class="dtr-details">
              <li
                class="dt-body-center"
                data-dtr-index="15"
                data-dt-row="2"
                data-dt-column="15"
              >
                <span class="dtr-title">Decisión</span>
                <span class="dtr-data">PDTE</span>
              </li>
            </ul>
          </td>
        </tr>
        <tr class="even">
          <td class="dt-body-center dtr-control" tabindex="0">FRIN</td>
          <td class="dt-body-center">01.00.16</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">NO</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">NO</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">NO</td>
          <td class="dt-body-right">1+</td>
          <td class="dt-body-right">2+</td>
          <td class="dt-body-center" style="display: none">NO</td>
        </tr>
        <tr class="odd">
          <td class="dt-body-center dtr-control" tabindex="0">ACAR</td>
          <td class="dt-body-center">01.12.16</td>
          <td class="dt-body-center">NO</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">NO</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">NO</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-right">0.4-1</td>
          <td class="dt-body-right">0.5-3</td>
          <td class="dt-body-center" style="display: none">SI</td>
        </tr>
        <tr class="even">
          <td class="dt-body-center dtr-control" tabindex="0">SIGE</td>
          <td class="dt-body-center">03.12.16</td>
          <td class="dt-body-center">NO</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">NO</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">NO</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-right">0.5-0.9</td>
          <td class="dt-body-right">1+</td>
          <td class="dt-body-center" style="display: none">SI</td>
        </tr>
        <tr class="odd">
          <td class="dt-body-center dtr-control" tabindex="0">RASS</td>
          <td class="dt-body-center">01.12.16</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-right">0-0.4</td>
          <td class="dt-body-right">0.5-3</td>
          <td class="dt-body-center" style="display: none">SI</td>
        </tr>
        <tr class="even">
          <td class="dt-body-center dtr-control" tabindex="0">GEMA</td>
          <td class="dt-body-center">01.14.16</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-right">0.3-1</td>
          <td class="dt-body-right">0.5-1</td>
          <td class="dt-body-center" style="display: none">SI</td>
        </tr>
        <tr class="odd">
          <td class="dt-body-center dtr-control" tabindex="0">RARI</td>
          <td class="dt-body-center">01.12.20</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">PDTE</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">PDTE</td>
          <td class="dt-body-center">SI</td>
          <td class="dt-body-center">PDTE</td>
          <td class="dt-body-right">0.1-0.2</td>
          <td class="dt-body-right">0.6-3</td>
          <td class="dt-body-center" style="display: none">PDTE</td>
        </tr>
      </tbody>
    </table>
    

    I have seen this: responsive.details.display, and I think it is the solution, but I don't know how to approach it.

    Regarding what happens in the video, in the second 12, nothing can be done, right?

    Thanks Colin.

  • kthorngrenkthorngren Posts: 21,443Questions: 26Answers: 4,974

    Regarding what happens in the video, in the second 12, nothing can be done, right?

    As Colin mentioned the Responsive extension doesn't support complex headers with colspan. However you probably could use the responsive-resize event to manage the thead rows that Responsive doesn't support. Use the column parameter to see which columns are hidden then, based on your requirements, you can hide or display the columns with colspan.

    Kevin

Sign In or Register to comment.