Skip to content

Commit

Permalink
feat: configurable title and colors
Browse files Browse the repository at this point in the history
The report title, primary color and traffic light colors are now configurable.

Co-authored-by: pradyot-09 <pradyotpatil@gmail.com>
  • Loading branch information
sbrugman and pradyot-09 committed Jul 5, 2022
1 parent 72df86d commit 37fcd0e
Show file tree
Hide file tree
Showing 16 changed files with 130 additions and 97 deletions.
1 change: 1 addition & 0 deletions examples/flight_delays.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# Configuration of the monitoring rules and report
settings = Settings(time_axis="DATE", reference_type="self")
settings.report.extended_report = False
settings.report.title += " | Flight Delays Dataset"
settings.monitoring.pull_rules = {"*_pull": [10, 7, -7, -10]}

# generate stability report using automatic binning of all encountered features
Expand Down
10 changes: 8 additions & 2 deletions examples/synthetic_data.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import pandas as pd

import popmon # noqa
from popmon import resources
from popmon import Settings, resources

# open synthetic data
df = pd.read_csv(resources.data("test.csv.gz"), parse_dates=["date"])

# report configuration
settings = Settings(
features=["date:age", "date:gender", "date:isActive", "date:eyeColor"]
)
settings.report.title += " | Synthetic Dataset"

# generate stability report using automatic binning of all encountered features
# (importing popmon automatically adds this functionality to a dataframe)
report = df.pm_stability_report(
time_axis="date",
time_width="2w",
features=["date:age", "date:gender", "date:isActive", "date:eyeColor"],
settings=settings,
)

# or save the report to file
Expand Down
14 changes: 12 additions & 2 deletions popmon/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ class Section(BaseModel):
class Report(BaseModel):
"""Report-specific configuration"""

title = "POPMON Report"
"""Report title in browser and navbar. May contain HTML."""

skip_empty_plots: bool = True
"""if false, also show empty plots in report with only nans or zeroes (optional)"""

Expand Down Expand Up @@ -194,8 +197,15 @@ class Report(BaseModel):
]
"""list of statistic name patterns to show in the report. If None, show all (optional)"""

zline_color: List[str] = ["#FF0000", "#FFC800"]
""""Configure line colors in barplots of Comparisons and Profiles section. First and second elements as hex color code in list will replace the default red and yellow respectively"""
primary_color = "#000080"
"""Primary color used throughout the report"""

tl_colors: Dict[str, str] = {
"green": "#008000",
"yellow": "#FFC800",
"red": "#FF0000",
}
""""Configure line colors in barplots of Comparisons and Profiles section. Need to be hex format (full length)"""

section: Section = Section()
"""Configuration for the individual sections"""
Expand Down
2 changes: 2 additions & 0 deletions popmon/visualization/alert_section_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def __init__(
self.section_name = settings.section.alerts.name
self.description = settings.section.alerts.description
self.descriptions = settings.section.alerts.descriptions
self.tl_colors = settings.tl_colors

def get_description(self):
return self.section_name
Expand Down Expand Up @@ -141,6 +142,7 @@ def transform(
0,
0,
0,
self.tl_colors,
style="alerts",
)
]
Expand Down
6 changes: 3 additions & 3 deletions popmon/visualization/histogram_section.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from ..base import Module
from ..config import HistogramSectionModel
from ..utils import parallel, short_date
from ..visualization.utils import plot_heatmap_b64, plot_overlay_1d_histogram_b64
from ..visualization.utils import plot_heatmap, plot_histogram_overlay


class HistogramSection(Module):
Expand Down Expand Up @@ -242,7 +242,7 @@ def _plot_histograms(feature, date, hc_list, hist_names, top_n, max_nbins=1000):
entries_list = np.reshape(entries_list.ravel(), (-1, len(bins)))

hists = [(el, bins) for el in entries_list]
plot = plot_overlay_1d_histogram_b64(
plot = plot_histogram_overlay(
hists, feature, hist_names, y_label, is_num, is_ts
)
elif hc_list[0].n_dim == 2:
Expand Down Expand Up @@ -338,7 +338,7 @@ def _plot_heatmap(
(hist, bins, date, feature, hist_name, y_label, is_num, is_ts, cmap)
for hist, hist_name in zip(hists, hist_names)
]
heatmaps = parallel(plot_heatmap_b64, args)
heatmaps = parallel(plot_heatmap, args)

if isinstance(heatmaps, list):
plot = [hist_lookup(heatmaps, hist_name) for hist_name in hist_names]
Expand Down
4 changes: 4 additions & 0 deletions popmon/visualization/report_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ def __init__(self, read_key, store_key, settings: Report):
super().__init__()
self.read_key = read_key
self.store_key = store_key
self.title = settings.title
self.online_report = settings.online_report
self.tl_colors = settings.tl_colors

def get_description(self):
return "HTML Report"
Expand All @@ -64,5 +66,7 @@ def transform(self, sections: list) -> str:
generator=f"popmon {version}",
sections=sections_html,
online_report=self.online_report,
title=self.title,
**self.tl_colors,
)
)
16 changes: 11 additions & 5 deletions popmon/visualization/section_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from ..base import Module
from ..config import Report
from ..utils import filter_metrics, parallel, short_date
from ..visualization.utils import _prune, plot_bars_b64
from ..visualization.utils import _prune, plot_bars

profiles = Profiles.get_descriptions()

Expand Down Expand Up @@ -117,14 +117,16 @@ def __init__(
self.last_n = settings.last_n
self.skip_first_n = settings.skip_first_n
self.skip_last_n = settings.skip_last_n
self.zline_color = settings.zline_color
self.prefix = prefix
self.suffices = suffices
self.ignore_stat_endswith = ignore_stat_endswith or []
self.skip_empty_plots = settings.skip_empty_plots
self.description = description
self.show_stats = settings.show_stats if not settings.extended_report else None

self.primary_color = settings.primary_color
self.tl_colors = settings.tl_colors

def get_description(self):
return self.section_name

Expand Down Expand Up @@ -181,7 +183,8 @@ def transform(
self.skip_first_n,
self.skip_last_n,
self.skip_empty_plots,
self.zline_color,
self.primary_color,
self.tl_colors,
)
for metric in metrics
]
Expand Down Expand Up @@ -230,6 +233,7 @@ def _plot_metric(
skip_first_n,
skip_last_n,
skip_empty,
primary_color,
zline_color,
):
"""Split off plot histogram generation to allow for parallel processing"""
Expand All @@ -251,13 +255,15 @@ def _plot_metric(
values = _prune(values, last_n, skip_first_n, skip_last_n)

# make plot. note: slow!
plot = plot_bars_b64(
plot = plot_bars(
data=values,
labels=dates,
ylim=True,
bounds=bounds,
skip_empty=skip_empty,
zline_color=zline_color,
primary_color=primary_color,
tl_colors=zline_color,
metric=metric,
)

if not isinstance(plot, dict):
Expand Down
16 changes: 8 additions & 8 deletions popmon/visualization/templates/aggregated-overview.html
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
<table width="95%" style="margin-bottom: 30px;">
{% for feature, vals in values.items() %}
{%- for feature, vals in values.items() -%}
<tr>
<td width="20%" style="text-align:center;"><a class="table-item" href="#" data-feature="{{ feature }}">{{ feature }}</a></td>
<td width="80%">
<div class="tl-container">
{% for i in [2, 1, 0] %}
{% if vals[i] > 0 %}
<div style="width: calc({{ vals[i] }} / {{ vals['total'] }} * 100%)" class="tl-bar {% if i == 2%}r{%elif i == 1%}y{%else%}g{%endif%}">
{%- for i in [2, 1, 0] -%}
{%- if vals[i] > 0 -%}
<div style="width: calc({{ vals[i] }} / {{ vals['total'] }} * 100%)" class="tl-bar {% if i == 2 %}r{% elif i == 1 %}y{% else %}g{% endif %}">
{{ vals[i] }} ({{ "%d" % (vals[i] / (vals["total"] * 0.01))}}%)
</div>
{% else %}
{%- else -%}
<div style="width: 0%">&nbsp;</div>
{% endif %}
{% endfor %}
{%- endif -%}
{%- endfor -%}
</div>
</td>
</tr>
{% endfor %}
{%- endfor -%}
</table>
11 changes: 8 additions & 3 deletions popmon/visualization/templates/assets/css/custom-style.css
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,13 @@ table.overview tbody td:not(.metric){
text-align: center;
}
.g{
background: green;
background: {{ green }};
}
.y{
background: rgba(255, 200, 0, 1.0);
background: {{ yellow }};
}
.r{
background: rgba(255, 0, 0, 1.0);
background: {{ red }};
}
table.overview tfoot td {
padding-top: 5px;
Expand Down Expand Up @@ -131,3 +131,8 @@ table.overview tfoot td span{
display: flex;
width: 100%;
}

#settings-btn{
background-color: transparent;
border-color: #666;
}
3 changes: 1 addition & 2 deletions popmon/visualization/templates/assets/js/custom-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ $(document).on("click", "button.dropdown-item", function() {
var type = window.location.hash.substr(1);
if (type.length > 0){
// Find link to that section
var o = $("a.nav-link.js-scroll-trigger[href='#" + type +"'");
var o = $("a.nav-link.js-scroll-trigger[href='#" + type +"'" );

// If exists
if (o.length == 1){
Expand All @@ -34,7 +34,6 @@ $(document).on("click", "a.table-item", function(){

// making navigation work: after clicking a nav link scrolling to the corresponding section's position
$(document).on("click", "a.nav-link,a.navbar-brand", function(e) {
/*e.preventDefault();*/
obj = $(this)
$([document.documentElement, document.body]).animate({
scrollTop: $("section[data-section-title='" + obj.attr("data-scroll-to-section") + "']").offset().top
Expand Down
2 changes: 1 addition & 1 deletion popmon/visualization/templates/core.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<meta name="description" content="Automatically generated population shift report" />
<meta name="url" content="https://github.com/ing-bank/popmon" />

<title>POPMON Report</title>
<title>{{ title | striptags }}</title>

{%- if online_report %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css">
Expand Down
9 changes: 4 additions & 5 deletions popmon/visualization/templates/header.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top" id="mainNav">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top" id="mainNav">
<div class="container">
<a class="navbar-brand js-scroll-trigger">POPMON REPORT</a>
<a class="navbar-brand js-scroll-trigger">{{ title }}</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto" id="navigation-sections"></ul>&nbsp;&nbsp;&nbsp;
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModalCenter" style="background-color: transparent; border-color: #666">
<button id="settings-btn" type="button" class="btn btn-primary" data-toggle="modal" data-target="#settingsModalCenter">
&#9881;
</button>
</div>
</div>
</nav>
</nav>
5 changes: 2 additions & 3 deletions popmon/visualization/templates/modal-popup.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<!-- Modal -->
<div class="modal fade" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal fade" id="settingsModalCenter" tabindex="-1" role="dialog" aria-labelledby="settingsModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Settings</h5>
<h5 class="modal-title" id="settingsModalLongTitle">Settings</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
Expand Down
56 changes: 27 additions & 29 deletions popmon/visualization/templates/section.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,49 @@

<div class="d-flex justify-content-between align-items-center">
<h2>{{ section_title }}</h2>
{% if features | length %}
{%- if features | length -%}
<div class="dropdown feature-select">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Feature: {{ features[0].name }}
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenu">
{% for feature in features %}
{%- for feature in features -%}
<button class="dropdown-item" type="button" data-feature="{{ feature.name }}">{{ feature.name }}</button>
{% endfor %}
{%- endfor -%}
</div>
</div>
{% endif %}
{%- endif -%}
</div>
<hr>
{% if section_description|length %}
{%- if section_description|length -%}
<div class="section-description">{{section_description}}</div><hr>
{% endif %}
{% if features | length %}
{% for feature in features %}
{%- endif -%}
{%- if features | length -%}
{%- for feature in features -%}
<script>
{% set curr = loop.index %}
var feature{{ section_index }}{{ curr }}_layout = {}
{%- set curr = loop.index -%}
var feature{{ section_index }}{{ curr }}_layout = {};
{%- for plot_type, layout in feature.plot_type_layouts.items() -%}
feature{{ section_index }}{{ curr }}_layout["{{ plot_type }}"] = {{ layout | json_plot }};
{%- endfor -%}
</script>
{% for plot_type, layout in feature.plot_type_layouts.items() %}
<script>
feature{{ section_index }}{{ curr }}_layout["{{ plot_type }}"] = JSON.parse('{{ layout | tojson }}');
</script>
{% endfor %}
<div class="row section_feature" data-section-feature="{{ feature.name }}">
{% for metric in feature.plots %}
{% set plt = loop.index %}
{% with metric=metric %}
{% include 'card.html' %}
{% endwith %}
{% endfor %}
{%- for metric in feature.plots -%}
{%- set plt = loop.index -%}
{%- with metric=metric -%}
{%- include 'card.html' -%}
{%- endwith -%}
{%- endfor -%}
</div>
{% endfor %}
{% else %}
{%- endfor -%}
{%- else -%}
<div class="row" >
{% for metric in plots %}
{% with metric=metric %}
{% include 'card.html' %}
{% endwith %}
{% endfor %}
{%- for metric in plots -%}
{%- with metric=metric -%}
{%- include 'card.html' -%}
{%- endwith -%}
{%- endfor -%}
</div>
{% endif %}
{%- endif -%}
</div>
</section>
Loading

0 comments on commit 37fcd0e

Please sign in to comment.