613 lines
24 KiB
Python
613 lines
24 KiB
Python
import base64
|
|
import io
|
|
import os
|
|
|
|
import numpy as np
|
|
import sklearn
|
|
from matplotlib.colors import LinearSegmentedColormap
|
|
|
|
from .. import __version__
|
|
from ..plots import colors
|
|
from . import methods, metrics, models
|
|
from .experiments import run_experiments
|
|
|
|
try:
|
|
import matplotlib
|
|
import matplotlib.pyplot as pl
|
|
from IPython.display import HTML
|
|
except ImportError:
|
|
pass
|
|
|
|
|
|
metadata = {
|
|
# "runtime": {
|
|
# "title": "Runtime",
|
|
# "sort_order": 1
|
|
# },
|
|
# "local_accuracy": {
|
|
# "title": "Local Accuracy",
|
|
# "sort_order": 2
|
|
# },
|
|
# "consistency_guarantees": {
|
|
# "title": "Consistency Guarantees",
|
|
# "sort_order": 3
|
|
# },
|
|
# "keep_positive_mask": {
|
|
# "title": "Keep Positive (mask)",
|
|
# "xlabel": "Max fraction of features kept",
|
|
# "ylabel": "Mean model output",
|
|
# "sort_order": 4
|
|
# },
|
|
# "keep_negative_mask": {
|
|
# "title": "Keep Negative (mask)",
|
|
# "xlabel": "Max fraction of features kept",
|
|
# "ylabel": "Negative mean model output",
|
|
# "sort_order": 5
|
|
# },
|
|
# "keep_absolute_mask__r2": {
|
|
# "title": "Keep Absolute (mask)",
|
|
# "xlabel": "Max fraction of features kept",
|
|
# "ylabel": "R^2",
|
|
# "sort_order": 6
|
|
# },
|
|
# "keep_absolute_mask__roc_auc": {
|
|
# "title": "Keep Absolute (mask)",
|
|
# "xlabel": "Max fraction of features kept",
|
|
# "ylabel": "ROC AUC",
|
|
# "sort_order": 6
|
|
# },
|
|
# "remove_positive_mask": {
|
|
# "title": "Remove Positive (mask)",
|
|
# "xlabel": "Max fraction of features removed",
|
|
# "ylabel": "Negative mean model output",
|
|
# "sort_order": 7
|
|
# },
|
|
# "remove_negative_mask": {
|
|
# "title": "Remove Negative (mask)",
|
|
# "xlabel": "Max fraction of features removed",
|
|
# "ylabel": "Mean model output",
|
|
# "sort_order": 8
|
|
# },
|
|
# "remove_absolute_mask__r2": {
|
|
# "title": "Remove Absolute (mask)",
|
|
# "xlabel": "Max fraction of features removed",
|
|
# "ylabel": "1 - R^2",
|
|
# "sort_order": 9
|
|
# },
|
|
# "remove_absolute_mask__roc_auc": {
|
|
# "title": "Remove Absolute (mask)",
|
|
# "xlabel": "Max fraction of features removed",
|
|
# "ylabel": "1 - ROC AUC",
|
|
# "sort_order": 9
|
|
# },
|
|
# "keep_positive_resample": {
|
|
# "title": "Keep Positive (resample)",
|
|
# "xlabel": "Max fraction of features kept",
|
|
# "ylabel": "Mean model output",
|
|
# "sort_order": 10
|
|
# },
|
|
# "keep_negative_resample": {
|
|
# "title": "Keep Negative (resample)",
|
|
# "xlabel": "Max fraction of features kept",
|
|
# "ylabel": "Negative mean model output",
|
|
# "sort_order": 11
|
|
# },
|
|
# "keep_absolute_resample__r2": {
|
|
# "title": "Keep Absolute (resample)",
|
|
# "xlabel": "Max fraction of features kept",
|
|
# "ylabel": "R^2",
|
|
# "sort_order": 12
|
|
# },
|
|
# "keep_absolute_resample__roc_auc": {
|
|
# "title": "Keep Absolute (resample)",
|
|
# "xlabel": "Max fraction of features kept",
|
|
# "ylabel": "ROC AUC",
|
|
# "sort_order": 12
|
|
# },
|
|
# "remove_positive_resample": {
|
|
# "title": "Remove Positive (resample)",
|
|
# "xlabel": "Max fraction of features removed",
|
|
# "ylabel": "Negative mean model output",
|
|
# "sort_order": 13
|
|
# },
|
|
# "remove_negative_resample": {
|
|
# "title": "Remove Negative (resample)",
|
|
# "xlabel": "Max fraction of features removed",
|
|
# "ylabel": "Mean model output",
|
|
# "sort_order": 14
|
|
# },
|
|
# "remove_absolute_resample__r2": {
|
|
# "title": "Remove Absolute (resample)",
|
|
# "xlabel": "Max fraction of features removed",
|
|
# "ylabel": "1 - R^2",
|
|
# "sort_order": 15
|
|
# },
|
|
# "remove_absolute_resample__roc_auc": {
|
|
# "title": "Remove Absolute (resample)",
|
|
# "xlabel": "Max fraction of features removed",
|
|
# "ylabel": "1 - ROC AUC",
|
|
# "sort_order": 15
|
|
# },
|
|
# "remove_positive_retrain": {
|
|
# "title": "Remove Positive (retrain)",
|
|
# "xlabel": "Max fraction of features removed",
|
|
# "ylabel": "Negative mean model output",
|
|
# "sort_order": 11
|
|
# },
|
|
# "remove_negative_retrain": {
|
|
# "title": "Remove Negative (retrain)",
|
|
# "xlabel": "Max fraction of features removed",
|
|
# "ylabel": "Mean model output",
|
|
# "sort_order": 12
|
|
# },
|
|
# "keep_positive_retrain": {
|
|
# "title": "Keep Positive (retrain)",
|
|
# "xlabel": "Max fraction of features kept",
|
|
# "ylabel": "Mean model output",
|
|
# "sort_order": 6
|
|
# },
|
|
# "keep_negative_retrain": {
|
|
# "title": "Keep Negative (retrain)",
|
|
# "xlabel": "Max fraction of features kept",
|
|
# "ylabel": "Negative mean model output",
|
|
# "sort_order": 7
|
|
# },
|
|
# "batch_remove_absolute__r2": {
|
|
# "title": "Batch Remove Absolute",
|
|
# "xlabel": "Fraction of features removed",
|
|
# "ylabel": "1 - R^2",
|
|
# "sort_order": 13
|
|
# },
|
|
# "batch_keep_absolute__r2": {
|
|
# "title": "Batch Keep Absolute",
|
|
# "xlabel": "Fraction of features kept",
|
|
# "ylabel": "R^2",
|
|
# "sort_order": 8
|
|
# },
|
|
# "batch_remove_absolute__roc_auc": {
|
|
# "title": "Batch Remove Absolute",
|
|
# "xlabel": "Fraction of features removed",
|
|
# "ylabel": "1 - ROC AUC",
|
|
# "sort_order": 13
|
|
# },
|
|
# "batch_keep_absolute__roc_auc": {
|
|
# "title": "Batch Keep Absolute",
|
|
# "xlabel": "Fraction of features kept",
|
|
# "ylabel": "ROC AUC",
|
|
# "sort_order": 8
|
|
# },
|
|
# "linear_shap_corr": {
|
|
# "title": "Linear SHAP (corr)"
|
|
# },
|
|
# "linear_shap_ind": {
|
|
# "title": "Linear SHAP (ind)"
|
|
# },
|
|
# "coef": {
|
|
# "title": "Coefficients"
|
|
# },
|
|
# "random": {
|
|
# "title": "Random"
|
|
# },
|
|
# "kernel_shap_1000_meanref": {
|
|
# "title": "Kernel SHAP 1000 mean ref."
|
|
# },
|
|
# "sampling_shap_1000": {
|
|
# "title": "Sampling SHAP 1000"
|
|
# },
|
|
# "tree_shap_tree_path_dependent": {
|
|
# "title": "Tree SHAP"
|
|
# },
|
|
# "saabas": {
|
|
# "title": "Saabas"
|
|
# },
|
|
# "tree_gain": {
|
|
# "title": "Gain/Gini Importance"
|
|
# },
|
|
# "mean_abs_tree_shap": {
|
|
# "title": "mean(|Tree SHAP|)"
|
|
# },
|
|
# "lasso_regression": {
|
|
# "title": "Lasso Regression"
|
|
# },
|
|
# "ridge_regression": {
|
|
# "title": "Ridge Regression"
|
|
# },
|
|
# "gbm_regression": {
|
|
# "title": "Gradient Boosting Regression"
|
|
# }
|
|
}
|
|
|
|
benchmark_color_map = {
|
|
"tree_shap": "#1E88E5",
|
|
"deep_shap": "#1E88E5",
|
|
"linear_shap_corr": "#1E88E5",
|
|
"linear_shap_ind": "#ff0d57",
|
|
"coef": "#13B755",
|
|
"random": "#999999",
|
|
"const_random": "#666666",
|
|
"kernel_shap_1000_meanref": "#7C52FF",
|
|
}
|
|
|
|
# negated_metrics = [
|
|
# "runtime",
|
|
# "remove_positive_retrain",
|
|
# "remove_positive_mask",
|
|
# "remove_positive_resample",
|
|
# "keep_negative_retrain",
|
|
# "keep_negative_mask",
|
|
# "keep_negative_resample"
|
|
# ]
|
|
|
|
# one_minus_metrics = [
|
|
# "remove_absolute_mask__r2",
|
|
# "remove_absolute_mask__roc_auc",
|
|
# "remove_absolute_resample__r2",
|
|
# "remove_absolute_resample__roc_auc"
|
|
# ]
|
|
|
|
|
|
def get_method_color(method):
|
|
for line in getattr(methods, method).__doc__.split("\n"):
|
|
line = line.strip()
|
|
if line.startswith("color = "):
|
|
v = line.split("=")[1].strip()
|
|
if v.startswith("red_blue_circle("):
|
|
return colors.red_blue_circle(float(v[16:-1]))
|
|
else:
|
|
return v
|
|
return "#000000"
|
|
|
|
|
|
def get_method_linestyle(method):
|
|
for line in getattr(methods, method).__doc__.split("\n"):
|
|
line = line.strip()
|
|
if line.startswith("linestyle = "):
|
|
return line.split("=")[1].strip()
|
|
return "solid"
|
|
|
|
|
|
def get_metric_attr(metric, attr):
|
|
for line in getattr(metrics, metric).__doc__.split("\n"):
|
|
line = line.strip()
|
|
|
|
# string
|
|
prefix = attr + ' = "'
|
|
suffix = '"'
|
|
if line.startswith(prefix) and line.endswith(suffix):
|
|
return line[len(prefix) : -len(suffix)]
|
|
|
|
# number
|
|
prefix = attr + " = "
|
|
if line.startswith(prefix):
|
|
return float(line[len(prefix) :])
|
|
return ""
|
|
|
|
|
|
def plot_curve(dataset, model, metric, cmap=benchmark_color_map):
|
|
experiments = run_experiments(dataset=dataset, model=model, metric=metric)
|
|
pl.figure()
|
|
method_arr = []
|
|
for name, (fcounts, scores) in experiments:
|
|
_, _, method, _ = name
|
|
transform = get_metric_attr(metric, "transform")
|
|
if transform == "negate":
|
|
scores = -scores
|
|
elif transform == "one_minus":
|
|
scores = 1 - scores
|
|
auc = sklearn.metrics.auc(fcounts, scores) / fcounts[-1]
|
|
method_arr.append((auc, method, scores))
|
|
for auc, method, scores in sorted(method_arr):
|
|
method_title = getattr(methods, method).__doc__.split("\n")[0].strip()
|
|
label = f"{auc:6.3f} - " + method_title
|
|
pl.plot(
|
|
fcounts / fcounts[-1],
|
|
scores,
|
|
label=label,
|
|
color=get_method_color(method),
|
|
linewidth=2,
|
|
linestyle=get_method_linestyle(method),
|
|
)
|
|
metric_title = getattr(metrics, metric).__doc__.split("\n")[0].strip()
|
|
pl.xlabel(get_metric_attr(metric, "xlabel"))
|
|
pl.ylabel(get_metric_attr(metric, "ylabel"))
|
|
model_title = getattr(models, dataset + "__" + model).__doc__.split("\n")[0].strip()
|
|
pl.title(metric_title + " - " + model_title)
|
|
pl.gca().xaxis.set_ticks_position("bottom")
|
|
pl.gca().yaxis.set_ticks_position("left")
|
|
pl.gca().spines["right"].set_visible(False)
|
|
pl.gca().spines["top"].set_visible(False)
|
|
ahandles, alabels = pl.gca().get_legend_handles_labels()
|
|
pl.legend(reversed(ahandles), reversed(alabels))
|
|
return pl.gcf()
|
|
|
|
|
|
def plot_human(dataset, model, metric, cmap=benchmark_color_map):
|
|
experiments = run_experiments(dataset=dataset, model=model, metric=metric)
|
|
pl.figure()
|
|
method_arr = []
|
|
for name, (fcounts, scores) in experiments:
|
|
_, _, method, _ = name
|
|
diff_sum = np.sum(np.abs(scores[1] - scores[0]))
|
|
method_arr.append((diff_sum, method, scores[0], scores[1]))
|
|
|
|
inds = np.arange(3) # the x locations for the groups
|
|
inc_width = (1.0 / len(method_arr)) * 0.8
|
|
width = inc_width * 0.9
|
|
pl.bar(inds, method_arr[0][2], width, label="Human Consensus", color="black", edgecolor="white")
|
|
i = 1
|
|
line_style_to_hatch = {"dashed": "///", "dotted": "..."}
|
|
for diff_sum, method, _, methods_attrs in sorted(method_arr):
|
|
method_title = getattr(methods, method).__doc__.split("\n")[0].strip()
|
|
label = f"{diff_sum:.2f} - " + method_title
|
|
pl.bar(
|
|
inds + inc_width * i,
|
|
methods_attrs.flatten(),
|
|
width,
|
|
label=label,
|
|
edgecolor="white",
|
|
color=get_method_color(method),
|
|
hatch=line_style_to_hatch.get(get_method_linestyle(method), None),
|
|
)
|
|
i += 1
|
|
metric_title = getattr(metrics, metric).__doc__.split("\n")[0].strip()
|
|
pl.xlabel("Features in the model")
|
|
pl.ylabel("Feature attribution value")
|
|
model_title = getattr(models, dataset + "__" + model).__doc__.split("\n")[0].strip()
|
|
pl.title(metric_title + " - " + model_title)
|
|
pl.gca().xaxis.set_ticks_position("bottom")
|
|
pl.gca().yaxis.set_ticks_position("left")
|
|
pl.gca().spines["right"].set_visible(False)
|
|
pl.gca().spines["top"].set_visible(False)
|
|
ahandles, alabels = pl.gca().get_legend_handles_labels()
|
|
# pl.legend(ahandles, alabels)
|
|
pl.xticks(np.array([0, 1, 2, 3]) - (inc_width + width) / 2, ["", "", "", ""])
|
|
|
|
pl.gca().xaxis.set_minor_locator(matplotlib.ticker.FixedLocator([0.4, 1.4, 2.4]))
|
|
pl.gca().xaxis.set_minor_formatter(matplotlib.ticker.FixedFormatter(["Fever", "Cough", "Headache"]))
|
|
pl.gca().tick_params(which="minor", length=0)
|
|
|
|
pl.axhline(0, color="#aaaaaa", linewidth=0.5)
|
|
|
|
box = pl.gca().get_position()
|
|
pl.gca().set_position([box.x0, box.y0 + box.height * 0.3, box.width, box.height * 0.7])
|
|
|
|
# Put a legend below current axis
|
|
pl.gca().legend(ahandles, alabels, loc="upper center", bbox_to_anchor=(0.5, -0.15), ncol=2)
|
|
|
|
return pl.gcf()
|
|
|
|
|
|
def _human_score_map(human_consensus, methods_attrs):
|
|
"""Converts human agreement differences to numerical scores for coloring."""
|
|
v = 1 - min(np.sum(np.abs(methods_attrs - human_consensus)) / (np.abs(human_consensus).sum() + 1), 1.0)
|
|
return v
|
|
|
|
|
|
def make_grid(scores, dataset, model, normalize=True, transform=True):
|
|
color_vals = {}
|
|
metric_sort_order = {}
|
|
for (_, _, method, metric), (fcounts, score) in filter(lambda x: x[0][0] == dataset and x[0][1] == model, scores):
|
|
metric_sort_order[metric] = get_metric_attr(metric, "sort_order")
|
|
if metric not in color_vals:
|
|
color_vals[metric] = {}
|
|
|
|
if transform:
|
|
transform_type = get_metric_attr(metric, "transform")
|
|
if transform_type == "negate":
|
|
score = -score
|
|
elif transform_type == "one_minus":
|
|
score = 1 - score
|
|
elif transform_type == "negate_log":
|
|
score = -np.log10(score)
|
|
|
|
if fcounts is None:
|
|
color_vals[metric][method] = score
|
|
elif fcounts == "human":
|
|
color_vals[metric][method] = _human_score_map(*score)
|
|
else:
|
|
auc = sklearn.metrics.auc(fcounts, score) / fcounts[-1]
|
|
color_vals[metric][method] = auc
|
|
# print(metric_sort_order)
|
|
# col_keys = sorted(list(color_vals.keys()), key=lambda v: metric_sort_order[v])
|
|
# print(col_keys)
|
|
col_keys = list(color_vals.keys())
|
|
row_keys = list({v for k in col_keys for v in color_vals[k].keys()})
|
|
|
|
data = -28567 * np.ones((len(row_keys), len(col_keys)))
|
|
|
|
for i in range(len(row_keys)):
|
|
for j in range(len(col_keys)):
|
|
data[i, j] = color_vals[col_keys[j]][row_keys[i]]
|
|
|
|
assert np.sum(data == -28567) == 0, "There are missing data values!"
|
|
|
|
if normalize:
|
|
data = (data - data.min(0)) / (data.max(0) - data.min(0) + 1e-8)
|
|
|
|
# sort by performans
|
|
inds = np.argsort(-data.mean(1))
|
|
row_keys = [row_keys[i] for i in inds]
|
|
data = data[inds, :]
|
|
|
|
return row_keys, col_keys, data
|
|
|
|
|
|
red_blue_solid = LinearSegmentedColormap(
|
|
"red_blue_solid",
|
|
{
|
|
"red": ((0.0, 198.0 / 255, 198.0 / 255), (1.0, 5.0 / 255, 5.0 / 255)),
|
|
"green": ((0.0, 34.0 / 255, 34.0 / 255), (1.0, 198.0 / 255, 198.0 / 255)),
|
|
"blue": ((0.0, 5.0 / 255, 5.0 / 255), (1.0, 24.0 / 255, 24.0 / 255)),
|
|
"alpha": ((0.0, 1, 1), (1.0, 1, 1)),
|
|
},
|
|
)
|
|
|
|
|
|
def plot_grids(dataset, model_names, out_dir=None):
|
|
if out_dir is not None:
|
|
os.mkdir(out_dir)
|
|
|
|
scores = []
|
|
for model in model_names:
|
|
scores.extend(run_experiments(dataset=dataset, model=model))
|
|
|
|
prefix = "<style type='text/css'> .shap_benchmark__select:focus { outline-width: 0 }</style>"
|
|
out = "" # background: rgb(30, 136, 229)
|
|
|
|
# out += "<div style='font-weight: regular; font-size: 24px; text-align: center; background: #f8f8f8; color: #000; padding: 20px;'>SHAP Benchmark</div>\n"
|
|
# out += "<div style='height: 1px; background: #ddd;'></div>\n"
|
|
# out += "<div style='height: 7px; background-image: linear-gradient(to right, rgb(30, 136, 229), rgb(255, 13, 87));'></div>"
|
|
|
|
out += "<div style='position: fixed; left: 0px; top: 0px; right: 0px; height: 230px; background: #fff;'>\n" # box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
|
out += "<div style='position: absolute; bottom: 0px; left: 0px; right: 0px;' align='center'><table style='border-width: 1px; margin-right: 100px'>\n"
|
|
for ind, model in enumerate(model_names):
|
|
row_keys, col_keys, data = make_grid(scores, dataset, model)
|
|
# print(data)
|
|
# print(colors.red_blue_solid(0.))
|
|
# print(colors.red_blue_solid(1.))
|
|
# return
|
|
for metric in col_keys:
|
|
save_plot = False
|
|
if metric.startswith("human_"):
|
|
plot_human(dataset, model, metric)
|
|
save_plot = True
|
|
elif metric not in ["local_accuracy", "runtime", "consistency_guarantees"]:
|
|
plot_curve(dataset, model, metric)
|
|
save_plot = True
|
|
|
|
if save_plot:
|
|
buf = io.BytesIO()
|
|
pl.gcf().set_size_inches(1200.0 / 175, 1000.0 / 175)
|
|
pl.savefig(buf, format="png", dpi=175)
|
|
if out_dir is not None:
|
|
pl.savefig(f"{out_dir}/plot_{dataset}_{model}_{metric}.pdf", format="pdf")
|
|
pl.close()
|
|
buf.seek(0)
|
|
data_uri = base64.b64encode(buf.read()).decode("utf-8").replace("\n", "")
|
|
plot_id = "plot__" + dataset + "__" + model + "__" + metric
|
|
prefix += f"<div onclick='document.getElementById(\"{plot_id}\").style.display = \"none\"' style='display: none; position: fixed; z-index: 10000; left: 0px; right: 0px; top: 0px; bottom: 0px; background: rgba(255,255,255,0.9);' id='{plot_id}'>"
|
|
prefix += f"<img width='600' height='500' style='margin-left: auto; margin-right: auto; margin-top: 230px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);' src='data:image/png;base64,{data_uri}'>"
|
|
prefix += "</div>"
|
|
|
|
model_title = getattr(models, dataset + "__" + model).__doc__.split("\n")[0].strip()
|
|
|
|
if ind == 0:
|
|
out += "<tr><td style='background: #fff; width: 250px'></td></td>"
|
|
for j in range(data.shape[1]):
|
|
metric_title = getattr(metrics, col_keys[j]).__doc__.split("\n")[0].strip()
|
|
out += (
|
|
"<td style='width: 40px; min-width: 40px; background: #fff; text-align: right;'><div style='margin-left: 10px; margin-bottom: -5px; white-space: nowrap; transform: rotate(-45deg); transform-origin: left top 0; width: 1.5em; margin-top: 8em'>"
|
|
+ metric_title
|
|
+ "</div></td>"
|
|
)
|
|
out += "</tr>\n"
|
|
out += "</table></div></div>\n"
|
|
out += "<table style='border-width: 1px; margin-right: 100px; margin-top: 230px;'>\n"
|
|
out += f"<tr><td style='background: #fff'></td><td colspan='{data.shape[1]}' style='background: #fff; font-weight: bold; text-align: center; margin-top: 10px;'>{model_title}</td></tr>\n"
|
|
for i in range(data.shape[0]):
|
|
out += "<tr>"
|
|
# if i == 0:
|
|
# out += "<td rowspan='%d' style='background: #fff; text-align: center; white-space: nowrap; vertical-align: middle; '><div style='font-weight: bold; transform: rotate(-90deg); transform-origin: left top 0; width: 1.5em; margin-top: 8em'>%s</div></td>" % (data.shape[0], model_name)
|
|
method_title = getattr(methods, row_keys[i]).__doc__.split("\n")[0].strip()
|
|
out += (
|
|
"<td style='background: #ffffff; text-align: right; width: 250px' title='shap.LinearExplainer(model)'>"
|
|
+ method_title
|
|
+ "</td>\n"
|
|
)
|
|
for j in range(data.shape[1]):
|
|
plot_id = "plot__" + dataset + "__" + model + "__" + col_keys[j]
|
|
out += f"<td onclick='document.getElementById(\"{plot_id}\").style.display = \"block\"' style='padding: 0px; padding-left: 0px; padding-right: 0px; border-left: 0px solid #999; width: 42px; min-width: 42px; height: 34px; background-color: #fff'>"
|
|
# out += "<div style='opacity: "+str(2*(max(1-data[i,j], data[i,j])-0.5))+"; background-color: rgb" + str(tuple(v*255 for v in colors.red_blue_solid(0. if data[i,j] < 0.5 else 1.)[:-1])) + "; height: "+str((30*max(1-data[i,j], data[i,j])))+"px; margin-left: auto; margin-right: auto; width:"+str((30*max(1-data[i,j], data[i,j])))+"px'></div>"
|
|
out += (
|
|
"<div style='opacity: "
|
|
+ str(1)
|
|
+ "; background-color: rgb"
|
|
+ str(tuple(int(v * 255) for v in colors.red_blue_no_bounds(5 * (data[i, j] - 0.8))[:-1]))
|
|
+ "; height: "
|
|
+ str(30 * data[i, j])
|
|
+ "px; margin-left: auto; margin-right: auto; width:"
|
|
+ str(30 * data[i, j])
|
|
+ "px'></div>"
|
|
)
|
|
# out += "<div style='float: left; background-color: #eee; height: 10px; width: "+str((40*(1-data[i,j])))+"px'></div>"
|
|
out += "</td>\n"
|
|
out += "</tr>\n" #
|
|
|
|
out += f"<tr><td colspan='{data.shape[1] + 1}' style='background: #fff'></td></tr>"
|
|
out += "</table>"
|
|
|
|
out += "<div style='position: fixed; left: 0px; top: 0px; right: 0px; text-align: left; padding: 20px; text-align: right'>\n"
|
|
out += (
|
|
"<div style='float: left; font-weight: regular; font-size: 24px; color: #000;'>SHAP Benchmark <span style='font-size: 14px; color: #777777;'>v"
|
|
+ __version__
|
|
+ "</span></div>\n"
|
|
)
|
|
# select {
|
|
# margin: 50px;
|
|
# width: 150px;
|
|
# padding: 5px 35px 5px 5px;
|
|
# font-size: 16px;
|
|
# border: 1px solid #ccc;
|
|
# height: 34px;
|
|
# -webkit-appearance: none;
|
|
# -moz-appearance: none;
|
|
# appearance: none;
|
|
# background: url(http://www.stackoverflow.com/favicon.ico) 96% / 15% no-repeat #eee;
|
|
# }
|
|
# out += "<div style='display: inline-block; margin-right: 20px; font-weight: normal; text-decoration: none; font-size: 18px; color: #000;'>Dataset:</div>\n"
|
|
|
|
out += "<select id='shap_benchmark__select' onchange=\"document.location = '../' + this.value + '/index.html'\"dir='rtl' class='shap_benchmark__select' style='font-weight: normal; font-size: 20px; color: #000; padding: 10px; background: #fff; border: 1px solid #fff; -webkit-appearance: none; appearance: none;'>\n"
|
|
out += (
|
|
"<option value='human' "
|
|
+ ("selected" if dataset == "human" else "")
|
|
+ ">Agreement with Human Intuition</option>\n"
|
|
)
|
|
out += (
|
|
"<option value='corrgroups60' "
|
|
+ ("selected" if dataset == "corrgroups60" else "")
|
|
+ ">Correlated Groups 60 Dataset</option>\n"
|
|
)
|
|
out += (
|
|
"<option value='independentlinear60' "
|
|
+ ("selected" if dataset == "independentlinear60" else "")
|
|
+ ">Independent Linear 60 Dataset</option>\n"
|
|
)
|
|
# out += "<option>CRIC</option>\n"
|
|
out += "</select>\n"
|
|
# out += "<script> document.onload = function() { document.getElementById('shap_benchmark__select').value = '"+dataset+"'; }</script>"
|
|
# out += "<div style='display: inline-block; margin-left: 20px; font-weight: normal; text-decoration: none; font-size: 18px; color: #000;'>CRIC</div>\n"
|
|
out += "</div>\n"
|
|
|
|
# output the legend
|
|
out += "<table style='border-width: 0px; width: 100px; position: fixed; right: 50px; top: 200px; background: rgba(255, 255, 255, 0.9)'>\n"
|
|
out += "<tr><td style='background: #fff; font-weight: normal; text-align: center'>Higher score</td></tr>\n"
|
|
legend_size = 21
|
|
for i in range(legend_size - 9):
|
|
out += "<tr>"
|
|
out += "<td style='padding: 0px; padding-left: 0px; padding-right: 0px; border-left: 0px solid #999; height: 34px'>"
|
|
val = (legend_size - i - 1) / (legend_size - 1)
|
|
out += (
|
|
"<div style='opacity: 1; background-color: rgb"
|
|
+ str(tuple(int(v * 255) for v in colors.red_blue_no_bounds(5 * (val - 0.8)))[:-1])
|
|
+ "; height: "
|
|
+ str(30 * val)
|
|
+ "px; margin-left: auto; margin-right: auto; width:"
|
|
+ str(30 * val)
|
|
+ "px'></div>"
|
|
)
|
|
out += "</td>"
|
|
out += "</tr>\n" #
|
|
out += "<tr><td style='background: #fff; font-weight: normal; text-align: center'>Lower score</td></tr>\n"
|
|
out += "</table>\n"
|
|
|
|
if out_dir is not None:
|
|
with open(out_dir + "/index.html", "w") as f:
|
|
f.write(
|
|
"<html><body style='margin: 0px; font-size: 16px; font-family: \"Myriad Pro\", Arial, sans-serif;'><center>"
|
|
)
|
|
f.write(prefix)
|
|
f.write(out)
|
|
f.write("</center></body></html>")
|
|
else:
|
|
return HTML(prefix + out)
|