import json
import string
import os
from sklearn.utils import check_random_state
[docs]def data_validation(data):
"""Validate the if the given data format is a list of dictionary.
Parameters
----------
param1 : :obj:`Any`
Data to be validated.
Returns
-------
:obj:`bool`
True: The data is a list of dictionary.\n
False: The data is not a list of dictionary.
Examples
--------
>>> from pypkgs import pypkgs
>>> a = pd.Categorical(["character", "hits", "your", "eyeballs"])
>>> b = pd.Categorical(["but", "integer", "where it", "counts"])
>>> pypkgs.catbind(a, b)
[character, hits, your, eyeballs, but, integer, where it, counts]
Categories (8, object): [but, character, counts,
eyeballs, hits, integer, where it, your]
"""
valid = True
if str(type(data)) == "<class 'list'>":
for i in range(len(data)):
if str(type(data[i])) != "<class 'dict'>":
print(
"Data Format Error - the input data should be a list of dictionary")
valid = False
break
else:
valid = False
return valid
[docs]def id_generator(size=15, random_state=None):
"""Generate unique ids for div tag which will contain the visualisation stuff from d3.
Parameters
----------
param1 : :obj:`int`
An integer that specifies the length of the returned id, default = 15.
param2 : :obj:`np.random.RandomState`, default is None.
A RandomState instance.
Returns
-------
:obj:`str`
A random identifier.
Examples
--------
>>> from pypkgs import pypkgs
>>> a = pd.Categorical(["character", "hits", "your", "eyeballs"])
>>> b = pd.Categorical(["but", "integer", "where it", "counts"])
>>> pypkgs.catbind(a, b)
[character, hits, your, eyeballs, but, integer, where it, counts]
Categories (8, object): [but, character, counts,
eyeballs, hits, integer, where it, your]
"""
chars = list(string.ascii_uppercase + string.digits)
return ''.join(random_state.choice(chars, size, replace=True))
[docs]class Explainer():
""" __init__ method of Explainer class.
Parameters
----------
param1 : :obj:`list` of :obj:`dict`
A list of dictionary that contains the specification of the bullet chart to be created.
param2 : :obj:`list` of :obj:`dict`
A list of dictionary that contains the information about risk scores.
param3 : :obj:`np.random.RandomState`, default is None
A RandomState instance.
"""
def __init__(self, bullet_data, risk_data, random_state=None):
valid_bullet_data = data_validation(bullet_data)
if valid_bullet_data:
self.set_bullet_data(str(bullet_data)+";")
else:
self.set_bullet_data([{}])
print(
"Bullet Data Format Error - the input data should be a list of dictionary")
valid_risk_data = data_validation(risk_data)
if valid_risk_data:
self.set_risk_data(str(risk_data)+";")
else:
self.set_risk_data([{}])
print(
"Risk Data Format Error - the input data should be a list of dictionary")
self.random_state = random_state
[docs] def generate_html(self):
"""Generate html and return it as a String.
Returns
----------
:obj:`str`
html String
Examples
--------
>>> from pypkgs import pypkgs
>>> a = pd.Categorical(["character", "hits", "your", "eyeballs"])
>>> b = pd.Categorical(["but", "integer", "where it", "counts"])
>>> pypkgs.catbind(a, b)
[character, hits, your, eyeballs, but, integer, where it, counts]
Categories (8, object): [but, character, counts,
eyeballs, hits, integer, where it, your]
"""
unique_id = id_generator(random_state=check_random_state(self.get_random_state()))
css_filepath = "css/styles.css"
css_stylesheet = \
"""
<link rel="stylesheet" href="%s" />
""" % (css_filepath)
d3_filepath = "js/d3.min.js"
bulletjs_filepath = "js/bullet.js"
d3_script = \
"""
<script src="%s"></script>
<script src="%s"></script>
""" % (d3_filepath, bulletjs_filepath)
main_title = "What to do to decrease the risk of having defects?"
title = \
"""
<div style="position: relative; top: 0; width: 100vw; text-align: center">
<b>%s</b>
</div>
""" % main_title
d3_operation_script = \
"""
<script>
var margin = { top: 5, right: 40, bottom: 20, left: 500 },
width = 1300 - margin.left - margin.right,
height = 50 - margin.top - margin.bottom;
var chart = d3.bullet().width(width).height(height);
var bulletData = %s
var riskData = %s
// define the color of the box
var boxColor = "box green";
var riskPred = riskData[0].riskPred[0];
if (riskPred.localeCompare("Yes")==0) {
boxColor = "box orange";
}
// append risk prediction and risk score
d3.select("#d3-target-bullet-%s")
.append("div")
.attr("class", "riskPred")
.data(riskData)
.text((d) => d.riskPred)
.append("div")
.attr("class", boxColor);
d3.select("#d3-target-bullet-%s")
.append("div")
.attr("class", "riskScore")
.data(riskData)
.text((d) => "Risk Score: " + d.riskScore);
var svg = d3
.select("#d3-target-bullet-%s")
.selectAll("svg")
.data(bulletData)
.enter()
.append("svg")
.attr("class", "bullet")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr(
"transform",
"translate(" + margin.left + "," + margin.top + ")"
)
.call(chart);
var title = svg
.append("g")
.style("text-anchor", "end")
.attr("transform", "translate(-6," + height / 2 + ")");
title
.append("text")
.attr("class", "title")
.text((d) => d.title);
title
.append("text")
.attr("class", "subtitle")
.attr("dy", "1em")
.text((d) => d.subtitle);
</script>
""" % (self.get_bullet_data(), self.get_risk_data(), unique_id, unique_id, unique_id)
html = \
"""
<!DOCTYPE html>
<html>
<meta http-equiv="content-type" content="text/html; charset=UTF8">
<head>
%s
%s
</head>
<body>
<div class="bullet-chart">
%s
<div class="d3-target-bullet" id="d3-target-bullet-%s" />
</div>
%s
</body>
</html>
""" % (css_stylesheet, d3_script, title, unique_id, d3_operation_script)
return html
[docs] def get_bullet_data(self):
return self.bullet_data
[docs] def get_random_state(self):
return self.random_state
[docs] def get_risk_data(self):
return self.risk_data
[docs] def set_bullet_data(self, bullet_data):
self.bullet_data = bullet_data
[docs] def set_random_state(self, random_state):
self.random_state = random_state
[docs] def set_risk_data(self, risk_data):
self.risk_data = risk_data
[docs] def show_visualisation(self):
"""Display the html string in a cell of Jupyter Notebook.
Examples
--------
>>> from pypkgs import pypkgs
>>> a = pd.Categorical(["character", "hits", "your", "eyeballs"])
>>> b = pd.Categorical(["but", "integer", "where it", "counts"])
>>> pypkgs.catbind(a, b)
[character, hits, your, eyeballs, but, integer, where it, counts]
Categories (8, object): [but, character, counts,
eyeballs, hits, integer, where it, your]
"""
self.generate_html()
from IPython.core.display import display, HTML
print(self.generate_html()) # TBR - (to be removed)
display(HTML(self.generate_html()))