Métriques/KPI et tableaux de données

Les graphes, les cartes, les tableaux et les calendriers sont les vues par défaut. Vous découvrirez de nombreux autres paramètres dans cette documentation. Vous verrez également des widgets moins connus mais tout aussi intéressants que ceux généralement utilisés.

Reportez-vous à la liste des widgets pour plus d’informations.

Choisir un jeu de données

Pour décrire les métriques, les KPI, les infobulles de cartes avancées, ainsi que d’autres fonctions, nous utiliserons un jeu de données contenant tous les rapports de régularité de la SNCF depuis 2011. Ce jeu de données contient, pour chaque ligne de TGV (100 lignes), le nombre de trains programmés chaque mois, le nombre de trains annulés et le nombre de trains en retard à l’arrivée.

ID du jeu de données : regularite-mensuelle-tgv Vous pouvez le rechercher sur data.opendatasoft.com Ajoutez ensuite ce jeu de données sur votre domaine (Nouveau jeu de données, Ajouter une source depuis le réseau OpenDataSoft, choisir le jeu de données, enregistrer, publier)

Créer des KPI

Pour créer des métriques/KPI, nous utilisons la fonction odsAggregation, afin de calculer la somme, la moyenne, la valeur minimale et la valeur maximale d’un champ de données. En fonction du contexte, la métrique se met à jour de manière dynamique à mesure que l’utilisateur poursuit sa navigation (requêtes, filtres).

Depuis une nouvelle page, commençons par obtenir un contexte à partir de ce jeu de données. La méthode la plus simple consiste à accéder à la page d’exploration/du catalogue, puis d’accéder au jeu de données. Ensuite, dans la vue tableau, copiez et collez le code de widget depuis l’encadré ci-dessous :

<ods-dataset-context
        context="regularitemensuelletgv"
        regularitemensuelletgv-dataset="regularite-mensuelle-tgv">

        <ods-table context="regularitemensuelletgv"></ods-table>

</ods-dataset-context>

Au-dessus de la vue tableau, nous allons ajouter un compteur basé sur le champ nombre_de_trains_programmes. Cela nous permettra d’obtenir le nombre de trains programmés depuis 2011 en France.

Avec la fonction odsAggregation, les paramètres sont les suivants :
  • le nom de la variable qui stockera le résultat de l’agrégation

  • le contexte sur lequel travailler

  • la fonction

  • l’expression (le nom du champ)

Avec un filtre number pour un affichage correct dans un tag HTML span, vous devriez obtenir le résultat suivant :

<div class="container">

    <ods-dataset-context
                         context="regularitemensuelletgv"
                         regularitemensuelletgv-dataset="regularite-mensuelle-tgv">

        <div ods-aggregation="myvar"
             ods-aggregation-context="regularitemensuelletgv"
             ods-aggregation-function="SUM"
             ods-aggregation-expression="nombre_de_trains_programmes">

                <span>Scheduled train : {{ myvar | number }}</span>

        </div>

        <br/>

        <ods-table context="regularitemensuelletgv"></ods-table>

    </ods-dataset-context>

</div>

Un nombre (environ 1,7 million) s’affiche en haut de la page, il nécessite du code CSS pour le mettre en valeur. Les métriques sont souvent affichées dans un cadre, avec une grande taille de police et mises en gras.

Ajoutez ce code CSS à votre page :

.kpi {
    padding: 2px 30px; /* Give some air to the digits */
    border: 1.5px solid #010201; /* the border */
    border-radius: 5px; /* rounded corners */
    font-size: 2em; /* bigger font */
    font-weight: 500; /* thicker font */
    margin: 10px 5px; /* give some air around the KPI */
}

Ajoutez également la classe KPI à votre tag span.

Enregistrez, actualisez la page et admirez le résultat.

Avant de poursuivre avec CSS et en particulier avec le code responsive, ajoutons 2 métriques supplémentaires : nombre_de_trains_annules et nombre_de_trains_en_retard_a_l_arrivee

<div ods-aggregation="myvar"
     ods-aggregation-context="regularitemensuelletgv"
     ods-aggregation-function="SUM"
     ods-aggregation-expression="nombre_de_trains_programmes">
        <span class="kpi">Scheduled train : {{ myvar | number }}</span>
</div>

<br/>

<div ods-aggregation="myvar"
     ods-aggregation-context="regularitemensuelletgv"
     ods-aggregation-function="SUM"
     ods-aggregation-expression="nombre_de_trains_annules">
        <span class="kpi">Canceled train : {{ myvar | number }}</span>
</div>

<br/>

<div ods-aggregation="myvar"
     ods-aggregation-context="regularitemensuelletgv"
     ods-aggregation-function="SUM"
     ods-aggregation-expression="nombre_de_trains_en_retard_a_l_arrivee">
        <span class="kpi">Delayed train : {{ myvar | number }}</span>
</div>

<br/>

<ods-table context="regularitemensuelletgv"></ods-table>

Résultat :

../../../_images/advanced__kpi-1.png

Cela fonctionne, mais toutes les métriques sont indépendantes. Nous pouvons ajouter des filtres pour les rendre dynamiques en fonction des filtres des utilisateurs, etc. mais elles ne peuvent pas être utilisées pour calculer quoi que ce soit. Il serait intéressant d’obtenir le pourcentage de trains annulés ou en retard.

Pour cela, vous devez chaîner la fonction ods-aggregation à différents noms de variables.

Votre code doit ressembler à ceci :

    <div ods-aggregation="total"
     ods-aggregation-context="regularitemensuelletgv"
     ods-aggregation-function="SUM"
     ods-aggregation-expression="nombre_de_trains_programmes">
    <div ods-aggregation="canceled"
         ods-aggregation-context="regularitemensuelletgv"
         ods-aggregation-function="SUM"
         ods-aggregation-expression="nombre_de_trains_annules">
        <div ods-aggregation="delayed"
             ods-aggregation-context="regularitemensuelletgv"
             ods-aggregation-function="SUM"
             ods-aggregation-expression="nombre_de_trains_en_retard_a_l_arrivee">

                <span class="kpi">Scheduled : {{ total | number }}</span>
                <span class="kpi">Canceled : {{ canceled | number }}</span>
                <span class="kpi">Delayed : {{ delayed | number }}</span>
        </div>
    </div>
</div>

Il est désormais possible, avec une expression AngularJS, de calculer des pourcentages parmi les valeurs :

<span class="kpi">Scheduled : {{ total | number }}</span>
<span class="kpi">Canceled : {{ canceled | number }}</span>
<span class="kpi">Delayed : {{ delayed | number }}</span>
<span class="kpi">% Canceled : {{ canceled / total * 100 | number : 2 }}%</span>
<span class="kpi">% Delayed : {{ delayed / total * 100 | number : 2 }}%</span>

Remarque

| number : 2 correspond au filtre AngularJS pour imprimer automatiquement des valeurs numériques. Le paramètre optionnel 2 permet de limiter la valeur à 2 décimales

Avant de poursuivre, nettoyons le code HTML afin de pouvoir appliquer une CSS pour obtenir un affichage responsive, utiliser des tailles de polices différentes pour les titres et les valeurs, etc. :

<div class="row">
    <div class="col-md-2 col-sm-3 col-xs-4">
        <div class="kpi">
            <div class="kpi-title">
                Scheduled
            </div>
            <div class="kpi-value">
                {{ total | number }}
            </div>
        </div>
    </div>
    <div class="col-md-2 col-sm-3 col-xs-4">
        <div class="kpi">
            <div class="kpi-title">
                Canceled
            </div>
            <div class="kpi-value">
                {{ canceled | number }}
            </div>
        </div>
    </div>
    <div class="col-md-2 col-sm-3 col-xs-4">
        <div class="kpi">
            <div class="kpi-title">
                Delayed
            </div>
            <div class="kpi-value">
                {{ delayed | number }}
            </div>
        </div>
    </div>
    <div class="col-md-2 col-sm-3 col-xs-4">
        <div class="kpi">
            <div class="kpi-title">
                % Canceled
            </div>
            <div class="kpi-value">
                {{ canceled / total * 100 | number : 2 }}<span class="kpi-value-unit"> %</span>
            </div>
        </div>
    </div>
    <div class="col-md-2 col-sm-3 col-xs-4">
        <div class="kpi">
            <div class="kpi-title">
                % Delayed

            </div>
            <div class="kpi-value">
                {{ delayed / total * 100 | number : 2 }}<span class="kpi-value-unit"> %</span>
            </div>
        </div>
    </div>
    <div class="col-md-2 col-sm-3 col-xs-4">
        <div class="kpi">

            <div class="kpi-title">
                On time
            </div>
            <div class="kpi-value">
                {{ total - delayed - canceled | number }}
            </div>
        </div>
    </div>
</div>

Et remplacez la CSS :

.kpis {
    display: inline-flex;
}

.kpi {
    text-align: center;

    padding: 5px 0px;
    margin-bottom: 10px;
    height: 70px;

    border: 1.5px solid #010201; /* the border */
    border-radius: 5px; /* rounded corners */
}

.kpi-title {
    font-size: 1em; /* bigger font */
    font-weight: 400; /* thicker font */
}

.kpi-value {
    font-size: 2em; /* bigger font */
    font-weight: 500; /* thicker font */
}

.kpi-value-unit {
    font-size: 1.5rem; /* bigger font */
    font-weight: 400; /* thicker font */
}

Enregistrez, actualisez la page et observez le résultat :

../../../_images/advanced__kpi-2.png

intégrer un code couleur à la directive ng-class de vos KPI

La directive ng-class se révèle être très pratique lorsqu’un style doit être appliqué à un élément HTML en fonction d’une valeur, d’un contexte, d’une expression ou de tout autre élément dynamique pouvant être utilisé dans une expression AngularJS.

Par exemple, pour définir des couleurs en fonction d’un seuil sur nos métriques, vert si le pourcentage de trains annulés est inférieur à 0,20 % et rouge s’il est supérieur, ajoutez ceci à votre élément :

<div class="col-md-2 col-sm-3 col-xs-4">
    <div class="kpi" ng-class="{'good' : canceled / total * 100 < 0.2, 'bad' : canceled / total * 100 >= 0.2}">
        <div class="kpi-title">
            % Canceled
        </div>
        <div class="kpi-value">
            {{ canceled / total * 100 | number : 2 }}<span class="kpi-value-unit"> %</span>
        </div>
    </div>
</div>

Et cette CSS :

.good {
    color: #55cd61;
    border-color: #55cd61;
}

.medium {
    color: #ff9c22;
    border-color: #ff9c22;
}

.bad {
    color: #e50000;
    border-color: #e50000;
}

Enregistrez, actualisez la page et vous verrez que nos métriques sont désormais affichées en rouge (la classe bad de la CSS est utilisée)

Pour observer le comportement dynamique, ajoutons quelques filtres à gauche du tableau (sur la deuxième ligne). Pour cela :
  • ajoutez un tag div``avec la classe ``row autour du tableau

  • ajoutez un tag div avec la classe col-md-9 autour du tableau

  • ajoutez un widget ods-facets contenant 2 facettes ods-facet pour les filtres date et depart

  • entourez les ods-facets d’un tag div avec le style col-md-3

  • si vous le souhaitez, ajoutez des tags div avec le style ods-box pour entourer les blocs avec un fond blanc

Votre code devrait ressembler à ceci :

<div class="row">
    <div class="col-md-3">
        <div class="ods-box">
            <ods-facets context="regularitemensuelletgv">
                <h2>
                    Date
                </h2>
                <ods-facet name="date"></ods-facet>
                <h2>
                    Origin station
                </h2>
                <ods-facet name="depart"></ods-facet>
            </ods-facets>
        </div>
    </div>
    <div class="col-md-9">
        <div class="ods-box">
            <ods-table context="regularitemensuelletgv"></ods-table>
        </div>
    </div>
</div>

Enregistrez, actualisez la page et observez comment les métriques se comportent lorsque des filtres sont sélectionnés. En 2013, moins de 0,20 % des trains au départ de la gare Paris EST ont été annulés. Prenez le temps d’observer les effets des filtres sur les métriques.

../../../_images/advanced__kpi-ngclass-1.png ../../../_images/advanced__kpi-ngclass-2.png

Remarque

La syntaxe de la directive ng-class est, entre accolades, la classe CSS entre guillemets simples suivie de deux points :, puis l’expression AngularJS :

{ 'classe CSS' : expression AngularJS, ... }

Plusieurs classes et expressions peuvent être spécifiées, toutes les expressions seront testées, de gauche à droite.

Faire des comparaisons à l’aide de filtres : mettre en valeur les différences avec des couleurs

Il est intéressant de comparer l’ensemble du jeu de données avec une vue sur laquelle sont appliqués les filtres de l’utilisateur, afin de voir si les métriques (en particulier les pourcentages) varient à la hausse ou à la baisse.

L’idée consiste à avoir 2 contextes, le premier représentant le jeu de données dans son intégralité, et le second pouvant être filtré par l’utilisateur. Lorsqu’un filtre est appliqué, si la métrique est supérieure ou inférieure à la métrique du jeu de données complet, elle sera affichée dans une couleur différente.

Pour cela, vous devez :
  • disposer d’un contexte secondaire

  • injecter ods-facets et ods-table sur ce contexte secondaire

  • calculer les mêmes métriques sur les deux contextes

  • ajouter la métrique du contexte secondaire SI et SEULEMENT SI un filtre a été sélectionné

  • configurer la directive ng-class pour comparer le jeu de données complet et les métriques sur lesquelles sont appliqués des filtres

C’est parti !

Deux contextes, un jeu de données :

<ods-dataset-context
                     context="regularitemensuelletgv,regularitemensuelletgvfiltered"
                     regularitemensuelletgv-dataset="regularite-mensuelle-tgv"
                     regularitemensuelletgvfiltered-dataset="regularite-mensuelle-tgv">

Les blocs entiers des métriques doivent désormais ressembler à ceci :

<div ods-aggregation="total"
     ods-aggregation-context="regularitemensuelletgv"
     ods-aggregation-function="SUM"
     ods-aggregation-expression="nombre_de_trains_programmes">
    <div ods-aggregation="canceled"
         ods-aggregation-context="regularitemensuelletgv"
         ods-aggregation-function="SUM"
         ods-aggregation-expression="nombre_de_trains_annules">
        <div ods-aggregation="delayed"
             ods-aggregation-context="regularitemensuelletgv"
             ods-aggregation-function="SUM"
             ods-aggregation-expression="nombre_de_trains_en_retard_a_l_arrivee">

            <div ods-aggregation="totalfiltered"
                 ods-aggregation-context="regularitemensuelletgvfiltered"
                 ods-aggregation-function="SUM"
                 ods-aggregation-expression="nombre_de_trains_programmes">
                <div ods-aggregation="canceledfiltered"
                     ods-aggregation-context="regularitemensuelletgvfiltered"
                     ods-aggregation-function="SUM"
                     ods-aggregation-expression="nombre_de_trains_annules">
                    <div ods-aggregation="delayedfiltered"
                         ods-aggregation-context="regularitemensuelletgvfiltered"
                         ods-aggregation-function="SUM"
                         ods-aggregation-expression="nombre_de_trains_en_retard_a_l_arrivee">

                        <div class="row">
                            <div class="col-md-2 col-sm-3 col-xs-4">
                                <div class="kpi">
                                    <div class="kpi-title">
                                        Scheduled
                                    </div>
                                    <div class="kpi-value">
                                        {{ totalfiltered | number }}
                                    </div>
                                    <div class="kpi-value-reference">
                                        ({{ total | number }})
                                    </div>
                                </div>
                            </div>
                            <div class="col-md-2 col-sm-3 col-xs-4">
                                <div class="kpi">
                                    <div class="kpi-title">
                                        Canceled
                                    </div>
                                    <div class="kpi-value">
                                        {{ canceledfiltered | number }}
                                    </div>
                                    <div class="kpi-value-reference">
                                        ({{ canceled | number }})
                                    </div>
                                </div>
                            </div>
                            <div class="col-md-2 col-sm-3 col-xs-4">
                                <div class="kpi">
                                    <div class="kpi-title">
                                        Delayed
                                    </div>
                                    <div class="kpi-value">
                                        {{ delayedfiltered | number }}
                                    </div>
                                    <div class="kpi-value-reference">
                                        ({{ delayed | number }})
                                    </div>
                                </div>
                            </div>
                            <div class="col-md-2 col-sm-3 col-xs-4">
                                <div class="kpi">
                                    <div class="kpi-title">
                                        % Canceled
                                    </div>
                                    <div class="kpi-value">
                                        {{ canceledfiltered / totalfiltered * 100 | number : 2 }}<span class="kpi-value-unit"> %</span>
                                    </div>
                                    <div class="kpi-value-reference">
                                        ({{ canceled / total * 100 | number : 2 }}<span class="kpi-value-unit"> %</span>)
                                    </div>
                                </div>
                            </div>
                            <div class="col-md-2 col-sm-3 col-xs-4">
                                <div class="kpi">
                                    <div class="kpi-title">
                                        % Delayed

                                    </div>
                                    <div class="kpi-value">
                                        {{ delayedfiltered / totalfiltered * 100 | number : 2 }}<span class="kpi-value-unit"> %</span>
                                    </div>
                                    <div class="kpi-value-reference">
                                        ({{ delayed / total * 100 | number : 2 }}<span class="kpi-value-unit"> %</span>)
                                    </div>
                                </div>
                            </div>
                            <div class="col-md-2 col-sm-3 col-xs-4">
                                <div class="kpi">
                                    <div class="kpi-title">
                                        On time
                                    </div>
                                    <div class="kpi-value">
                                        {{ totalfiltered - delayedfiltered - canceledfiltered | number }}
                                    </div>
                                    <div class="kpi-value-reference">
                                        ({{ total - delayed - canceled | number }})
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

Adaptez la CSS en mettant à jour ou en ajoutant les classes suivantes :

.kpi {
    height: 90px;
    /* ... */
}

.kpi-value-reference {
    font-size: 1em; /* bigger font */
    font-weight: 400; /* thicker font */
}

.kpi-value-unit {
    font-size: 0.7em; /* bigger font */
    /* ... */
}

Enfin, appliquez un code couleur sur les métriques % en retard et % annulés. Si le résultat des données filtrées est supérieur à la moyenne totale, affichez-le en rouge, s’il est inférieur (meilleur), affichez-le en vert.

<div class="col-md-2 col-sm-3 col-xs-4">
    <div class="kpi" ng-class="{
                               'good': (canceledfiltered / totalfiltered * 100) < (canceled / total * 100),
                               'bad': (canceledfiltered / totalfiltered * 100) > (canceled / total * 100),
                               }">
        <div class="kpi-title">
            % Canceled
        </div>
        <div class="kpi-value">
            {{ canceledfiltered / totalfiltered * 100 | number : 2 }}<span class="kpi-value-unit"> %</span>
        </div>
        <div class="kpi-value-reference">
            ({{ canceled / total * 100 | number : 2 }}<span class="kpi-value-unit"> %</span>)
        </div>
    </div>
</div>
<div class="col-md-2 col-sm-3 col-xs-4">
    <div class="kpi" ng-class="{
                               'good': (delayedfiltered / totalfiltered * 100) < (delayed / total * 100),
                               'bad': (delayedfiltered / totalfiltered * 100) > (delayed / total * 100),
                               }">
        <div class="kpi-title">
            % Delayed

        </div>
        <div class="kpi-value">
            {{ delayedfiltered / totalfiltered * 100 | number : 2 }}<span class="kpi-value-unit"> %</span>
        </div>
        <div class="kpi-value-reference">
            ({{ delayed / total * 100 | number : 2 }}<span class="kpi-value-unit"> %</span>)
        </div>
    </div>
</div>

Enregistrez, actualisez la page et faites un essai sur l’année 2015 :

../../../_images/advanced__kpi-ngclass-3.png

Créer un tableau de données

odsAnalysis permet d’obtenir l’analyse d’une ou de plusieurs agrégations pour chaque valeur d’un champ. Cette fonction peut être apparentée à un graphe, à la différence qu’elle n’affiche pas des courbes, des colonnes ou des secteurs, mais renvoie chaque valeur, et vous avez la possibilité d’afficher ces dernières dans un tableau ou à l’aide d’une autre expression.

Tout d’abord, nous allons tester le résultat en configurant l’analyse correcte dans l’onglet Analyse du jeu de données. Il peut être intéressant d’afficher dans un tableau les 10 gares présentant la régularité la plus élevée. Pour cela, suivez la procédure ci-après :

  • Axe X : “départ” (station d’origine)
    • 4 séries : - AVG régularité (Régularité) - AVG nombre de trains programmés (nombre_de_trains_programmes) - AVG nombre de trains annulés (nombre_de_trains_annules) - AVG nombre de trains en retard à l’arrivée (nombre_de_trains_en_retard_a_l_arrivee)

  • triez la série par régularité

  • Nombre de points : 10 max.

../../../_images/advanced__data-table-1.png

L’objectif est de reproduire exactement cette analyse avec odsAnalysis. Pour rappel, veuillez consulter la documentation ici

Paramètres odsAnalysis :
  • ods-analysis : le nom de la variable

  • ods-analysis-context : le contexte sur lequel travailler

  • ods-analysis-max : 10 éléments max.

  • ods-analysis-x : le champ sur lequel travailler (toutes les agrégations seront calculées pour chaque valeur de ce champ)

  • ods-analysis-serie-xxx : définit une série appelée xxx basée sur une expression (le champ) et sur une fonction (AVG, MAX, MIN, SUM, etc.)

  • ods-analysis-sort : permet de trier une série en spécifiant l’argument name, ou -name pour inverser l’ordre du tri

Avant de vous plonger dans le code (HTML), observez les résultats stockés dans la variable :

<div class="row">
    <div ods-analysis="results"
         ods-analysis-context="regularitemensuelletgvfiltered"
         ods-analysis-max="10"
         ods-analysis-x="depart"
         ods-analysis-serie-regularity="AVG(regularite)"
         ods-analysis-serie-scheduled="AVG(nombre_de_trains_programmes)"
         ods-analysis-serie-canceled="AVG(nombre_de_trains_annules)"
         ods-analysis-serie-delayed="AVG(nombre_de_trains_en_retard_a_l_arrivee)"
         ods-analysis-sort="regularity"
         >
        {{ results }}
    </div>
</div>

Impression automatique du bloc JSON :

{
   "results":[
      {
         "scheduled":97.37288135593221,
         "canceled":0.2033898305084746,
         "regularity":94.60508474576272,
         "delayed":5.288135593220339,
         "x":"ST MALO"
      },
      {
         "scheduled":283.728813559322,
         "canceled":1.2203389830508475,
         "regularity":94.28813559322033,
         "delayed":16.135593220338983,
         "x":"NANCY"
      },
      {
         "scheduled":160.64406779661016,
         "canceled":0.559322033898305,
         "regularity":92.61186440677963,
         "delayed":11.677966101694915,
         "x":"QUIMPER"
      }
   ]
}

Nous avons une liste de résultats au format JSON, chaque bloc présente une valeur de x, la gare de départ, et 4 agrégations/valeurs correspondant à nos séries. La directive AngularJS ng-repeat permet de réaliser une itération sur la liste results. Pour chaque élément, nous imprimons une nouvelle ligne dans le tableau.

<div ods-analysis="tgvanalysis"
     ods-analysis-context="regularitemensuelletgvfiltered"
     ods-analysis-max="10"
     ods-analysis-x="depart"
     ods-analysis-serie-regularity="AVG(regularite)"
     ods-analysis-serie-scheduled="AVG(nombre_de_trains_programmes)"
     ods-analysis-serie-canceled="AVG(nombre_de_trains_annules)"
     ods-analysis-serie-delayed="AVG(nombre_de_trains_en_retard_a_l_arrivee)"
     ods-analysis-sort="regularity"
     >
    <table id="top10">
        <thead>
            <tr>
                <td>Position</td>
                <td>Train station</td>
                <td>Regularity</td>
                <td>Scheduled</td>
                <td>Canceled</td>
                <td>Delayed</td>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="(i, result) in tgvanalysis.results">
                <td>
                    {{ i + 1 }}
                </td>
                <td>
                    {{ result.x }}
                </td>
                <td>
                    {{ result.regularity | number : 2 }}
                </td>
                <td>
                    {{ result.scheduled | number : 2 }}
                </td>
                <td>
                    {{ result.canceled | number : 2 }}
                </td>
                <td>
                    {{ result.delayed | number : 2 }}
                </td>
            </tr>
        </tbody>
    </table>
</div>

Un peu de CSS pour un beau rendu du tableau en HTML :

#top10 {
    margin: 20px auto;
}

#top10 thead > tr {
    background-color: #007396;
    color: white;
}

#top10 td {
    min-width: 100px;
    padding: 3px 10px;
    text-align: center;
}

#top10 tr:nth-child(even) {
    background-color: #ededed;
}

#top10 tr:hover{
    background-color:#ccc;
}

Enregistrez, actualisez la page et jouez avec les filtres :

../../../_images/advanced__data-table-2.png