Skip to content

Commit

Permalink
docstring to_html
Browse files Browse the repository at this point in the history
  • Loading branch information
oegedijk committed Jul 8, 2021
1 parent 25bc172 commit 29d25ba
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 45 deletions.
69 changes: 41 additions & 28 deletions explainerdashboard/dashboard_components/composites.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def layout(self):
])

def to_html(self, state_dict=None, add_header=True):
html = to_html.title(self.title)
html = to_html.hide(to_html.title(self.title), hide=self.hide_title)
html += to_html.card_rows(
[to_html.hide(self.importances.to_html(state_dict, add_header=False), self.hide_importances)],
[to_html.hide(self.feature_descriptions.to_html(state_dict, add_header=False), self.hide_descriptions)],
Expand Down Expand Up @@ -181,12 +181,16 @@ def layout(self):
])

def to_html(self, state_dict=None, add_header=True):
html = to_html.title(self.title)
html = to_html.hide(to_html.title(self.title), hide=self.hide_title)
html += to_html.card_rows(
[self.summary.to_html(state_dict, add_header=False), self.confusionmatrix.to_html(state_dict, add_header=False)],
[self.precision.to_html(state_dict, add_header=False), self.classification.to_html(state_dict, add_header=False)],
[self.rocauc.to_html(state_dict, add_header=False), self.prauc.to_html(state_dict, add_header=False)],
[self.liftcurve.to_html(state_dict, add_header=False), self.cumulative_precision.to_html(state_dict, add_header=False)],
[to_html.hide(self.summary.to_html(state_dict, add_header=False), hide=self.hide_modelsummary),
to_html.hide(self.confusionmatrix.to_html(state_dict, add_header=False), hide=self.hide_confusionmatrix)],
[to_html.hide(self.precision.to_html(state_dict, add_header=False), hide=self.hide_precision),
to_html.hide(self.classification.to_html(state_dict, add_header=False), hide=self.hide_classification)],
[to_html.hide(self.rocauc.to_html(state_dict, add_header=False), hide=self.hide_rocauc),
to_html.hide(self.prauc.to_html(state_dict, add_header=False), hide=self.hide_prauc)],
[to_html.hide(self.liftcurve.to_html(state_dict, add_header=False), hide=self.hide_liftcurve),
to_html.hide(self.cumulative_precision.to_html(state_dict, add_header=False), hide=self.hide_cumprecision)]
)
if add_header:
return to_html.add_header(html)
Expand Down Expand Up @@ -258,10 +262,12 @@ def layout(self):
])

def to_html(self, state_dict=None, add_header=True):
html = to_html.title(self.title)
html = to_html.hide(to_html.title(self.title), hide=self.hide_title)
html += to_html.card_rows(
[self.modelsummary.to_html(state_dict, add_header=False), self.preds_vs_actual.to_html(state_dict, add_header=False)],
[self.residuals.to_html(state_dict, add_header=False), self.reg_vs_col.to_html(state_dict, add_header=False)],
[to_html.hide(self.modelsummary.to_html(state_dict, add_header=False), hide=self.hide_modelsummary),
to_html.hide(self.preds_vs_actual.to_html(state_dict, add_header=False), hide=self.hide_predsvsactual)],
[to_html.hide(self.residuals.to_html(state_dict, add_header=False), hide=self.hide_residuals),
to_html.hide(self.reg_vs_col.to_html(state_dict, add_header=False), hide=self.hide_regvscol)],
)
if add_header:
return to_html.add_header(html)
Expand Down Expand Up @@ -805,24 +811,16 @@ def layout(self):
], fluid=False)

def to_html(self, state_dict=None, add_header=True):
html = to_html.title(self.title)
html += to_html.row(
to_html.card_deck(
self.confusionmatrix.to_html(state_dict, add_header=False),
self.classifier_custom_component.to_html(state_dict, add_header=False)))
html += to_html.row(
to_html.card_deck(
self.shap_summary.to_html(state_dict, add_header=False),
self.shap_dependence.to_html(state_dict, add_header=False)))
html += to_html.row(
to_html.card_deck(
self.index.to_html(state_dict, add_header=False),
self.summary.to_html(state_dict, add_header=False)))
html += to_html.row(
to_html.card_deck(
self.contributions.to_html(state_dict, add_header=False)))

html = to_html.wrap_in_div(html)
html = to_html.hide(to_html.title(self.title), hide=self.hide_title)
html += to_html.card_rows(
[to_html.hide(self.confusionmatrix.to_html(state_dict, add_header=False), hide=self.hide_confusionmatrix),
to_html.hide(self.classifier_custom_component.to_html(state_dict, add_header=False), hide=self.hide_classifier_custom_component)],
[to_html.hide(self.shap_summary.to_html(state_dict, add_header=False), hide=self.hide_shapsummary),
to_html.hide(self.shap_dependence.to_html(state_dict, add_header=False), hide=self.hide_shapdependence)],
[to_html.hide(self.index.to_html(state_dict, add_header=False), hide=self.hide_predindexselector),
to_html.hide(self.summary.to_html(state_dict, add_header=False), hide=self.hide_predictionsummary)],
[to_html.hide(self.contributions.to_html(state_dict, add_header=False), hide=self.hide_contributiongraph)]
)
if add_header:
return to_html.add_header(html)
return html
Expand Down Expand Up @@ -945,4 +943,19 @@ def layout(self):
], style=dict(marginBottom=25, marginTop=25))
])
])
], fluid=False)
], fluid=False)

def to_html(self, state_dict=None, add_header=True):
html = to_html.hide(to_html.title(self.title), hide=self.hide_title)
html += to_html.card_rows(
[to_html.hide(self.goodness_of_fit.to_html(state_dict, add_header=False), hide=self.hide_goodness_of_fit),
to_html.hide(self.classifier_custom_component.to_html(state_dict, add_header=False), hide=self.hide_regression_custom_component)],
[to_html.hide(self.shap_summary.to_html(state_dict, add_header=False), hide=self.hide_shapsummary),
to_html.hide(self.shap_dependence.to_html(state_dict, add_header=False), hude=self.hide_shapdependence)],
[to_html.hide(self.index.to_html(state_dict, add_header=False), hide=self.hide_predindexselector),
to_html.hide(self.summary.to_html(state_dict, add_header=False), hide=self.hide_predictionsummary)],
[to_html.hide(self.contributions.to_html(state_dict, add_header=False), hide=self.hide_contributiongraph)]
)
if add_header:
return to_html.add_header(html)
return html
12 changes: 11 additions & 1 deletion explainerdashboard/dashboard_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,11 +450,21 @@ def to_html(self, state_dict:dict=None, add_header=True):
Args:
state_dict (dict): dictionary with id_prop_tuple as keys and state as value.
"""
html = to_html.wrap_in_div("")
html = to_html.div("")
if add_header:
return to_html.add_header(html)
return html

def save_html(self, filename:Union[str, Path]):
"""Store output of to_html to a file
Args:
filename (str, Path): filename to store html
"""
html = self.to_html(add_header=True)
with open(filename, "w") as file:
file.write(html)

def component_callbacks(self, app):
"""register callbacks specific to this ExplainerComponent."""
if hasattr(self, "_register_callbacks"):
Expand Down
101 changes: 85 additions & 16 deletions explainerdashboard/to_html.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@

def add_header(html:str, title="explainerdashboard"):
"""Helper module to define static html outputs"""

__all__ = [
'add_header',
'row',
'rows',
'fig',
'card',
'card_deck',
'card_rows',
'title',
'wrap_in_div',
'table_from_df',
'hide',
'tabs',
'input'
]


def add_header(html:str, title="explainerdashboard")->str:
"""Turns a html snippet into a full html layout by adding <html>, <head> and <body> tags.
Loads bootstrap css and javascript and triggers a resize event in order to prevent
plotly figs from overflowing their div containers.
"""
return f"""
<!DOCTYPE html>
<html lang="en">
Expand All @@ -26,7 +49,13 @@ def add_header(html:str, title="explainerdashboard"):
"""


def row(*cols):
def row(*cols)->str:
"""Turns a series of html snippets into a bootstrap row with equally sized
columns for each snippet.
Example:
to_html.row("<div>first snippet</div>", "<div>second snippet</div>")
"""
row = '<div class="row" style="margin-top: 20px;">'
for col in cols:
row += '<div class="col-sm">'
Expand All @@ -35,15 +64,34 @@ def row(*cols):
row += '</div>'
return row

def rows(*col_lists):
def rows(*col_lists)->str:
"""Turns a list of lists of html snippets into a series of bootstrap rows
with equally sized columns for each snippet.
Example:
to_html.row(["<div>first snippet</div>", "<div>second snippet</div>"],
["<div>second row snippet snippet</div>", "<div>second row snippet two</div>"])
"""
rows = [row(*cols) for cols in col_lists]
rows = "".join(rows)
return wrap_in_div(rows)

def fig(fig):
return fig.to_html(include_plotlyjs='cdn', full_html=False)

def card(html, title=None, subtitle=None):
def fig(fig, include_plotlyjs='cdn', full_html:bool=False)->str:
"""Returns html for a plotly figure. By default the plotly javascript is not
included but imported from the plotly cdn, and the full html wrapper is not included.
Args:
include_plotlyjs (bool, str): how to import the necessary javascript for the plotly
fig. Defaults to 'cdn'. If set to True then a 3MB javascript snippet is included.
For other options check https://plotly.com/python-api-reference/generated/plotly.io.to_html.html
full_html (bool): include <html>, <head> and <body> tags. Defaults to False.
"""
return fig.to_html(include_plotlyjs=include_plotlyjs, full_html=full_html)

def card(html:str, title:str=None, subtitle:str=None)->str:
"""Wrap to html snippet in a bootstrap card. You can optionally add a title
and subtitle to the card.
"""
if title:
card_header = f"""<div class="card-header"><h3 class="card-title">{title}</h3>"""
if subtitle:
Expand All @@ -64,7 +112,9 @@ def card(html, title=None, subtitle=None):
"""


def card_deck(*cards):
def card_deck(*cards)->str:
"""turn a list of bootstrap cards into an equally spaced card deck.
"""
cards = list(cards)
cards = "".join(cards)
return f"""
Expand All @@ -74,20 +124,26 @@ def card_deck(*cards):
"""


def card_rows(*card_lists):
def card_rows(*card_lists)->str:
"""Turn a list of lists of bootstrap cards into a series of bootstrap rows
with card decks"""
card_decks = [[card_deck(*cards)] for cards in card_lists]
return rows(*card_decks)


def title(title):
def title(title:str)->str:
"""wrap a title string in div and <H1></H1>"""
return f"<div><H1>{title}</H1></div>"


def wrap_in_div(html:str):
def div(html:str)->str:
"""wrap an html snippet in a <div></div>"""
return f'<div>{html}</div>'


def table_from_df(df):
def table_from_df(df)-str:
"""Generate a html table from a pandas DataFrame"""

header_row = '\n'.join([f' <th scope="col">{col}</th>' for col in df.columns])
body_rows = ""
for i, row in df.iterrows():
Expand All @@ -107,12 +163,16 @@ def table_from_df(df):
"""
return table

def hide(html, hide=False):
def hide(html:str, hide:bool=False)->str:
"""optionally hide an html snippet (return empty div) if parameter hide=True"""
if hide:
return "<div></div>"
return html

def tabs(tabs_dict):
def tabs(tabs_dict:dict)->str:
"""Generate a series of bootstrap tabs for a dictionary tabs_dict with the
name of the tab of key and the html contents of the tab as value.
"""
html = '<ul class="nav nav-tabs" id="myTab" role="tablist">'
for i, tab_name in enumerate(tabs_dict.keys()):
if i == 0:
Expand Down Expand Up @@ -154,7 +214,16 @@ def tabs(tabs_dict):

return html

def input(feature, value, disabled=False):

def input(feature:str, value, disabled:bool=False)->str:
"""
Return a html feature input with a feature name and default value.
Args:
feature (str): name of feature
value (str): default value
disabled (bool): disable the input. Defaults to False.
"""
return f"""
<div style="display:flex;flex-direction:column;">
<label for="{feature}">{feature}</label>
Expand Down

0 comments on commit 29d25ba

Please sign in to comment.