whylabs/whylogs-python

View on GitHub
python/whylogs/viz/html/templates/index-hbs-cdn-all-in-jupyter-feature-summary-statistics.html

Summary

Maintainability
Test Coverage
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="" />
    <meta name="author" content="" />

    <title>Profile Visualizer | whylogs</title>

    <link rel="icon" href="images/whylabs-favicon.png" type="image/png" sizes="16x16" />
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link href="https://fonts.googleapis.com/css2?family=Asap:wght@400;500;600;700&display=swap" rel="stylesheet" />
    <link rel="preconnect" href="https://fonts.gstatic.com" />
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" />

    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"
      integrity="sha512-RNLkV3d+aLtfcpEyFG8jRbnWHxUqVZozacROI4J2F1sTaDqo1dPQYs01OMi1t1w9Y2FdbSCDSQ2ZVdAC8bzgAg=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    ></script>

    <style type="text/css">

      /* Screen on smaller screens */
      .no-responsive {
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        z-index: 1031;
        width: 100vw;
        height: 100vh;
        background-color: var(--tealBackground);
        display: flex;
        align-items: center;
        justify-content: center;
      }

      @media screen and (min-width: 1000px) {
        .desktop-content {
          display: block;
        }
        .no-responsive {
          display: none;
        }
      }

      .no-responsive__content {
        max-width: 600px;
        width: 100%;
        padding: 0 24px;
      }

      .no-responsive__title {
        font-size: 96px;
        font-weight: 300;
        color: var(--brandSecondary900);
        line-height: 1.167;
      }

      .no-responsive__text {
        margin: 0;
        font-size: 16px;
        font-weight: 400;
        color: var(--brandSecondary900);
        line-height: 1.5;
      }

      .header-title {
        font-size: 26px;
        font-weight: 700;
        color: #444444;
      }

      .statistics-header-title {
        font-size: 20px;
        font-weight: 700;
        color: #444444;
      }

      .statistic-number-title {
        font-family: Arial;
        font-weight: normal;
        font-size: 14px;
        line-height: 20px;
        color: #6C757D;
      }

      .statistic-number {
        font-family: Arial;
        font-weight: bold;
        font-size: 20px;
        line-height: 140%;
        display: flex;
        align-items: center;
        color: #4F595B;
      }

      .full-summary-statistics-wrap {
        padding: 20px;
      }

      .statistics {
        width: 100%;
      }

      .statistics-list {
        width: 49% ;
      }

      .notif-circle-container{
        position: absolute;
        top: -8px;
        right: -8px;
        padding: 5.3px;
        border-radius: 50%;
        background-color: var(--brandSecondary100);
        cursor: pointer;
      }

      .notif-circle {
        position: absolute;
        top: 2px;
        right: 2px;
        height: 16px;
        width: 16px;
        border-radius: 50%;
        font-size: 10px;
        color: #fff;
        background-color: #ECB100;
      }

      .border-solid-gray {
        border: 1px solid #CED4DA;
        border-radius: 4px;
        padding: 10px;
      }

      .display-flex {
        display: flex;
      }

      .justify-content-space-between {
        justify-content: space-between;
      }

      .justify-content-center {
        justify-content: center;
      }

      .align-items-center {
        align-items: center;
      }

      .padding-right-30 {
        padding-right: 30px;
      }

      @media screen and (min-width: 500px) {
        .desktop-content {
          display: block;
        }
        .no-responsive {
          display: none;
        }
      }
    </style>
  </head>

  <body id="generated-html"></body>

  <script id="entry-template" type="text/x-handlebars-template">
    {{{{raw}}}}
      <div class="desktop-content">
        <div class="full-summary-statistics-wrap">
          <div class="full-summary-statistics">
            <div class="mb-4">
                <strong class="header-title">{{featureName this}}: Summary Statistics</strong>
            </div>
            <div class="statistics-wrap border-solid-gray display-flex justify-content-center mb-5">
              <div class="statistics display-flex justify-content-space-between">
                  <div class="statistic-item padding-right-30">
                    <div class="statistic-number-title">Distinct (%)</div>
                    <div class="statistic-number">{{distinct this}}</div>
                  </div>
                  <div class="statistic-item padding-right-30">
                    <div class="statistic-number-title">Missing</div>
                    <div class="statistic-number">{{missing this}}</div>
                  </div>
                  <div class="statistic-item padding-right-30">
                    <div class="statistic-number-title">Mean</div>
                    <div class="statistic-number">{{mean this}}</div>
                  </div>
                  <div class="statistic-item padding-right-30">
                    <div class="statistic-number-title">Minimum</div>
                    <div class="statistic-number">{{minimum this}}</div>
                  </div>
                  <div class="statistic-item padding-right-30">
                    <div class="statistic-number-title">Maximum</div>
                    <div class="statistic-number">{{maximum this}}</div>
                  </div>
              </div>
            </div>
            <div>
              <div class="display-flex justify-content-space-between">
                <div class="statistics-list border-solid-gray">
                  <div>
                    <div class="mb-3">
                      <strong class="statistics-header-title">Quantile statistics</strong>
                    </div>
                    <div>
                      <div class="display-flex justify-content-space-between mb-2">
                        <div>5-th percentile</div>
                        <div>{{fifthPercentile this}}</div>
                      </div>
                      <div class="display-flex justify-content-space-between mb-2">
                        <div>Q1</div>
                        <div>{{q1 this}}</div>
                      </div>
                      <div class="display-flex justify-content-space-between mb-2">
                        <div>median</div>
                        <div>{{median this}}</div>
                      </div>
                      <div class="display-flex justify-content-space-between mb-2">
                        <div>Q3</div>
                        <div>{{q3 this}}</div>
                      </div>
                      <div class="display-flex justify-content-space-between mb-2">
                        <div>95-th percentile</div>
                        <div>{{ninetyFifthPercentile this}}</div>
                      </div>
                      <div class="display-flex justify-content-space-between mb-2">
                        <div>Range</div>
                        <div>{{range this}}</div>
                      </div>
                      <div class="display-flex justify-content-space-between mb-2">
                        <div>Interquartile range (IQR)</div>
                        <div>{{iqr this}}</div>
                      </div>
                    </div>
                  </div>
                </div>
                <div class="statistics-list border-solid-gray">
                  <div>
                    <div class="mb-3">
                      <strong class="statistics-header-title">Descriptive statistics</strong>
                    </div>
                    <div>
                      <div class="display-flex justify-content-space-between mb-2">
                        <div>Standard deviation</div>
                        <div>{{stddev this}}</div>
                      </div>
                      <div class="display-flex justify-content-space-between mb-2">
                        <div>Coefficient of variation (CV)</div>
                        <div>{{coefficientOfVariation this}}</div>
                      </div>
                      <div class="display-flex justify-content-space-between mb-2">
                        <div>Sum</div>
                        <div>{{getSum this}}</div>
                      </div>
                      <div class="display-flex justify-content-space-between mb-2">
                        <div>Variance</div>
                        <div>{{variance this}}</div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="no-responsive">
        <div class="no-responsive__content">
          <h1 class="no-responsive__title">Hold on! :)</h1>
          <p class="no-responsive__text">
            It looks like your current screen size or device is not yet supported by the WhyLabs Sandbox. The Sandbox is
            best experienced on a desktop computer. Please try maximizing this window or switching to another device. We
            are working on adding support for a larger variety of devices.
          </p>
        </div>
      </div>
    {{{{/raw}}}}
  </script>

  <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js" integrity="sha512-cd6CHE+XWDQ33ElJqsi0MdNte3S+bQY819f7p3NUHgwQQLXSKjE4cPZTeGNI+vaxZynk1wVU3hoHmow3m089wA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

  <script>
    function registerHandlebarHelperFunctions() {
      //helper fun
      // function formatLabelDate(timestamp) {
      //   const date = new Date(timestamp);
      //   const format = d3.timeFormat("%Y-%m-%d %I:%M:%S %p %Z");
      //   return format(date);
      // }

      function fixNumberTo(number, decimals = 3) {
        return parseFloat(number).toFixed(decimals);
      }

      Handlebars.registerHelper("variance", function (column) {
        const feature = Object.values(column)[0]

        if (feature.descriptive_statistics && typeof feature.descriptive_statistics.variance === 'number') {
          if (isNaN(feature.descriptive_statistics.variance)){return "-"}
          if (feature.descriptive_statistics.variance==null){return "-"}
          return fixNumberTo(feature.descriptive_statistics.variance,2);
        }
        return "-";
      });

      Handlebars.registerHelper("coefficientOfVariation", function (column) {
        const feature = Object.values(column)[0]

        if (feature.descriptive_statistics && typeof feature.descriptive_statistics.coefficient_of_variation === 'number') {
          if (isNaN(feature.descriptive_statistics.coefficient_of_variation)){return "-"}
          if (feature.descriptive_statistics.coefficient_of_variation==null){return "-"}
          return fixNumberTo(feature.descriptive_statistics.coefficient_of_variation,2);
        }
        return "-";
      });

      Handlebars.registerHelper("median", function (column) {
        const feature = Object.values(column)[0]

        if (feature.quantile_statistics && typeof feature.quantile_statistics.median === 'number') {
          if (isNaN(feature.quantile_statistics.median)){return "-"}
          if (feature.quantile_statistics.median==null){return "-"}
          return fixNumberTo(feature.quantile_statistics.median);
        }
        return "-";
      });

      Handlebars.registerHelper("fifthPercentile", function (column) {
        const feature = Object.values(column)[0]

        if (feature.quantile_statistics && typeof feature.quantile_statistics.fifth_percentile === 'number') {
          if (isNaN(feature.quantile_statistics.fifth_percentile)){return "-"}
          if (feature.quantile_statistics.fifth_percentile==null){return "-"}
          return fixNumberTo(feature.quantile_statistics.fifth_percentile);
        }
        return "-";
      });

      Handlebars.registerHelper("ninetyFifthPercentile", function (column) {
        const feature = Object.values(column)[0]

        if (feature.quantile_statistics && typeof feature.quantile_statistics.ninety_fifth_percentile === 'number') {
          if (isNaN(feature.quantile_statistics.ninety_fifth_percentile)){return "-"}
          if (feature.quantile_statistics.ninety_fifth_percentile==null){return "-"}
          return fixNumberTo(feature.quantile_statistics.ninety_fifth_percentile);
        }
        return "-";
      });

      Handlebars.registerHelper("range", function (column) {
        const feature = Object.values(column)[0]

        if (feature.range && typeof feature.range === 'number') {
          if (isNaN(feature.range)){return "-"}
          if (feature.range==null){return "-"}
          return fixNumberTo(feature.range);
        }
        return "-";
      });

      Handlebars.registerHelper("q3", function (column) {
        const feature = Object.values(column)[0]

        if (feature.quantile_statistics && typeof feature.quantile_statistics.q3 === 'number') {
          if (isNaN(feature.quantile_statistics.q3)){return "-"}
          if (feature.quantile_statistics.q3==null){return "-"}
          return fixNumberTo(feature.quantile_statistics.q3);
        }
        return "-";
      });

      Handlebars.registerHelper("q1", function (column) {
        const feature = Object.values(column)[0]

        if (feature.quantile_statistics && typeof feature.quantile_statistics.q1 === 'number') {
          if (isNaN(feature.quantile_statistics.q1)){return "-"}
          if (feature.quantile_statistics.q1==null){return "-"}
          return fixNumberTo(feature.quantile_statistics.q1);
        }
        return "-";
      });

      Handlebars.registerHelper("getSum", function (column) {
        const feature = Object.values(column)[0]

        if (feature.descriptive_statistics && typeof feature.descriptive_statistics.sum === 'number') {
          if (isNaN(feature.descriptive_statistics.sum)){return "-"}
          if (feature.descriptive_statistics.sum==null){return "-"}
          return fixNumberTo(feature.descriptive_statistics.sum,2);
        }
        return "-";
      });

      Handlebars.registerHelper("iqr", function (column) {
        const feature = Object.values(column)[0]

        if (feature.quantile_statistics && typeof feature.quantile_statistics.iqr === 'number' ) {
          if (isNaN(feature.quantile_statistics.iqr)){return "-"}
          if (feature.quantile_statistics.iqr==null){return "-"}
          return fixNumberTo(feature.quantile_statistics.iqr);
        }
        return "-";
      });


      Handlebars.registerHelper("distinct", function (column) {
        const feature = Object.values(column)[0]
        const distinct_pct = feature.distinct

        return fixNumberTo(distinct_pct,2);
      });

      Handlebars.registerHelper("missing", function (column) {
        const feature = Object.values(column)[0]
        if (feature.missing) {
          return feature.missing;
        }
        return "0";
      });

      Handlebars.registerHelper("mean", function (column) {
        const feature = Object.values(column)[0]

        if (feature.descriptive_statistics && typeof feature.descriptive_statistics.mean === 'number') {
          if (isNaN(feature.descriptive_statistics.mean)){return "-"}
          if (feature.descriptive_statistics.mean==null){return "-"}
          return fixNumberTo(feature.descriptive_statistics.mean);
        }
        return "-";
      });

      Handlebars.registerHelper("stddev", function (column) {
        const feature = Object.values(column)[0]

        if (feature.descriptive_statistics && typeof feature.descriptive_statistics.stddev === 'number') {
          if (isNaN(feature.descriptive_statistics.stddev)){return "-"}
          if (feature.descriptive_statistics.stddev==null){return "-"}
          return fixNumberTo(feature.descriptive_statistics.stddev);
        }
        return "-";
      });

      Handlebars.registerHelper("minimum", function (column) {
        const feature = Object.values(column)[0]
        if (typeof feature.min === 'number') {
          if (isNaN(feature.min)){return "-"}
          if (feature.min==null){return "-"}
          return fixNumberTo(feature.min);
        }
        return "-";
      });

      Handlebars.registerHelper("maximum", function (column) {
        const feature = Object.values(column)[0]

        if (typeof feature.max === 'number') {
          if (isNaN(feature.max)){return "-"}
          if (feature.max==null){return "-"}
          return fixNumberTo(feature.max);
        }
        return "-";
      });

      // Handlebars.registerHelper("getProfileTimeStamp", function (column) {
      //   return formatLabelDate(+column.properties.dataTimestamp)
      // });

      // Handlebars.registerHelper("getProfileName", function (column) {
      //   return column.properties.tags.name
      // });

      Handlebars.registerHelper("featureName", function (column) {
        const featureName = Object.keys(column)[0]
        return featureName
      });
    }

    function initHandlebarsTemplate() {
      // Replace this context with JSON from .py file
      const context = {{{profile_feature_statistics_from_whylogs}}};
      // Config handlebars and pass data to HBS template
      const source = document.getElementById("entry-template").innerHTML;
      const template = Handlebars.compile(source);
      const html = template(context);
      const target = document.getElementById("generated-html");
      target.innerHTML = html;
    }

    // Invoke functions -- keep in mind invokation order
    registerHandlebarHelperFunctions();
    initHandlebarsTemplate();
  </script>
</html>