Widget Tricks - ods-aggregation

The technical documentation says :

This widget exposes the results of an aggregation function over a context… The result is exposed into a new variable that you can use in other widgets or directly in your HTML.

More concretely :

It computes a function like the sum, average, minimum, maximum etc.. over a numerical field. Depending on the context parameters, if filtered (queries, refines, etc…) it will compute the aggregation on a subset of the records, if not, on the entire dataset.

A simple ods-aggregation results

Count the number of record of a dataset, here : the number of US hospitals

<div class="row">
    <div class="col-sm-offset-4 col-sm-4">
        <ods-dataset-context context="ushospitals"
                             ushospitals-domain="userclub"
                             ushospitals-dataset="us-hospitals">
            <!-- KPI box component -->
            <div class="kpi-card">
                <i class="kpi-icon fa fa-hospital-o" aria-hidden="true"></i>
                <h2 class="kpi-title"
                    ods-aggregation="count"
                    ods-aggregation-context="ushospitals"
                    ods-aggregation-function="COUNT">
                    {{ count | number }}
                </h2>
                <p class="kpi-description">
                    Number of hospitals
                </p>
            </div>
        </ods-dataset-context>
    </div>
</div>
/* Variables & Shared classes
========================================================================== */
:root {
    --secondary-color: #142E7B;
}
.row-equal-height {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
    margin-bottom: 20px;
}
/* Fix for early content wrapping in Safari*/
.row-equal-height:before,
.row-equal-height:after {
    content: normal;
}
/* KPI Card
========================================================================== */
.kpi-card {
    background-color: var(--boxes-background);
    height: 100%;
    padding: 39px;
    border-radius: 4px;
    margin-bottom: 20px;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -ms-flex-direction: column;
    flex-direction: column;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    text-align: center;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    text-align: center;
}
.kpi-icon {
    color: var(--highlight);
    color: var(--secondary-color);
    font-size: 4rem;
    margin-top: 0;
    margin-bottom: 13px;
    max-width: 100%;
}
.kpi-title {
    font-weight: normal;
    color: var(--highlight);
    font-size: 3.2rem;
    margin-top: 0;
    margin-bottom: 13px;
    max-width: 100%;
}
.kpi-description {
    color: var(--text);
    font-size: 1rem;
    line-height: 1.5;
    font-weight: normal;
    margin-top: 0;
    margin-bottom: 0;
    max-width: 100%;
}
.kpi-description-detail {
    opacity: 0.9;
    font-style: italic;
    font-size: 0.9em;
    margin-top: 0.8em;
}

A simple ods-aggregation results

The same aggregation but this time on a filtered dataset

<div class="row">
    <div class="col-sm-offset-4 col-sm-4">
        <ods-dataset-context context="ushospitals"
                             ushospitals-domain="userclub"
                             ushospitals-dataset="us-hospitals"
                             ushospitals-parameters="{'refine.city':'Houston'}">
            <!-- KPI box component -->
            <div class="kpi-card">
                <i class="kpi-icon fa fa-hospital-o" aria-hidden="true"></i>
                <h2 class="kpi-title"
                    ods-aggregation="count"
                    ods-aggregation-context="ushospitals"
                    ods-aggregation-function="COUNT">
                    {{ count | number }}
                </h2>
                <p class="kpi-description">
                    Number of hospitals in Houston, TX
                </p>
            </div>
        </ods-dataset-context>
    </div>
</div>
/* Variables & Shared classes
========================================================================== */
:root {
    --secondary-color: #142E7B;
}
.row-equal-height {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
    margin-bottom: 20px;
}
/* Fix for early content wrapping in Safari*/
.row-equal-height:before,
.row-equal-height:after {
    content: normal;
}
/* KPI Card
========================================================================== */
.kpi-card {
    background-color: var(--boxes-background);
    height: 100%;
    padding: 39px;
    border-radius: 4px;
    margin-bottom: 20px;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -ms-flex-direction: column;
    flex-direction: column;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    text-align: center;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    text-align: center;
}
.kpi-icon {
    color: var(--highlight);
    color: var(--secondary-color);
    font-size: 4rem;
    margin-top: 0;
    margin-bottom: 13px;
    max-width: 100%;
}
.kpi-title {
    font-weight: normal;
    color: var(--highlight);
    font-size: 3.2rem;
    margin-top: 0;
    margin-bottom: 13px;
    max-width: 100%;
}
.kpi-description {
    color: var(--text);
    font-size: 1rem;
    line-height: 1.5;
    font-weight: normal;
    margin-top: 0;
    margin-bottom: 0;
    max-width: 100%;
}
.kpi-description-detail {
    opacity: 0.9;
    font-style: italic;
    font-size: 0.9em;
    margin-top: 0.8em;
}

A multiple ods-aggregation and a computation to get a new value from the results

The same two aggregation that before, declared in the same bloc, and used in a pourcentage formula in an AngularJS expression

<div class="row">
    <div class="col-sm-offset-4 col-sm-4">
        <ods-dataset-context context="ushospitals,ushospitalshelipad"
                             ushospitals-domain="userclub"
                             ushospitals-dataset="us-hospitals"
                             ushospitalshelipad-domain="userclub"
                             ushospitalshelipad-dataset="us-hospitals"
                             ushospitalshelipad-parameters="{'refine.helipad':'Y'}">
            <!-- KPI box component -->
            <div class="kpi-card">
                <i class="kpi-icon fa fa-h-square" aria-hidden="true"></i>
                <h2 class="kpi-title"
                    ods-aggregation="hospitals,hospitalshelipad"
                    ods-aggregation-hospitals-context="ushospitals"
                    ods-aggregation-hospitals-function="COUNT"
                    ods-aggregation-hospitalshelipad-context="ushospitalshelipad"
                    ods-aggregation-hospitalshelipad-function="COUNT">
                    {{ hospitalshelipad / hospitals * 100 | number : 0 }} %
                </h2>
                <p class="kpi-description">
                    of US hospitals are equipped with an helipad
                </p>
            </div>
        </ods-dataset-context>
    </div>
</div>
/* Variables & Shared classes
========================================================================== */
:root {
    --secondary-color: #142E7B;
}
.row-equal-height {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
    margin-bottom: 20px;
}
/* Fix for early content wrapping in Safari*/
.row-equal-height:before,
.row-equal-height:after {
    content: normal;
}
/* KPI Card
========================================================================== */
.kpi-card {
    background-color: var(--boxes-background);
    height: 100%;
    padding: 39px;
    border-radius: 4px;
    margin-bottom: 20px;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -ms-flex-direction: column;
    flex-direction: column;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    text-align: center;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    text-align: center;
}
.kpi-icon {
    color: var(--highlight);
    color: var(--secondary-color);
    font-size: 4rem;
    margin-top: 0;
    margin-bottom: 13px;
    max-width: 100%;
}
.kpi-title {
    font-weight: normal;
    color: var(--highlight);
    font-size: 3.2rem;
    margin-top: 0;
    margin-bottom: 13px;
    max-width: 100%;
}
.kpi-description {
    color: var(--text);
    font-size: 1rem;
    line-height: 1.5;
    font-weight: normal;
    margin-top: 0;
    margin-bottom: 0;
    max-width: 100%;
}
.kpi-description-detail {
    opacity: 0.9;
    font-style: italic;
    font-size: 0.9em;
    margin-top: 0.8em;
}

Evolution over past years

A multiple ods-aggregation on two different context

This example showcase the number of cities in France before and after a reform (2015 vs. 2016).

<div class="row">
    <div class="col-sm-offset-4 col-sm-4">
        <ods-dataset-context context="cities2015,cities2016"
                             cities2015-dataset="communes-et-arrondissements-municipaux-millesime-france"
                             cities2015-parameters="{'refine.year':'2015'}"
                             cities2015-domain="userclub"
                             cities2016-dataset="communes-et-arrondissements-municipaux-millesime-france"
                             cities2016-parameters="{'refine.year':'2016'}"
                             cities2016-domain="userclub">
            <!-- KPI box component -->
            <div class="kpi-card"
                 ods-aggregation="agg2015,agg2016"
                 ods-aggregation-agg2015-context="cities2015"
                 ods-aggregation-agg2015-function="COUNT"
                 ods-aggregation-agg2016-context="cities2016"
                 ods-aggregation-agg2016-function="COUNT">
                <i class="kpi-icon fa fa-line-chart" aria-hidden="true"></i>
                <h2 class="kpi-title">
                    {{ (agg2016 - agg2015) / agg2015 * 100 | number : 2 }} %
                </h2>
                <p class="kpi-description">
                    Administrative division evolution in term of # of cities between 2015 and 2016
                </p>
                <p class="kpi-description-detail">
                    <b>{{ agg2015 | number }}</b> in 2015, <b>{{ agg2016 | number }}</b> in 2016
                </p>
            </div>
        </ods-dataset-context>
    </div>
</div>
      
/* Variables & Shared classes
========================================================================== */
:root {
    --secondary-color: #142E7B;
}
.row-equal-height {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
    margin-bottom: 20px;
}
/* Fix for early content wrapping in Safari*/
.row-equal-height:before,
.row-equal-height:after {
    content: normal;
}
/* KPI Card
========================================================================== */
.kpi-card {
    background-color: var(--boxes-background);
    height: 100%;
    padding: 39px;
    border-radius: 4px;
    margin-bottom: 20px;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -ms-flex-direction: column;
    flex-direction: column;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    text-align: center;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    text-align: center;
}
.kpi-icon {
    color: var(--highlight);
    color: var(--secondary-color);
    font-size: 4rem;
    margin-top: 0;
    margin-bottom: 13px;
    max-width: 100%;
}
.kpi-title {
    font-weight: normal;
    color: var(--highlight);
    font-size: 3.2rem;
    margin-top: 0;
    margin-bottom: 13px;
    max-width: 100%;
}
.kpi-description {
    color: var(--text);
    font-size: 1rem;
    line-height: 1.5;
    font-weight: normal;
    margin-top: 0;
    margin-bottom: 0;
    max-width: 100%;
}
.kpi-description-detail {
    opacity: 0.9;
    font-style: italic;
    font-size: 0.9em;
    margin-top: 0.8em;
}

Progression bar / custom gauge

Considering that a gauge or progression bar is nothing more than displaying a value over a total value, we just need to see how to make objects grow with CSS style attributes !

<ods-dataset-context context="ushospitals,ushospitalswithoutgeo"
                     ushospitals-dataset="us-hospitals"
                     ushospitals-domain="userclub"
                     ushospitalswithoutgeo-dataset="us-hospitals"
                     ushospitalswithoutgeo-domain="userclub"
                     ushospitalswithoutgeo-parameters="{'q':'#null(geo_point)'}">

    <div class="row">
        <div class="col-sm-offset-3 col-sm-6">
            <ul ods-aggregation="with,without"
                ods-aggregation-with-context="ushospitals"
                ods-aggregation-with-function="COUNT"
                ods-aggregation-without-context="ushospitalswithoutgeo"
                ods-aggregation-without-function="COUNT">
                {{ rate = (with - without) / with * 100 ; '' }}
                <div class="row bar">
                    <div class="card">
                        <h3>
                            Data quality check
                        </h3>
                        <p>
                            {{ rate | number : 1 }} % of hospitals has geo-coordinates
                        </p>
                        <span class="jauge-container">
                            <span class="jauge"
                                  style="width: {{ rate }}%;
                                         background-color: #142e7b;"></span>
                        </span>
                    </div>
                </div>
            </ul>
        </div>
    </div>
</ods-dataset-context>
/* Progression / gauge */
.card {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border: 1px solid #dee5ef;
    border-radius: 4px;
    background-color: #f6f8fb;
    padding: 30px;
    text-align: center;
}
.jauge-container {
    background-color: white;
    border: 1px solid #707070;
    border-radius: 3px;
    position: relative;
}
.jauge {
    background-color: black;
    color: white;
    border: 2px solid white;
    border-radius: 3px;
    display: block;
}
/* column */
.column .jauge {
    height: 80px;
    width: 30px;
}
/* bar */
.bar .jauge-container {
    width: 100%;
    height: 30px;
}
.bar .jauge {
    height: 100%;
}

Progression bar / custom gauge

A different way to do it is to play with the background color only ! the element keeps it’s full width or height, but a linear gradient style colors it until the pourcentage value.

From 0% to the pourcentage value X with a color, then from X to 100% in white.

<ods-dataset-context context="ushospitals,ushospitalswithoutgeo"
                     ushospitals-dataset="us-hospitals"
                     ushospitals-domain="userclub"
                     ushospitalswithoutgeo-dataset="us-hospitals"
                     ushospitalswithoutgeo-domain="userclub"
                     ushospitalswithoutgeo-parameters="{'q':'#null(beds)'}">

    <div class="row">
        <div class="col-sm-offset-4 col-sm-4">
            <ul ods-aggregation="with,without"
                ods-aggregation-with-context="ushospitals"
                ods-aggregation-with-function="COUNT"
                ods-aggregation-without-context="ushospitalswithoutgeo"
                ods-aggregation-without-function="COUNT">
                {{ rate = without / with * 100 ; '' }}
                <div class="row column">
                    <div class="card">
                        <h3>
                            {{ rate | number : 1 }} % with poor data quality
                        </h3>
                        <p>
                            {{ without | number }} records have no value in "beds" field
                        </p>
                        <span class="jauge-container">
                                <span class="jauge"
                                      style="background: linear-gradient(to top, red, red {{ rate | number : 0 }}%, white {{ rate | number : 0 }}%, white);"></span>
                            </span>
                    </div>
                </div>
            </ul>
        </div>
    </div>
</ods-dataset-context>
/* Progression / gauge */
.card {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border: 1px solid #dee5ef;
    border-radius: 4px;
    background-color: #f6f8fb;
    padding: 30px;
    text-align: center;
}
.jauge-container {
    background-color: white;
    border: 1px solid #707070;
    border-radius: 3px;
    position: relative;
}
.jauge {
    background-color: black;
    color: white;
    border: 2px solid white;
    border-radius: 3px;
    display: block;
}
/* column */
.column .jauge {
    height: 80px;
    width: 30px;
}
/* bar */
.bar .jauge-container {
    width: 100%;
    height: 30px;
}
.bar .jauge {
    height: 100%;
}