<jupyter_start><jupyter_text>Table of Contents1&nbsp;&nbsp;Imports1.1&nbsp;&nbsp;Set constants1.2&nbsp;&nbsp;Load dataset2&nbsp;&nbsp;Eval trained model3&nbsp;&nbsp;Visualizing kernels3.1&nbsp;&nbsp;Load endpoints4&nbsp;&nbsp;Visualizing activations4.1&nbsp;&nbsp;Points clustering4.2&nbsp;&nbsp;Clustring of points from raw input4.3&nbsp;&nbsp;Feature vectors  Imports<jupyter_code>%load_ext autoreload
%autoreload 2
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
tf.enable_eager_execution()
tf.executing_eagerly()
import os
import plotly.express as px
import plotly.graph_objects as go
import numpy as np
import json
import pandas as pd
from glob import glob 
import matplotlib.pyplot as plt
import seaborn as sns

def plot_conf_matrix(confusion_matrix, normalize=True):
    plt.figure(figsize=(20, 19.5))  # width by height
    if normalize:
        col_norm = np.sum(confusion_matrix, axis=0)
        confusion_matrix /= col_norm[None, :]
    ax = sns.heatmap(confusion_matrix, #annot=True, annot_kws={'size': 3},
                    fmt='.1f', cbar=False, cmap='binary', linecolor='black', linewidths=0.5)
    return plt
import math
from datetime import datetime, timezone
import h5py
import numpy as np

import socket
import importlib
import os
import sys
BASE_DIR = '/scidatalg/ar/pointnet2'
ROOT_DIR = BASE_DIR
sys.path.append(BASE_DIR)
sys.path.append(os.path.join(ROOT_DIR, 'models'))
sys.path.append(os.path.join(ROOT_DIR, 'utils'))
from utils import provider
import tf_util
import pfr_dataset<jupyter_output><empty_output><jupyter_text>Set constants<jupyter_code>EPOCH_CNT = 0
MODEL = 'models.pointnet2_super'
DATASET_PATH = 'data/F184_scaled_splited53/'
NUM_CLASSES = 184
BATCH_SIZE = 32
NUM_POINT = 1024
MAX_EPOCH = 10
BASE_LEARNING_RATE = 0.001
GPU_INDEX = 1
MOMENTUM = 0.9
OPTIMIZER = 'adam'
DECAY_STEP = 200000
DECAY_RATE = 0.9
WEIGHT_DECAY = 0.001
NO_SHUFFLE_POINTS = True
WANDB = False
ADD_N_C = True
TO_CATEGORICAL_IND = [8]
TO_CATEGORICAL_SIZES = [20]
AUX_LOSS_WEIGHTS = [0.5, 0.35, 0.15]
LOG_DIR = 'logs'<jupyter_output><empty_output><jupyter_text>Load dataset<jupyter_code>import pfr_dataset


# TRAIN_DATASET = pfr_dataset.PFRDataset(
#     root=DATASET_PATH,
#     batch_size=BATCH_SIZE,
#     npoints=NUM_POINT,
#     split='train',
#     normalize=False,
#     normal_channel=True,
#     shuffle_points=not NO_SHUFFLE_POINTS,
#     add_n_c_info=ADD_N_C,
#     to_categorical_indexes=TO_CATEGORICAL_IND,
#     to_categorical_sizes=TO_CATEGORICAL_SIZES
# )
TEST_DATASET = pfr_dataset.PFRDataset(
    root=DATASET_PATH,
    batch_size=BATCH_SIZE,
    npoints=NUM_POINT,
    split='test',
    normalize=False,
    normal_channel=True,
    add_n_c_info=ADD_N_C,
    to_categorical_indexes=TO_CATEGORICAL_IND,
    to_categorical_sizes=TO_CATEGORICAL_SIZES
)

FEATURES_CHANNELS = TEST_DATASET.num_channel() - 3
LABELS = [i[0] for i in sorted(TEST_DATASET.classes.items(), key=lambda item: item[1])]

print(f'Database created with {FEATURES_CHANNELS} features channels')
a = TEST_DATASET.next_batch(augment=True)
a[0].shape<jupyter_output><empty_output><jupyter_text>Eval trained model<jupyter_code>!ls F184_1024_full/
# path to the model:
MODEL_PATH = 'F184_1024_full/418/model.ckpt'

tf.reset_default_graph()
MODEL = importlib.import_module('F184_1024_full.pointnet2_super')
is_training = False
with tf.Graph().as_default():


    with tf.device('/gpu:'+str(GPU_INDEX)):
        pointclouds_pl, labels_pl, weights = MODEL.placeholder_inputs(BATCH_SIZE, NUM_POINT, 3 + FEATURES_CHANNELS)
        is_training_pl = tf.placeholder(tf.bool, shape=())
        
        batch = tf.get_variable('batch', [],
        initializer=tf.constant_initializer(0), trainable=False)

        # simple model
        pred, pt_pred, end_points = MODEL.get_model(pointclouds_pl, is_training_pl, NUM_CLASSES,  weight_decay=WEIGHT_DECAY, knn=False)        
        MODEL.get_loss(pred, pt_pred, labels_pl, end_points, AUX_LOSS_WEIGHTS, weights)
        losses = tf.get_collection('losses')
        total_loss = tf.add_n(losses, name='total_loss')
        tf.summary.scalar('total_loss', total_loss)
        for l in losses + [total_loss]:
            tf.summary.scalar(l.op.name, l)

        # Add ops to save and restore all the variables.
        saver = tf.train.Saver()

    # Create a session
    config = tf.ConfigProto()
    config.gpu_options.allow_growth = True
    config.allow_soft_placement = True
    config.log_device_placement = False
    sess = tf.Session(config=config)

    # Restore variables from disk.
    saver.restore(sess, MODEL_PATH)

    ops = {'pointclouds_pl': pointclouds_pl,
           'labels_pl': labels_pl,
           'is_training_pl': is_training_pl,
           'pred': pred,
           'weights': weights,
           'pt_pred': pt_pred,
           'end_points': end_points,
           'loss': total_loss}

tf.enable_eager_execution()
tf.executing_eagerly()
end_points
# go.Figure(go.Heatmap(z=TEST_DATASET[0][0]))
feature_vectors = []

is_training = False

# Make sure batch data is of same size
cur_batch_data = np.zeros((BATCH_SIZE,NUM_POINT,TEST_DATASET.num_channel()))
cur_batch_label = np.zeros((BATCH_SIZE), dtype=np.int32)
cur_batch_weights = np.zeros((BATCH_SIZE), dtype=np.float32)

confusion_matrix = np.zeros((NUM_CLASSES, NUM_CLASSES))
pt_confusion_matrix = np.zeros((NUM_CLASSES, NUM_CLASSES))

loss_sum = 0
top3_correct = 0
top3_class_correct = np.zeros((NUM_CLASSES))
pt_top3_correct = 0
pt_top3_class_correct = np.zeros((NUM_CLASSES))

batch_idx = 0

print(str(datetime.now()))
print(f'---- EPOCH {EPOCH_CNT:03d} EVALUATION ----')

endpoints_list = [] 
failed = []

TEST_DATASET.reset()
while TEST_DATASET.has_next_batch():
    batch_data, batch_label, batch_cls_weights = TEST_DATASET.next_batch(augment=False)
    bsize = batch_data.shape[0]
    # for the last batch in the epoch, the bsize:end are from last batch
    cur_batch_data[0:bsize,...] = batch_data
    cur_batch_label[0:bsize] = batch_label
    cur_batch_weights[0:bsize] = batch_cls_weights    
    
    feed_dict = {ops['pointclouds_pl']: cur_batch_data,
                 ops['labels_pl']: cur_batch_label,
                 ops['weights']: classes_weights,
                 ops['is_training_pl']: is_training}

    loss_val, pred_val, pt_pred, end_points = sess.run([ops['loss'], ops['pred'], ops['pt_pred'], ops['end_points']], feed_dict=feed_dict)
    endpoints_list.append(end_points)
    pred_val_arg = np.argmax(pred_val, 1)
    loss_sum += loss_val
    batch_idx += 1
    for i in range(0, bsize):
        l = batch_label[i]
        top3 = pred_val[i].argsort()[-3:][::-1]
        failed.append(1 if l==top3[0] else 1 if l==top3[1] else 1 if l==top3[2] else 5)
        top3_correct += l in top3
        top3_class_correct[l] += l in top3
        confusion_matrix[pred_val_arg[i], l] += 1
    
    # for pointnet 
#     pred_val_arg = np.argmax(pt_pred, 1)
#     loss_sum += loss_val
#     batch_idx += 1
#     for i in range(0, bsize):
#         l = batch_label[i]
#         pt_top3 = pt_pred[i].argsort()[-3:][::-1]
# #         pt_failed.append(1 if l==top3[0] else 1 if l==top3[1] else 1 if l==top3[2] else 5)
#         pt_top3_correct += l in pt_top3
#         pt_top3_class_correct[l] += l in pt_top3
#         pt_confusion_matrix[pred_val_arg[i], l] += 1
        

col_norm = np.maximum(np.nan_to_num(np.sum(confusion_matrix, axis=0)), 1)
accuracy = np.sum(np.diag(confusion_matrix)) / np.sum(confusion_matrix)
top3_accuracy = top3_correct / np.sum(confusion_matrix)
top3_avg_class_acc = np.mean(top3_class_correct / col_norm)
class_acc = np.diag(confusion_matrix) / col_norm
avg_class_acc = np.mean(np.nan_to_num(class_acc))

# for pointnet
# col_norm = np.maximum(np.nan_to_num(np.sum(pt_confusion_matrix, axis=0)), 1)
# pt_accuracy = np.sum(np.diag(pt_confusion_matrix)) / np.sum(pt_confusion_matrix)
# pt_top3_accuracy = pt_top3_correct / np.sum(pt_confusion_matrix)
# pt_class_acc = np.diag(confusion_matrix) / col_norm


print(f'eval mean loss: {loss_sum / 50}')
print(f'eval accuracy: {accuracy}')
print(f'eval avg class acc {avg_class_acc}')
print(f'eval top3 acc {top3_accuracy}')
print(f'eval top3 avg class acc {top3_avg_class_acc}')

# print(f'\neval accuracy: {pt_accuracy}')
# print(f'eval top3 acc {pt_top3_accuracy}')


EPOCH_CNT += 1

TEST_DATASET.reset()
end_points.keys()
a = end_points['input_point_cloud'][0, :, :]
a.shape
px.scatter_3d(x=a[:, 0], y=a[:, 1], z=a[:, 2], color=np.arange(1024))
# Save end points into pickle file

SAVE_PATH = 'endpoints_EDD_1024_full.pkl'

import pickle
with open(SAVE_PATH, 'wb') as f:
    pickle.dump(endpoints_list, f)<jupyter_output><empty_output><jupyter_text>Visualizing kernels<jupyter_code>def publication_plot(fig, path):
    js = fig.to_json()
    json.dump(js, open(f'{path}.json', 'w'))
    fig.write_image(f'{path}.png')
    fig.write_image(f'{path}.jpeg')    
    fig.write_image(f'{path}.pdf')    
    fig.write_image(f'{path}.eps')<jupyter_output><empty_output><jupyter_text>Load endpoints<jupyter_code>import pickle
# f = open('exp_points_01_F184_1024_endpoints.pkl', 'rb')
f = open('end_points_eDD_512.pkl', 'rb')
input_point_cloud = [] 
extr = []
temp1_input = []
feature_vector = []

while True:
    try:
        # data for each protein
        a = pickle.load(f)
        input_point_cloud.extend(a['input_point_cloud'])
        extr.extend(a['extr'])
        temp1_input.extend(a['temp1_input'])
        feature_vector.extend(a['feature_vector'])
    except:
        break

# Filters kernels        
extr_ker = a['extr_ker']
pt_ker = a['pt_ker']
temp1_ker = a['temp1_ker']

AA_INDEX = {
    'A': 0,
    'C': 1,
    'D': 2,
    'E': 3,
    'F': 4,
    'G': 5,
    'H': 6,
    'I': 7,
    'K': 8,
    'L': 9,
    'M': 10,
    'N': 11,
    'P': 12,
    'Q': 13,
    'R': 14,
    'S': 15,
    'T': 16,
    'V': 17,
    'W': 18,
    'Y': 19
}
AA_INDEX = {v:k for k,v in AA_INDEX.items()}
def produce_sizes(kernels, which_kernel, quantile=0.85):
    q = np.quantile(kernels[:,which_kernel], q=quantile)
    return [0.9 if i > q else 0.1 for i in kernels[:, which_kernel]]
def expand_to_array(i, length):
    arr = np.zeros(length)
    arr[i] = 1
    return arr 
real_vectors = np.array([expand_to_array(TEST_DATASET[i][1][0], 184) for i in range(len(TEST_DATASET))])
# Heatmap of pointnet first kernel weights
go.Figure(go.Heatmap(z=np.squeeze(pt_ker)))\
.update_layout(
    dict(xaxis = dict(title='Filters'), 
         yaxis = dict(title='Features')
    )
)
def draw_stacked_heatmap(heatmaps, y_titles, x_title):
    fig = go.Figure()
    cum_heights = np.cumsum([i.shape[0] for i in heatmaps])
    final_heatmap = np.concatenate(heatmaps)
    fig.add_traces([go.Heatmap(z=final_heatmap)])
    
    # add tick values on y axis
    bins_ranges = [0] + list(np.cumsum([i.shape[0] for i in heatmaps]))
    bins_middle = [(bins_ranges[i] + bins_ranges[i+1])/2 for i in range(len(bins_ranges)-1)]
    fig.update_layout(
        showlegend=False,
        yaxis=dict(ticktext=y_titles, tickvals=bins_middle, title='Filter sizes'),
        xaxis_title=x_title
    )
    
    # add lines separating kernels
    [heatmaps[i].shape[1] for i in range(len(heatmaps)-1)]
    fig.add_traces([
        go.Scatter(x=[-.5, heatmaps[i].shape[1] - 0.5], y=[cum_heights[i] - 0.5] * 2,
                   mode='lines', line=dict(dash='dash', width=2, color='black'))
        for i in range(len(heatmaps)-1)
    ])
    return fig
[i.shape for i in temp1_ker]
filters_titles = [r'$1 \times 1$', r'$3 \times 1$', r'$5 \times 1$', r'$7 \times 1$']
cumulated_filters = []
for j in range(4):
    kernels = np.squeeze(extr_ker[j], axis=1)
    ker_h, ker_width, ker_num = kernels.shape
    filters = [kernels[:, :, i] for i in range(kernels.shape[-1])]
    draw_stacked_heatmap(filters, [filters_titles[j]] * ker_num, 'Channels')\
    .add_traces([go.Scatter(x=[51.5, 51.5], y=[-.5, ker_num * ker_h - .5], mode='lines', 
                            line=dict(dash='dash', width=2, color='black'))])\
    .add_traces([go.Scatter(x=[31.5, 31.5], y=[-.5, ker_num * ker_h - .5], mode='lines', 
                            line=dict(dash='dash', width=2, color='black'))])\
    .show()

fig = go.Figure(go.Heatmap(z=np.squeeze(temp1_ker[-1][:, :, 32:52, 2])))\
.update_layout(
    xaxis=dict(ticktext=sorted(AA_INDEX.values()), tickvals=np.arange(20), title='Amino acid'),
    yaxis_title='Subsequent filter\'s channels'
)
publication_plot(fig, 'images/Amino acids motifs temporal layer')
# [WVTPC]-[WVTPC]-[WVTRC]-[CTV]-[VT]-V-[GY]
for i in range(8):
    kernel = np.squeeze(extr_ker[-1][:, :, 32:52, i])
    fig = go.Figure(go.Heatmap(z=kernel))\
    .update_layout(
        xaxis=dict(ticktext=sorted(AA_INDEX.values()), tickvals=np.arange(20), title='Amino acid'),
        yaxis_title='Subsequent filter\'s channels'
    ).show()
    
    aa = ['']*7
    for n, which_aa in np.argwhere(kernel > 0.1):
        aa[n] += AA_INDEX[which_aa]
    print('-'.join([f"[{''.join(i)}]" for i in aa]))
#     publication_plot(fig, 'images/Amino acids motifs')<jupyter_output><empty_output><jupyter_text>Visualizing activations<jupyter_code>def visualize_activations(point_cloud, kernels, kernel_titles, plot_title):
#     print(point_cloud.shape)
    activations = []
    kernel_labels = []
    for i, kernel in enumerate(kernels):
#         print(kernel.shape)
        kernel_labels.extend([kernel_titles[i]] * kernel.shape[-1])
        activation = tf.squeeze(
            tf.nn.conv2d(
                point_cloud, kernel, strides=[1]*4, padding='SAME')
        ).numpy()
        activations.append(activation)

    d = dict(kernel=[], x=[], y=[], z=[], aa=[], importance=[], ss=[], dist=[], activation=[], kernel_size=[])
    point_cloud = np.squeeze(point_cloud)
    for i, kernel_group in enumerate(kernels):
        for kernel in range(kernel_group.shape[-1]):
            d['activation'].extend(activations[i][:, kernel])
            d['importance'].extend(produce_sizes(activations[i], kernel))
            d['x'].extend(point_cloud[:, 0])
            d['y'].extend(point_cloud[:, 1])
            d['z'].extend(point_cloud[:, 2])
            ss = np.zeros(point_cloud.shape[0])
            ss += point_cloud[:, 5] * 17
            ss += point_cloud[:, 6] * 21
            d['ss'].extend(ss)
            is_helix = point_cloud[:, 5]
            is_beta = point_cloud[:, 6]
            d['aa'].extend([AA_INDEX[i] for i in np.argmax(point_cloud[:, 8:28], axis=1)])
            d['kernel'].extend([kernel] * point_cloud.shape[0])
            d['kernel_size'].extend([kernel_titles[i]] * point_cloud.shape[0])
            d['dist'].extend(np.linspace(0, 1, activations[i].shape[0]))
        ss = np.zeros(shape=())
    fig = draw_stacked_heatmap([i.T for i in activations], kernel_titles, 'points')
    fig.update_layout(title=dict(text=plot_title, x=0.5))
    return activations, pd.DataFrame(d), fig

  

for i in range(50):
    
    activations, df, fig = visualize_activations(
        np.expand_dims(input_point_cloud[0], axis=(0,2)), 
        extr_ker,
        [r'$1 \times 1$', r'$3 \times 1$', r'$5 \times 1$', r'$7 \times 1$'],
        'Extractor'
    )
    fig.write_image(f'images/activations_eDD/{i}_extr.png')
    
    activations, df, fig = visualize_activations(
        np.expand_dims(temp1_input[i], axis=(0,2)), 
        temp1_ker,
        [r'$1 \times 1$', r'$3 \times 1$', r'$5 \times 1$', r'$7 \times 1$'],
        'Temporal convolution'
    )
    fig.write_image(f'images/activations_eDD/{i}_temp1.png')

    pointnet_input = np.concatenate([input_point_cloud[i], extr[i]], axis=-1)
    activations, df, fig = visualize_activations(
        np.expand_dims(pointnet_input, axis=(0,2)), 
        np.expand_dims(pt_ker, axis=0),
        [r'$1 \times 1$'],
        'PointNet'
    )
    fig.write_image(f'images/activations_eDD/{i}_pointnet.png')
#     break
    
# fig.show()
df.loc[:, 'kernel_id'] = df.kernel_size.str[:-1] + ' ' + df.kernel.astype(str) + '$'
fig = px.scatter_3d(df, x='x', y='y', z='z',
                    animation_frame='kernel_id',
                    symbol='ss', 
                    color='activation', 
                    size=df.activation - df.activation.min(),
                   )

axes_settings = dict(
#     backgroundcolor="white",
    gridcolor="rgba(127,127,127,0.5)",
#     showbackground=False,
    zerolinecolor="white",
    showticklabels=False,
    title=''
)

fig.update_layout(
    width=1000, height=1000,
    scene = dict(
        xaxis = axes_settings,
        yaxis = axes_settings,
        zaxis = axes_settings
    ),
    showlegend=False
)
activations, df, fig = visualize_activations(
    np.expand_dims(temp1_input[8], axis=(0,2)), 
    temp1_ker,
    [r'$1 \times 1$', r'$3 \times 1$', r'$5 \times 1$', r'$7 \times 1$'],
    'Temporal convolution'
)
fig.show('browser')<jupyter_output><empty_output><jupyter_text>Points clustering<jupyter_code>pointnet_input = np.concatenate([input_point_cloud[8], extr[8]], axis=-1)
activations, df, fig = visualize_activations(
    np.expand_dims(pointnet_input, axis=(0,2)), 
    [pt_ker], 
    [r'$1 \times 1$'],
    'PointNet'
)
activations, df, fig = visualize_activations(
    np.expand_dims(temp1_input[0], axis=(0, 2)), 
    temp1_ker,
    ['1x1', '3x1', '5x1', '7x1'],
    'PointNet'
)
df = df.loc[df.kernel==0]
from sklearn.cluster import AgglomerativeClustering
def cluster_points(activations, df, min_clust=2, max_clust=6):
    for i in range(min_clust, max_clust):
        clust = AgglomerativeClustering(n_clusters=i)
        clustering = clust.fit(activations)
        if i == min_clust:
            df.loc[:, 'cluster'] = list(clustering.labels_)* (len(df) // len(clustering.labels_))
            df.loc[:, 'num_clusters'] = i
        else:
            tmp = df.loc[:, df.columns != 'cluster'].copy()
            tmp.loc[:, 'cluster'] = list(clustering.labels_)* (len(df) // len(clustering.labels_))
            tmp.loc[:, 'num_clusters'] = i
            df = pd.concat([df, tmp])
    return df
def plot_clustered_points(df):
    fig = px.scatter_3d(df, x='x', y='y', z='z',
                    animation_frame='num_clusters',
                    color='cluster',
                   )

    axes_settings = dict(
    #     backgroundcolor="white",
        gridcolor="rgba(127,127,127,0.5)",
    #     showbackground=False,
        zerolinecolor="white",
        showticklabels=False,
        title=''
    )

    fig.update_layout(
        width=1000, height=1000,
        scene = dict(
            xaxis = axes_settings,
            yaxis = axes_settings,
            zaxis = axes_settings
        ),
        showlegend=False
    )
    return fig
df = cluster_points(activations[0], df, 2, 7)
plot_clustered_points(df)
publication_plot(fig, 'images/protein_parts')<jupyter_output><empty_output><jupyter_text>Clustring of points from raw input<jupyter_code>activations = TEST_DATASET[8][0]
df = pd.DataFrame(dict(x=activations[:, 0], y=activations[:, 1], z=activations[:, 2]))
df = cluster_points(activations, df)
fig = px.scatter_3d(df, x='x', y='y', z='z',
                    animation_frame='num_clusters',
                    color='cluster',
                   )

axes_settings = dict(
#     backgroundcolor="white",
    gridcolor="rgba(127,127,127,0.5)",
#     showbackground=False,
    zerolinecolor="white",
    showticklabels=False,
    title=''
)

fig.update_layout(
    width=1000, height=1000,
    scene = dict(
        xaxis = axes_settings,
        yaxis = axes_settings,
        zaxis = axes_settings
    ),
    showlegend=False
)
classes_names = TEST_DATASET.classes_names
import string
LETTERS = string.ascii_letters.upper()
## change pdb chain to show color of clusters in pymol
aa =  {'A': 'ALA', 'C': 'CYS', 'D': 'ASP', 'E': 'GLU', 'F': 'PHE', 'G': 'GLY', 'H': 'HIS', 'I': 'ILE', 'K': 'LYS', 'L': 'LEU', 'M': 'MET', 'N': 'ASN', 'P': 'PRO', 'Q': 'GLN', 'R': 'ARG', 'S': 'SER', 'T': 'THR', 'V': 'VAL', 'W': 'TRP', 'Y': 'TYR'}

def change_pdb_chain_to_cluster(path, savepath, seq, clusters):
    seq_ind = 0
    seq = [aa[i] for i in seq]
    clust = [LETTERS[i] for i in clusters]
    with open(path, 'r') as f:
        with open(savepath, 'w+') as g:
            for line in f.readlines():
                if line[:4] != 'ATOM':
                    g.write(line)
                    continue
                pdb_aa = line[17:20]
                if pdb_aa != seq[seq_ind]:
                    seq_ind+=1
                line = line[:21] + clust[seq_ind] + line[22:]
                g.write(line)

import time
from pymol import cmd
def draw_clustered_protein(path, save_path):
    cmd.load(path)
    cmd.center()
    cmd.zoom()
    cmd.select('aa', 'chain A')
    cmd.color('blue', 'aa')
    cmd.select('bb', 'chain B')
    cmd.color('red', 'bb')
    cmd.select('cc', 'chain C')
    cmd.color('green', 'cc')
    cmd.select('dd', 'chain D')
    cmd.color('yellow', 'dd')
    cmd.png(save_path)
    time.sleep(0.3)
    cmd.delete('all')

def render_fold_clusters(fold, n_clusters):
    os.makedirs(f'images/clustered_folds/{fold}', exist_ok=True)
    examples_seq = {}
    ind = [i for i in range(len(TEST_DATASET)) if TEST_DATASET.datapath[i][0] == fold]
    for example_ind in ind:
        sid = TEST_DATASET.datapath[example_ind][1].split('/')[-1][:-4]
        print(sid)
        pointnet_input = np.concatenate([input_point_cloud[example_ind], extr[example_ind]], axis=-1)
        activations, df, fig = visualize_activations(
            np.expand_dims(temp1_input[example_ind], axis=(0, 2)), 
            temp1_ker,
            ['1x1', '3x1', '5x1', '7x1'],
            'PointNet'
        )
        df = df.loc[df.kernel==0]
        df = cluster_points(activations[0], df, n_clusters, n_clusters+1)
        seq, clusters = df.loc[df.aa != df.aa.shift(), ['aa', 'cluster']].values.T
        try:
            change_pdb_chain_to_cluster(
                f'../datasets/F184_dataset/pdbs/{fold}/{sid}', 
                f'clustered_pdbs/{sid}.pdb',
                seq, clusters)
        except:
            continue
        draw_clustered_protein(f'clustered_pdbs/{sid}.pdb', f'images/clustered_folds/{fold}/{sid}.png')
render_fold_clusters('a.102', 4)<jupyter_output><empty_output><jupyter_text>Feature vectors<jupyter_code>import plotly.graph_objects as go
import pandas as pd
go.Figure(go.Heatmap(z=feature_vector))

data = TEST_DATASET.datapath

sids = [i[1].split('/')[-1][:-4] for i in data]

folds = [i[0] for i in data]

df = pd.DataFrame({'fold': folds, 'sids':sids})
df
np.save('../EDD1024_feature_vectors_for_tsne.npy', feature_vector)
df.to_csv('../EDD1024_feature_vectors_for_tsne.csv', index=False)
!ls
feature_vector[0].shape<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15305582502866213, 'fraction_numerical': 0.024208483993297468, 'mean_word_length': 3.4122568093385213, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '351189', 'license': 'MIT', 'n_tokens_mistral': 8861, 'n_tokens_neox': 8466, 'n_words': 1548, 'path': 'what_pointnet_learns.ipynb', 'repo_name': 'tryptofanik/bios2net', 'size': '22678'}