|
|
import subprocess |
|
|
import re |
|
|
import streamlit as st |
|
|
import json |
|
|
from typing import Optional |
|
|
|
|
|
|
|
|
def show_error(msg, action): |
|
|
st.error( |
|
|
f"Failed to {action}:\n\n...{msg}\n\nPlease [report](https://github.com/LudvigOlsen/plot_confusion_matrix/issues) this issue." |
|
|
) |
|
|
|
|
|
|
|
|
def call_subprocess(call_, message, return_output=False, encoding="UTF-8"): |
|
|
|
|
|
if return_output: |
|
|
try: |
|
|
out = subprocess.check_output(call_, shell=True, encoding=encoding) |
|
|
except subprocess.CalledProcessError as e: |
|
|
if "Failed to create plot from confusion matrix." in e.output: |
|
|
msg = e.output.split("Failed to create plot from confusion matrix.")[-1] |
|
|
show_error(msg=msg, action="plot confusion matrix") |
|
|
elif "Failed to read design settings as a json file" in e.output: |
|
|
msg = e.output.split("Failed to read design settings as a json file")[ |
|
|
-1 |
|
|
] |
|
|
show_error(msg=msg, action="read design settings") |
|
|
elif "Failed to read data from" in e.output: |
|
|
msg = e.output.split("Failed to read data from")[-1] |
|
|
show_error(msg=msg, action="read data") |
|
|
elif "Failed to ggsave plot to:" in e.output: |
|
|
msg = e.output.split("Failed to ggsave plot to:")[-1] |
|
|
show_error(msg=msg, action="save plot") |
|
|
else: |
|
|
msg = e.output.split("\n\n")[-1] |
|
|
st.error( |
|
|
f"Unknown type of error: {msg}.\n\n" |
|
|
"Please [report](https://github.com/LudvigOlsen/plot_confusion_matrix/issues) this issue." |
|
|
) |
|
|
print(e.output) |
|
|
print(f"{message}: {call_}") |
|
|
raise e |
|
|
return out |
|
|
|
|
|
|
|
|
try: |
|
|
subprocess.check_call(call_, shell=True) |
|
|
except subprocess.CalledProcessError as e: |
|
|
print(f"{message}: {call_}") |
|
|
raise e |
|
|
|
|
|
|
|
|
def clean_string_for_non_alphanumerics(s): |
|
|
|
|
|
pattern1 = re.compile("[^0-9a-zA-Z\s]+") |
|
|
|
|
|
pattern2 = re.compile("\s+") |
|
|
|
|
|
s = pattern1.sub("", s) |
|
|
s = pattern2.sub(" ", s) |
|
|
|
|
|
return s.strip() |
|
|
|
|
|
|
|
|
def clean_str_column(x): |
|
|
return x.astype(str).apply(lambda x: clean_string_for_non_alphanumerics(x)) |
|
|
|
|
|
|
|
|
def min_max_scale_list( |
|
|
x: list, |
|
|
new_min: float, |
|
|
new_max: float, |
|
|
old_min: Optional[float] = None, |
|
|
old_max: Optional[float] = None, |
|
|
) -> list: |
|
|
""" |
|
|
MinMax scaler for lists. |
|
|
Why: Currently we don't require numpy as dependency. |
|
|
""" |
|
|
if old_min is None: |
|
|
old_min = min(x) |
|
|
if old_max is None: |
|
|
old_max = max(x) |
|
|
|
|
|
diff = old_max - old_min |
|
|
|
|
|
|
|
|
if diff == 0: |
|
|
diff = 1 |
|
|
|
|
|
x = [(xi - old_min) / diff for xi in x] |
|
|
return [xi * (new_max - new_min) + new_min for xi in x] |
|
|
|