Commit 99528e01 authored by Luigi Sbailo's avatar Luigi Sbailo
Browse files

Adapt visualiezer for convex hulls

parent a026a7ae
......@@ -4,14 +4,14 @@ from jupyter_jsmol import JsmolView
import numpy as np
from IPython.display import display, HTML, FileLink
import os
import pandas as pd
from scipy.spatial import ConvexHull
import pandas as pd
class Visualizer:
def __init__(self, df_selected, sisso):
def __init__(self, df, sisso):
self.sisso = sisso
self.df_selected = df_selected
self.df = df
self.marker_size = 7
self.marker_symbol_cls0 = 'circle'
self.marker_symbol_cls1 = 'square'
......@@ -52,30 +52,15 @@ class Visualizer:
self.color_cls1 = "#EB8273"
self.color_cls0 = "rgb(138, 147, 248)"
# self.total_features = sisso.n_dim
# self.feat_val_list = list(reversed([feat.value for feat in sisso.models[sisso.n_dim - 1][0].feats]))
# self.features = list(reversed([str(feat) for feat in sisso.models[sisso.n_dim - 1][0].feats]))
# self.df_selected = pd.DataFrame()
# for feat, values in zip(self.features, self.feat_val_list):
# self.df_selected[feat] = values
# self.target_predict = sisso.models[sisso.n_dim - 1][0].fit
# self.target_train = sisso.models[sisso.n_dim - 1][0].prop_train
self.total_features = sisso.n_dim
self.features = list(reversed([str(feat) for feat in sisso.models[sisso.n_dim - 1][0].feats]))
self.coefficients = list(reversed(sisso.models[sisso.n_dim - 1][0].coefs[0][:-1]))
self.intercept = sisso.models[sisso.n_dim - 1][0].coefs[0][-1]
self.total_features = 2
self.features = ['Feat_0', 'Feat_1']
self.feat_val_list = df_selected[self.features]
# self.df_selected['Structure'] = df.reset_index()['min_struc_type']
# self.df_selected['Chem Formula'] = df.index.to_numpy()
self.df_cls0 = df_selected['Classification'] == 0
self.df_cls1 = df_selected['Classification'] == 1
self.df_cls0 = df['Classification'] == 0
self.df_cls1 = df['Classification'] == 1
self.compounds_list = df['Compound'].to_list()
self.bg_toggle = True
self.compounds_list = df_selected['Compound'].to_list()
self.npoints_cls0 = len(self.df_cls0)
self.npoints_cls1 = len(self.df_cls1)
self.symbols_cls0 = [self.marker_symbol_cls0] * self.npoints_cls0
......@@ -90,35 +75,7 @@ class Visualizer:
self.viewer_r = JsmolView()
self.instantiate_widgets()
line_x, line_y = self.f_x(self.features[0], self.features[1])
self.line_x = line_x
self.line_y = line_y
# Design of the convex hulls
hull_cls0 = ConvexHull(df_selected[self.df_cls0][[self.features[0], self.features[1]]].to_numpy())
vertexes_cls0 = df_selected[self.df_cls0][[self.features[0], self.features[1]]].to_numpy()[hull_cls0.vertices]
hull_cls1 = ConvexHull(df_selected[self.df_cls1][[self.features[0], self.features[1]]].to_numpy())
vertexes_cls1 = df_selected[self.df_cls1][[self.features[0], self.features[1]]].to_numpy()[hull_cls1.vertices]
x_hullvx_cls0 = vertexes_cls0[:, 0]
y_hullvx_cls0 = vertexes_cls0[:, 1]
x_hullvx_cls1 = vertexes_cls1[:, 0]
y_hullvx_cls1 = vertexes_cls1[:, 1]
n_intervals = 100
self.xhull_cls0 = np.array([x_hullvx_cls0[0]])
self.yhull_cls0 = np.array([y_hullvx_cls0[0]])
for xy in zip(x_hullvx_cls0, y_hullvx_cls0):
self.xhull_cls0 = np.concatenate([self.xhull_cls0, np.linspace(self.xhull_cls0[-1], xy[0], n_intervals)])
self.yhull_cls0 = np.concatenate([self.yhull_cls0, np.linspace(self.yhull_cls0[-1], xy[1], n_intervals)])
self.xhull_cls0 = np.concatenate([self.xhull_cls0, np.linspace(self.xhull_cls0[-1], x_hullvx_cls0[0], n_intervals)])
self.yhull_cls0 = np.concatenate([self.yhull_cls0, np.linspace(self.yhull_cls0[-1], y_hullvx_cls0[0], n_intervals)])
self.xhull_cls1 = np.array([x_hullvx_cls1[0]])
self.yhull_cls1 = np.array([y_hullvx_cls1[0]])
for xy in zip(x_hullvx_cls1, y_hullvx_cls1):
self.xhull_cls1 = np.concatenate([self.xhull_cls1, np.linspace(self.xhull_cls1[-1], xy[0], n_intervals)])
self.yhull_cls1 = np.concatenate([self.yhull_cls1, np.linspace(self.yhull_cls1[-1], xy[1], n_intervals)])
self.xhull_cls1 = np.concatenate(
[self.xhull_cls1, np.linspace(self.xhull_cls1[-1], x_hullvx_cls1[0], n_intervals)])
self.yhull_cls1 = np.concatenate(
[self.yhull_cls1, np.linspace(self.yhull_cls1[-1], y_hullvx_cls1[0], n_intervals)])
hullx_cls0, hully_cls0, hullx_cls1, hully_cls1 = self.make_hull(self.features[0], self.features[1])
# custom_cls0 = np.dstack((self.target_train[self.df_cls0],
# self.target_predict[self.df_cls0]))[0]
......@@ -126,10 +83,10 @@ class Visualizer:
# self.target_predict[self.df_cls1]))[0]
# the final plot is the sum of two traces, respectively containing the RS vs ZB materials
x_cls0 = self.feat_val_list[self.features[0]][self.df_cls0]
y_cls0 = self.feat_val_list[self.features[1]][self.df_cls0]
x_cls1 = self.feat_val_list[self.features[0]][self.df_cls1]
y_cls1 = self.feat_val_list[self.features[1]][self.df_cls1]
x_cls0 = df[self.features[0]][self.df_cls0]
y_cls0 = df[self.features[1]][self.df_cls0]
x_cls1 = df[self.features[0]][self.df_cls1]
y_cls1 = df[self.features[1]][self.df_cls1]
self.fig.add_trace(
(
go.Scatter(
......@@ -137,15 +94,14 @@ class Visualizer:
x=x_cls0,
y=y_cls0,
# customdata=custom_cls0,
# text=df[self.df_cls0].index.to_numpy(),
# hovertemplate=
# r"<b>%{text}</b><br><br>" +
# "x axis: %{x:,.2f}<br>" +
# "y axis: %{y:,.2f}<br>",
text=df[self.df_cls0]['Compound'].to_numpy(),
hovertemplate=
r"<b>%{text}</b><br><br>" +
"x axis: %{x:,.2f}<br>" +
"y axis: %{y:,.2f}<br>",
# "ΔE reference: %{customdata[0]:,.4f}<br>" +
# "ΔE predicted: %{customdata[1]:,.4f}<br>"
# name='RS',
name='Class 0',
marker=dict(color=self.colors_cls0),
)
))
......@@ -156,21 +112,21 @@ class Visualizer:
x=x_cls1,
y=y_cls1,
# customdata=custom_cls1,
# text=df[self.df_cls1].index.to_numpy(),
# hovertemplate=
# r"<b>%{text}</b><br><br>" +
# "x axis: %{x:,.2f}<br>" +
# "y axis: %{y:,.2f}<br>",
# # "ΔE reference: %{customdata[0]:,.4f}<br>" +
# # "ΔE predicted: %{customdata[1]:,.4f}<br>",
# name='ZB',
text=df[self.df_cls1]['Compound'].to_numpy(),
hovertemplate=
r"<b>%{text}</b><br><br>" +
"x axis: %{x:,.2f}<br>" +
"y axis: %{y:,.2f}<br>",
# "ΔE reference: %{customdata[0]:,.4f}<br>" +
# "ΔE predicted: %{customdata[1]:,.4f}<br>",
name='Class 1',
marker=dict(color=self.colors_cls1),
)
))
self.fig.add_trace(
go.Scatter(
x=self.xhull_cls0,
y=self.yhull_cls0,
x=hullx_cls0,
y=hully_cls0,
line=dict(color='Grey', width=1, dash=self.line_styles[0]),
name=r'Convex' + '<br>' + 'hull 0',
visible=True
......@@ -178,8 +134,8 @@ class Visualizer:
)
self.fig.add_trace(
go.Scatter(
x=self.xhull_cls1,
y=self.yhull_cls1,
x=hullx_cls1,
y=hully_cls1,
line=dict(color='Grey', width=1, dash=self.line_styles[0]),
name=r'Convex' + '<br>' + 'hull 1',
visible=True
......@@ -188,8 +144,8 @@ class Visualizer:
)
self.fig.add_trace(
go.Scatter(
x=self.line_x,
y=self.line_y,
x=line_x,
y=line_y,
line=dict(color='Black', width=1, dash='solid'),
name=r'Classification' + '<br>' + 'line',
visible=True
......@@ -244,21 +200,49 @@ class Visualizer:
self.update_markers()
def f_x(self, feat_x, feat_y):
idx_x = self.features.index(feat_x)
idx_y = self.features.index(feat_y)
line_x = np.linspace(self.df_selected[feat_x].min(), self.df_selected[feat_x].max(), 1000)
line_x = np.linspace(self.df[feat_x].min(), self.df[feat_x].max(), 1000)
# Gives the classifications line
if self.widg_featx.value == self.widg_featy.value:
return line_x, line_x
else:
# print('x', self.coefficients[self.current_features[idx_x]])
# print('y', self.coefficients[self.current_features[idx_y]])
line_y = -line_x * self.coefficients[idx_x] / self.coefficients[idx_y] - self.intercept / self.coefficients[
idx_y]
return line_x, line_y
def make_hull(self, feat_x, feat_y):
hull_cls0 = ConvexHull(self.df[self.df_cls0][[feat_x, feat_y]].to_numpy())
vertexes_cls0 = self.df[self.df_cls0][[feat_x, feat_y]].to_numpy()[hull_cls0.vertices]
hull_cls1 = ConvexHull(self.df[self.df_cls1][[feat_x, feat_y]].to_numpy())
vertexes_cls1 = self.df[self.df_cls1][[feat_x, feat_y]].to_numpy()[hull_cls1.vertices]
x_hullvx_cls0 = vertexes_cls0[:, 0]
y_hullvx_cls0 = vertexes_cls0[:, 1]
x_hullvx_cls1 = vertexes_cls1[:, 0]
y_hullvx_cls1 = vertexes_cls1[:, 1]
n_intervals = 100
xhull_cls0 = np.array([x_hullvx_cls0[0]])
yhull_cls0 = np.array([y_hullvx_cls0[0]])
for xy in zip(x_hullvx_cls0, y_hullvx_cls0):
xhull_cls0 = np.concatenate([xhull_cls0, np.linspace(xhull_cls0[-1], xy[0], n_intervals)])
yhull_cls0 = np.concatenate([yhull_cls0, np.linspace(yhull_cls0[-1], xy[1], n_intervals)])
xhull_cls0 = np.concatenate([xhull_cls0, np.linspace(xhull_cls0[-1], x_hullvx_cls0[0], n_intervals)])
yhull_cls0 = np.concatenate([yhull_cls0, np.linspace(yhull_cls0[-1], y_hullvx_cls0[0], n_intervals)])
xhull_cls1 = np.array([x_hullvx_cls1[0]])
yhull_cls1 = np.array([y_hullvx_cls1[0]])
for xy in zip(x_hullvx_cls1, y_hullvx_cls1):
xhull_cls1 = np.concatenate([xhull_cls1, np.linspace(xhull_cls1[-1], xy[0], n_intervals)])
yhull_cls1 = np.concatenate([yhull_cls1, np.linspace(yhull_cls1[-1], xy[1], n_intervals)])
xhull_cls1 = np.concatenate(
[xhull_cls1, np.linspace(xhull_cls1[-1], x_hullvx_cls1[0], n_intervals)])
yhull_cls1 = np.concatenate(
[yhull_cls1, np.linspace(yhull_cls1[-1], y_hullvx_cls1[0], n_intervals)])
return xhull_cls0, yhull_cls0, xhull_cls1, yhull_cls1
def update_markers(self):
# Markers size and symbol are updated simultaneously
with self.fig.batch_update():
......@@ -303,14 +287,14 @@ class Visualizer:
self.sizes_cls0 = sizes_cls0
self.sizes_cls1 = sizes_cls1
else:
min_value = min(min(self.df_selected.loc[self.df_selected['Structure'] == 'RS'][feature]),
min(self.df_selected.loc[self.df_selected['Structure'] == 'ZB'][feature]))
max_value = max(max(self.df_selected.loc[self.df_selected['Structure'] == 'RS'][feature]),
max(self.df_selected.loc[self.df_selected['Structure'] == 'ZB'][feature]))
min_value = min(min(self.df.loc[self.df_cls0][feature]),
min(self.df.loc[self.df_cls1][feature]))
max_value = max(max(self.df.loc[self.df_cls0][feature]),
max(self.df.loc[self.df_cls1][feature]))
coeff = 2 * self.marker_size / (max_value - min_value)
sizes_cls0 = self.marker_size / 2 + coeff * self.df_selected.loc[self.df_selected['Structure'] == 'RS'][
sizes_cls0 = self.marker_size / 2 + coeff * self.df.loc[self.df_cls0][
feature]
sizes_cls1 = self.marker_size / 2 + coeff * self.df_selected.loc[self.df_selected['Structure'] == 'ZB'][
sizes_cls1 = self.marker_size / 2 + coeff * self.df.loc[self.df_cls1][
feature]
self.sizes_cls0 = sizes_cls0
self.sizes_cls1 = sizes_cls1
......@@ -324,11 +308,11 @@ class Visualizer:
else:
min_value = self.df_selected[feature].min()
max_value = self.df_selected[feature].max()
shade_cls0 = 0.7*(self.df_selected.loc[self.df_selected['Structure'] == 'RS'][feature].to_numpy() - min_value)/\
min_value = self.df[feature].min()
max_value = self.df[feature].max()
shade_cls0 = 0.7 * (self.df.loc[self.df_cls0][feature].to_numpy() - min_value) / \
(max_value-min_value)
shade_cls1 = 0.7*(self.df_selected.loc[self.df_selected['Structure'] == 'ZB'][feature].to_numpy() - min_value)/\
shade_cls1 = 0.7 * (self.df.loc[self.df_cls1][feature].to_numpy() - min_value) / \
(max_value-min_value)
if gradient == 'Grey scale':
......@@ -362,11 +346,9 @@ class Visualizer:
self.colors_cls1[i] = string
shade_cls0 = 0.7 * (
self.df_selected.loc[self.df_selected['Structure'] == 'RS'][feature].to_numpy() - min_value) / \
(max_value - min_value)
self.df.loc[self.df_cls0][feature].to_numpy() - min_value) / (max_value - min_value)
shade_cls1 = 0.7 * (
self.df_selected.loc[self.df_selected['Structure'] == 'ZB'][feature].to_numpy() - min_value) / \
(max_value - min_value)
self.df.loc[self.df_cls1][feature].to_numpy() - min_value) / (max_value - min_value)
if gradient == 'Blue to green':
for i, e in enumerate(shade_cls0):
value = 255 * e
......@@ -406,36 +388,69 @@ class Visualizer:
def handle_xfeat_change(self, change):
# changes the feature plotted on the x-axis
# separating line is modified accordingly
feat_x = change.new
feat_y = self.widg_featy.value
self.fig.update_layout(
xaxis_title=change.new,
xaxis_title=feat_x,
)
self.scatter_cls0['x'] = self.df_selected.loc[self.df_selected['Structure'] == 'RS'][change.new].to_numpy()
self.scatter_cls1['x'] = self.df_selected.loc[self.df_selected['Structure'] == 'ZB'][change.new].to_numpy()
line_x, line_y = self.f_x(change.new, self.widg_featy.value)
self.scatter_hull0['x'] = line_x
self.scatter_hull0['y'] = line_y
self.scatter_cls0['x'] = self.df.loc[self.df_cls0][feat_x].to_numpy()
self.scatter_cls1['x'] = self.df.loc[self.df_cls1][feat_x].to_numpy()
line_x, line_y = self.f_x(feat_x, feat_y)
min_x = min(min(self.scatter_cls0['x']), min(self.scatter_cls1['x']))
max_x = max(max(self.scatter_cls0['x']), max(self.scatter_cls1['x']))
min_delta = 0.05 * abs(max_x - min_x)
self.fig.layout['xaxis'].range = [min_x - min_delta, max_x + min_delta]
with self.fig.batch_update():
self.scatter_clsline['x'] = line_x
self.scatter_clsline['y'] = line_y
self.fig.layout['xaxis'].range = [min_x - min_delta, max_x + min_delta]
if feat_x == feat_y:
self.scatter_hull0.visible = False
self.scatter_hull1.visible = False
else:
self.scatter_hull0.visible = True
self.scatter_hull1.visible = True
hullx_cls0, hully_cls0, hullx_cls1, hully_cls1 = self.make_hull(feat_x, feat_y)
self.scatter_hull0['x'] = hullx_cls0
self.scatter_hull0['y'] = hully_cls0
self.scatter_hull1['x'] = hullx_cls1
self.scatter_hull1['y'] = hully_cls1
def handle_yfeat_change(self, change):
# changes the feature plotted on the x-axis
# separating line is modified accordingly
feat_x = self.widg_featx.value
feat_y = change.new
self.fig.update_layout(
yaxis_title=change.new,
yaxis_title=feat_y,
)
self.scatter_cls0['y'] = self.df_selected.loc[self.df_selected['Structure'] == 'RS'][change.new].to_numpy()
self.scatter_cls1['y'] = self.df_selected.loc[self.df_selected['Structure'] == 'ZB'][change.new].to_numpy()
line_x, line_y = self.f_x(self.widg_featx.value, change.new)
self.scatter_cls0['y'] = self.df.loc[self.df_cls0][feat_y].to_numpy()
self.scatter_cls1['y'] = self.df.loc[self.df_cls1][feat_y].to_numpy()
self.scatter_hull0['x'] = line_x
self.scatter_hull0['y'] = line_y
line_x, line_y = self.f_x(feat_x, feat_y)
min_y = min(min(self.scatter_cls0['y']), min(self.scatter_cls1['y']))
max_y = max(max(self.scatter_cls0['y']), max(self.scatter_cls1['y']))
min_delta = 0.05 * abs(max_y - min_y)
self.fig.layout['yaxis'].range = [min_y - min_delta, max_y + min_delta]
with self.fig.batch_update():
self.scatter_clsline['x'] = line_x
self.scatter_clsline['y'] = line_y
self.fig.layout['yaxis'].range = [min_y - min_delta, max_y + min_delta]
if feat_x == feat_y:
self.scatter_hull0.visible = False
self.scatter_hull1.visible = False
else:
self.scatter_hull0.visible = True
self.scatter_hull1.visible = True
hullx_cls0, hully_cls0, hullx_cls1, hully_cls1 = self.make_hull(feat_x, feat_y)
self.scatter_hull0['x'] = hullx_cls0
self.scatter_hull0['y'] = hully_cls0
self.scatter_hull1['x'] = hullx_cls1
self.scatter_hull1['y'] = hully_cls1
def handle_markerfeat_change(self, change):
self.set_markers_size(feature=change.new)
......@@ -458,9 +473,9 @@ class Visualizer:
def display_button_l_clicked(self, button):
# Actions are performed only if the string inserted in the text widget corresponds to an existing compound
if self.widg_compound_text_l.value in self.df_selected['Chem Formula'].tolist():
structure_l = self.df_selected[self.df_selected['Chem Formula'] ==
self.widg_compound_text_l.value]['Structure'].values[0]
if self.widg_compound_text_l.value in self.df['Chem Formula'].tolist():
structure_l = self.df[self.df['Chem Formula'] ==
self.widg_compound_text_l.value]['Structure'].values[0]
self.viewer_l.script(
"load data/topological_insulators/structures/" + structure_l + "_structures/"
+ self.widg_compound_text_l.value + ".xyz")
......@@ -492,9 +507,9 @@ class Visualizer:
def display_button_r_clicked(self, button):
# Actions are performed only if the string inserted in the text widget corresponds to an existing compound
if self.widg_compound_text_r.value in self.df_selected['Chem Formula'].tolist():
structure_r = self.df_selected[self.df_selected['Chem Formula'] ==
self.widg_compound_text_r.value]['Structure'].values[0]
if self.widg_compound_text_r.value in self.df['Chem Formula'].tolist():
structure_r = self.df[self.df['Chem Formula'] ==
self.widg_compound_text_r.value]['Structure'].values[0]
self.viewer_r.script(
"load data/topological_insulators/structures/" + structure_r + "_structures/"
+ self.widg_compound_text_r.value + ".xyz")
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment