asigalov61's picture
Upload 2 files
f26e052 verified
raw
history blame
39.9 kB
#! /usr/bin/python3
r'''############################################################################
################################################################################
#
#
# Tegridy Plots Python Module (TPLOTS)
# Version 1.0
#
# Project Los Angeles
#
# Tegridy Code 2024
#
# https://github.com/asigalov61/tegridy-tools
#
#
################################################################################
#
# Copyright 2024 Project Los Angeles / Tegridy Code
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
################################################################################
################################################################################
#
# Critical dependencies
#
# !pip install numpy
# !pip install scipy
# !pip install matplotlib
# !pip install networkx
# !pip3 install scikit-learn
#
################################################################################
#
# Future critical dependencies
#
# !pip install umap-learn
# !pip install alphashape
#
################################################################################
'''
################################################################################
# Modules imports
################################################################################
import os
from collections import Counter
from itertools import groupby
import numpy as np
import networkx as nx
from sklearn.manifold import TSNE
from sklearn import metrics
from sklearn.preprocessing import MinMaxScaler
from sklearn.decomposition import PCA
from scipy.ndimage import zoom
from scipy.spatial import distance_matrix
from scipy.sparse.csgraph import minimum_spanning_tree
from scipy.stats import zscore
import matplotlib.pyplot as plt
from PIL import Image
################################################################################
# Constants
################################################################################
ALL_CHORDS_FULL = [[0], [0, 3], [0, 3, 5], [0, 3, 5, 8], [0, 3, 5, 9], [0, 3, 5, 10], [0, 3, 6],
[0, 3, 6, 9], [0, 3, 6, 10], [0, 3, 7], [0, 3, 7, 10], [0, 3, 8], [0, 3, 9],
[0, 3, 10], [0, 4], [0, 4, 6], [0, 4, 6, 9], [0, 4, 6, 10], [0, 4, 7],
[0, 4, 7, 10], [0, 4, 8], [0, 4, 9], [0, 4, 10], [0, 5], [0, 5, 8], [0, 5, 9],
[0, 5, 10], [0, 6], [0, 6, 9], [0, 6, 10], [0, 7], [0, 7, 10], [0, 8], [0, 9],
[0, 10], [1], [1, 4], [1, 4, 6], [1, 4, 6, 9], [1, 4, 6, 10], [1, 4, 6, 11],
[1, 4, 7], [1, 4, 7, 10], [1, 4, 7, 11], [1, 4, 8], [1, 4, 8, 11], [1, 4, 9],
[1, 4, 10], [1, 4, 11], [1, 5], [1, 5, 8], [1, 5, 8, 11], [1, 5, 9],
[1, 5, 10], [1, 5, 11], [1, 6], [1, 6, 9], [1, 6, 10], [1, 6, 11], [1, 7],
[1, 7, 10], [1, 7, 11], [1, 8], [1, 8, 11], [1, 9], [1, 10], [1, 11], [2],
[2, 5], [2, 5, 8], [2, 5, 8, 11], [2, 5, 9], [2, 5, 10], [2, 5, 11], [2, 6],
[2, 6, 9], [2, 6, 10], [2, 6, 11], [2, 7], [2, 7, 10], [2, 7, 11], [2, 8],
[2, 8, 11], [2, 9], [2, 10], [2, 11], [3], [3, 5], [3, 5, 8], [3, 5, 8, 11],
[3, 5, 9], [3, 5, 10], [3, 5, 11], [3, 6], [3, 6, 9], [3, 6, 10], [3, 6, 11],
[3, 7], [3, 7, 10], [3, 7, 11], [3, 8], [3, 8, 11], [3, 9], [3, 10], [3, 11],
[4], [4, 6], [4, 6, 9], [4, 6, 10], [4, 6, 11], [4, 7], [4, 7, 10], [4, 7, 11],
[4, 8], [4, 8, 11], [4, 9], [4, 10], [4, 11], [5], [5, 8], [5, 8, 11], [5, 9],
[5, 10], [5, 11], [6], [6, 9], [6, 10], [6, 11], [7], [7, 10], [7, 11], [8],
[8, 11], [9], [10], [11]]
################################################################################
CHORDS_TYPES = ['WHITE', 'BLACK', 'UNKNOWN', 'MIXED WHITE', 'MIXED BLACK', 'MIXED GRAY']
################################################################################
WHITE_NOTES = [0, 2, 4, 5, 7, 9, 11]
################################################################################
BLACK_NOTES = [1, 3, 6, 8, 10]
################################################################################
# Helper functions
################################################################################
def tones_chord_type(tones_chord,
return_chord_type_index=True,
):
"""
Returns tones chord type
"""
WN = WHITE_NOTES
BN = BLACK_NOTES
MX = WHITE_NOTES + BLACK_NOTES
CHORDS = ALL_CHORDS_FULL
tones_chord = sorted(tones_chord)
ctype = 'UNKNOWN'
if tones_chord in CHORDS:
if sorted(set(tones_chord) & set(WN)) == tones_chord:
ctype = 'WHITE'
elif sorted(set(tones_chord) & set(BN)) == tones_chord:
ctype = 'BLACK'
if len(tones_chord) > 1 and sorted(set(tones_chord) & set(MX)) == tones_chord:
if len(sorted(set(tones_chord) & set(WN))) == len(sorted(set(tones_chord) & set(BN))):
ctype = 'MIXED GRAY'
elif len(sorted(set(tones_chord) & set(WN))) > len(sorted(set(tones_chord) & set(BN))):
ctype = 'MIXED WHITE'
elif len(sorted(set(tones_chord) & set(WN))) < len(sorted(set(tones_chord) & set(BN))):
ctype = 'MIXED BLACK'
if return_chord_type_index:
return CHORDS_TYPES.index(ctype)
else:
return ctype
###################################################################################
def tone_type(tone,
return_tone_type_index=True
):
"""
Returns tone type
"""
tone = tone % 12
if tone in BLACK_NOTES:
if return_tone_type_index:
return CHORDS_TYPES.index('BLACK')
else:
return "BLACK"
else:
if return_tone_type_index:
return CHORDS_TYPES.index('WHITE')
else:
return "WHITE"
###################################################################################
def find_closest_points(points, return_points=True):
"""
Find closest 2D points
"""
coords = np.array(points)
num_points = coords.shape[0]
closest_matches = np.zeros(num_points, dtype=int)
distances = np.zeros((num_points, num_points))
for i in range(num_points):
for j in range(num_points):
if i != j:
distances[i, j] = np.linalg.norm(coords[i] - coords[j])
else:
distances[i, j] = np.inf
closest_matches = np.argmin(distances, axis=1)
if return_points:
points_matches = coords[closest_matches].tolist()
return points_matches
else:
return closest_matches.tolist()
################################################################################
def reduce_dimensionality_tsne(list_of_valies,
n_comp=2,
n_iter=5000,
verbose=True
):
"""
Reduces the dimensionality of the values using t-SNE.
"""
vals = np.array(list_of_valies)
tsne = TSNE(n_components=n_comp,
n_iter=n_iter,
verbose=verbose)
reduced_vals = tsne.fit_transform(vals)
return reduced_vals.tolist()
################################################################################
def compute_mst_edges(similarity_scores_list):
"""
Computes the Minimum Spanning Tree (MST) edges based on the similarity scores.
"""
num_tokens = len(similarity_scores_list[0])
graph = nx.Graph()
for i in range(num_tokens):
for j in range(i + 1, num_tokens):
weight = 1 - similarity_scores_list[i][j]
graph.add_edge(i, j, weight=weight)
mst = nx.minimum_spanning_tree(graph)
mst_edges = list(mst.edges(data=False))
return mst_edges
################################################################################
def square_binary_matrix(binary_matrix,
matrix_size=128,
interpolation_order=5,
return_square_matrix_points=False
):
"""
Reduces an arbitrary binary matrix to a square binary matrix
"""
zoom_factors = (matrix_size / len(binary_matrix), 1)
resized_matrix = zoom(binary_matrix, zoom_factors, order=interpolation_order)
resized_matrix = (resized_matrix > 0.5).astype(int)
final_matrix = np.zeros((matrix_size, matrix_size), dtype=int)
final_matrix[:, :resized_matrix.shape[1]] = resized_matrix
points = np.column_stack(np.where(final_matrix == 1)).tolist()
if return_square_matrix_points:
return points
else:
return resized_matrix
################################################################################
def square_matrix_points_colors(square_matrix_points):
"""
Returns colors for square matrix points
"""
cmap = generate_colors(12)
chords = []
chords_dict = set()
counts = []
for k, v in groupby(square_matrix_points, key=lambda x: x[0]):
pgroup = [vv[1] for vv in v]
chord = sorted(set(pgroup))
tchord = sorted(set([p % 12 for p in chord]))
chords_dict.add(tuple(tchord))
chords.append(tuple(tchord))
counts.append(len(pgroup))
chords_dict = sorted(chords_dict)
colors = []
for i, c in enumerate(chords):
colors.extend([cmap[round(sum(c) / len(c))]] * counts[i])
return colors
################################################################################
def hsv_to_rgb(h, s, v):
if s == 0.0:
return v, v, v
i = int(h*6.0)
f = (h*6.0) - i
p = v*(1.0 - s)
q = v*(1.0 - s*f)
t = v*(1.0 - s*(1.0-f))
i = i%6
return [(v, t, p), (q, v, p), (p, v, t), (p, q, v), (t, p, v), (v, p, q)][i]
################################################################################
def generate_colors(n):
return [hsv_to_rgb(i/n, 1, 1) for i in range(n)]
################################################################################
def add_arrays(a, b):
return [sum(pair) for pair in zip(a, b)]
################################################################################
def calculate_similarities(lists_of_values, metric='cosine'):
return metrics.pairwise_distances(lists_of_values, metric=metric).tolist()
################################################################################
def get_tokens_embeddings(x_transformer_model):
return x_transformer_model.net.token_emb.emb.weight.detach().cpu().tolist()
################################################################################
def minkowski_distance_matrix(X, p=3):
X = np.array(X)
n = X.shape[0]
dist_matrix = np.zeros((n, n))
for i in range(n):
for j in range(n):
dist_matrix[i, j] = np.sum(np.abs(X[i] - X[j])**p)**(1/p)
return dist_matrix.tolist()
################################################################################
def robust_normalize(values):
values = np.array(values)
q1 = np.percentile(values, 25)
q3 = np.percentile(values, 75)
iqr = q3 - q1
filtered_values = values[(values >= q1 - 1.5 * iqr) & (values <= q3 + 1.5 * iqr)]
min_val = np.min(filtered_values)
max_val = np.max(filtered_values)
normalized_values = (values - min_val) / (max_val - min_val)
normalized_values = np.clip(normalized_values, 0, 1)
return normalized_values.tolist()
################################################################################
def min_max_normalize(values):
scaler = MinMaxScaler()
return scaler.fit_transform(values).tolist()
################################################################################
def remove_points_outliers(points, z_score_threshold=3):
points = np.array(points)
z_scores = np.abs(zscore(points, axis=0))
return points[(z_scores < z_score_threshold).all(axis=1)].tolist()
################################################################################
def generate_labels(lists_of_values,
return_indices_labels=False
):
ordered_indices = list(range(len(lists_of_values)))
ordered_indices_labels = [str(i) for i in ordered_indices]
ordered_values_labels = [str(lists_of_values[i]) for i in ordered_indices]
if return_indices_labels:
return ordered_indices_labels
else:
return ordered_values_labels
################################################################################
def reduce_dimensionality_pca(list_of_values, n_components=2):
"""
Reduces the dimensionality of the values using PCA.
"""
pca = PCA(n_components=n_components)
pca_data = pca.fit_transform(list_of_values)
return pca_data.tolist()
def reduce_dimensionality_simple(list_of_values,
return_means=True,
return_std_devs=True,
return_medians=False,
return_vars=False
):
'''
Reduces dimensionality of the values in a simple way
'''
array = np.array(list_of_values)
results = []
if return_means:
means = np.mean(array, axis=1)
results.append(means)
if return_std_devs:
std_devs = np.std(array, axis=1)
results.append(std_devs)
if return_medians:
medians = np.median(array, axis=1)
results.append(medians)
if return_vars:
vars = np.var(array, axis=1)
results.append(vars)
merged_results = np.column_stack(results)
return merged_results.tolist()
################################################################################
def reduce_dimensionality_2d_distance(list_of_values, p=5):
'''
Reduces the dimensionality of the values using 2d distance
'''
values = np.array(list_of_values)
dist_matrix = distance_matrix(values, values, p=p)
mst = minimum_spanning_tree(dist_matrix).toarray()
points = []
for i in range(len(values)):
for j in range(len(values)):
if mst[i, j] > 0:
points.append([i, j])
return points
################################################################################
def normalize_to_range(values, n):
min_val = min(values)
max_val = max(values)
range_val = max_val - min_val
normalized_values = [((value - min_val) / range_val * 2 * n) - n for value in values]
return normalized_values
################################################################################
def reduce_dimensionality_simple_pca(list_of_values, n_components=2):
'''
Reduces the dimensionality of the values using simple PCA
'''
reduced_values = []
for l in list_of_values:
norm_values = [round(v * len(l)) for v in normalize_to_range(l, (n_components+1) // 2)]
pca_values = Counter(norm_values).most_common()
pca_values = [vv[0] / len(l) for vv in pca_values]
pca_values = pca_values[:n_components]
pca_values = pca_values + [0] * (n_components - len(pca_values))
reduced_values.append(pca_values)
return reduced_values
################################################################################
def filter_and_replace_values(list_of_values,
threshold,
replace_value,
replace_above_threshold=False
):
array = np.array(list_of_values)
modified_array = np.copy(array)
if replace_above_threshold:
modified_array[modified_array > threshold] = replace_value
else:
modified_array[modified_array < threshold] = replace_value
return modified_array.tolist()
################################################################################
def find_shortest_constellation_path(points,
start_point_idx,
end_point_idx,
p=5,
return_path_length=False,
return_path_points=False,
):
"""
Finds the shortest path between two points of the points constellation
"""
points = np.array(points)
dist_matrix = distance_matrix(points, points, p=p)
mst = minimum_spanning_tree(dist_matrix).toarray()
G = nx.Graph()
for i in range(len(points)):
for j in range(len(points)):
if mst[i, j] > 0:
G.add_edge(i, j, weight=mst[i, j])
path = nx.shortest_path(G,
source=start_point_idx,
target=end_point_idx,
weight='weight'
)
path_length = nx.shortest_path_length(G,
source=start_point_idx,
target=end_point_idx,
weight='weight')
path_points = points[np.array(path)].tolist()
if return_path_points:
return path_points
if return_path_length:
return path_length
return path
################################################################################
# Core functions
################################################################################
def plot_ms_SONG(ms_song,
preview_length_in_notes=0,
block_lines_times_list = None,
plot_title='ms Song',
max_num_colors=129,
drums_color_num=128,
plot_size=(11,4),
note_height = 0.75,
show_grid_lines=False,
return_plt = False,
timings_multiplier=1,
save_plt='',
save_only_plt_image=True,
save_transparent=False
):
'''ms SONG plot'''
notes = [s for s in ms_song if s[0] == 'note']
if (len(max(notes, key=len)) != 7) and (len(min(notes, key=len)) != 7):
print('The song notes do not have patches information')
print('Ploease add patches to the notes in the song')
else:
start_times = [(s[1] * timings_multiplier) / 1000 for s in notes]
durations = [(s[2] * timings_multiplier) / 1000 for s in notes]
pitches = [s[4] for s in notes]
patches = [s[6] for s in notes]
colors = generate_colors(max_num_colors)
colors[drums_color_num] = (1, 1, 1)
pbl = (notes[preview_length_in_notes][1] * timings_multiplier) / 1000
fig, ax = plt.subplots(figsize=plot_size)
for start, duration, pitch, patch in zip(start_times, durations, pitches, patches):
rect = plt.Rectangle((start, pitch), duration, note_height, facecolor=colors[patch])
ax.add_patch(rect)
ax.set_xlim([min(start_times), max(add_arrays(start_times, durations))])
ax.set_ylim([min(pitches)-1, max(pitches)+1])
ax.set_facecolor('black')
fig.patch.set_facecolor('white')
if preview_length_in_notes > 0:
ax.axvline(x=pbl, c='white')
if block_lines_times_list:
for bl in block_lines_times_list:
ax.axvline(x=bl, c='white')
if show_grid_lines:
ax.grid(color='white')
plt.xlabel('Time (s)', c='black')
plt.ylabel('MIDI Pitch', c='black')
plt.title(plot_title)
if save_plt != '':
if save_only_plt_image:
plt.axis('off')
plt.title('')
plt.savefig(save_plt,
transparent=save_transparent,
bbox_inches='tight',
pad_inches=0,
facecolor='black'
)
plt.close()
else:
plt.savefig(save_plt)
plt.close()
if return_plt:
return fig
plt.show()
plt.close()
################################################################################
def plot_square_matrix_points(list_of_points,
list_of_points_colors,
plot_size=(7, 7),
point_size = 10,
show_grid_lines=False,
plot_title = 'Square Matrix Points Plot',
return_plt=False,
save_plt='',
save_only_plt_image=True,
save_transparent=False
):
'''Square matrix points plot'''
fig, ax = plt.subplots(figsize=plot_size)
ax.set_facecolor('black')
if show_grid_lines:
ax.grid(color='white')
plt.xlabel('Time Step', c='black')
plt.ylabel('MIDI Pitch', c='black')
plt.title(plot_title)
plt.scatter([p[0] for p in list_of_points],
[p[1] for p in list_of_points],
c=list_of_points_colors,
s=point_size
)
if save_plt != '':
if save_only_plt_image:
plt.axis('off')
plt.title('')
plt.savefig(save_plt,
transparent=save_transparent,
bbox_inches='tight',
pad_inches=0,
facecolor='black'
)
plt.close()
else:
plt.savefig(save_plt)
plt.close()
if return_plt:
return fig
plt.show()
plt.close()
################################################################################
def plot_cosine_similarities(lists_of_values,
plot_size=(7, 7),
save_plot=''
):
"""
Cosine similarities plot
"""
cos_sim = metrics.pairwise_distances(lists_of_values, metric='cosine')
plt.figure(figsize=plot_size)
plt.imshow(cos_sim, cmap="inferno", interpolation="nearest")
im_ratio = cos_sim.shape[0] / cos_sim.shape[1]
plt.colorbar(fraction=0.046 * im_ratio, pad=0.04)
plt.xlabel("Index")
plt.ylabel("Index")
plt.tight_layout()
if save_plot != '':
plt.savefig(save_plot, bbox_inches="tight")
plt.close()
plt.show()
plt.close()
################################################################################
def plot_points_with_mst_lines(points,
points_labels,
points_mst_edges,
plot_size=(20, 20),
labels_size=24,
save_plot=''
):
"""
Plots 2D points with labels and MST lines.
"""
plt.figure(figsize=plot_size)
for i, label in enumerate(points_labels):
plt.scatter(points[i][0], points[i][1])
plt.annotate(label, (points[i][0], points[i][1]), fontsize=labels_size)
for edge in points_mst_edges:
i, j = edge
plt.plot([points[i][0], points[j][0]], [points[i][1], points[j][1]], 'k-', alpha=0.5)
plt.title('Points Map with MST Lines', fontsize=labels_size)
plt.xlabel('X-axis', fontsize=labels_size)
plt.ylabel('Y-axis', fontsize=labels_size)
if save_plot != '':
plt.savefig(save_plot, bbox_inches="tight")
plt.close()
plt.show()
plt.close()
################################################################################
def plot_points_constellation(points,
points_labels,
p=5,
plot_size=(15, 15),
labels_size=12,
show_grid=False,
save_plot=''
):
"""
Plots 2D points constellation
"""
points = np.array(points)
dist_matrix = distance_matrix(points, points, p=p)
mst = minimum_spanning_tree(dist_matrix).toarray()
plt.figure(figsize=plot_size)
plt.scatter(points[:, 0], points[:, 1], color='blue')
for i, label in enumerate(points_labels):
plt.annotate(label, (points[i, 0], points[i, 1]),
textcoords="offset points",
xytext=(0, 10),
ha='center',
fontsize=labels_size
)
for i in range(len(points)):
for j in range(len(points)):
if mst[i, j] > 0:
plt.plot([points[i, 0], points[j, 0]], [points[i, 1], points[j, 1]], 'k--')
plt.xlabel('X-axis', fontsize=labels_size)
plt.ylabel('Y-axis', fontsize=labels_size)
plt.title('2D Coordinates with Minimum Spanning Tree', fontsize=labels_size)
plt.grid(show_grid)
if save_plot != '':
plt.savefig(save_plot, bbox_inches="tight")
plt.close()
plt.show()
plt.close()
################################################################################
def binary_matrix_to_images(matrix,
step,
overlap,
output_folder='./Dataset/',
output_img_prefix='image',
output_img_ext='.png',
save_to_array=False,
verbose=True
):
if not save_to_array:
if verbose:
print('=' * 70)
print('Checking output folder dir...')
os.makedirs(os.path.dirname(output_folder), exist_ok=True)
if verbose:
print('Done!')
if verbose:
print('=' * 70)
print('Writing images...')
matrix = np.array(matrix, dtype=np.uint8)
image_array = []
for i in range(0, max(1, matrix.shape[0]), overlap):
submatrix = matrix[i:i+step, :]
if submatrix.shape[0] < 128:
zeros_array = np.zeros((128-submatrix.shape[0], 128))
submatrix = np.vstack((submatrix, zeros_array))
img = Image.fromarray(submatrix * 255).convert('1')
if save_to_array:
image_array.append(np.array(img))
else:
img.save(output_folder + output_img_prefix + '_' + str(matrix.shape[1]) + '_' + str(i).zfill(7) + output_img_ext)
if verbose:
print('Done!')
print('=' * 70)
print('Saved', (matrix.shape[0] // min(step, overlap))+1, 'imges!')
print('=' * 70)
if save_to_array:
return np.array(image_array).tolist()
################################################################################
def images_to_binary_matrix(list_of_images):
image_array = np.array(list_of_images)
original_matrix = []
for img in image_array:
submatrix = np.array(img)
original_matrix.extend(submatrix.tolist())
return original_matrix
################################################################################
def square_image_matrix(image_matrix,
matrix_size=128,
num_pca_components=5,
filter_out_zero_rows=False,
return_square_matrix_points=False
):
"""
Reduces an arbitrary image matrix to a square image matrix
"""
matrix = np.array(image_matrix)
if filter_out_zero_rows:
matrix = matrix[~np.all(matrix == 0, axis=1)]
target_rows = matrix_size
rows_per_group = matrix.shape[0] // target_rows
compressed_matrix = np.zeros((target_rows, matrix.shape[1]), dtype=np.int32)
for i in range(target_rows):
start_row = i * rows_per_group
end_row = (i + 1) * rows_per_group
group = matrix[start_row:end_row, :]
pca = PCA(n_components=num_pca_components)
pca.fit(group)
principal_component = np.mean(pca.components_, axis=0)
contributions = np.dot(group, principal_component)
selected_row_index = np.argmax(contributions)
compressed_matrix[i, :] = group[selected_row_index, :]
if return_square_matrix_points:
filtered_matrix = compressed_matrix[~np.all(compressed_matrix == 0, axis=1)]
row_indexes, col_indexes = np.where(filtered_matrix != 0)
points = np.column_stack((row_indexes, filtered_matrix[row_indexes, col_indexes])).tolist()
return points
else:
return compressed_matrix.tolist()
################################################################################
def image_matrix_to_images(image_matrix,
step,
overlap,
num_img_channels=3,
output_folder='./Dataset/',
output_img_prefix='image',
output_img_ext='.png',
save_to_array=False,
verbose=True
):
if num_img_channels > 1:
n_mat_channels = 3
else:
n_mat_channels = 1
if not save_to_array:
if verbose:
print('=' * 70)
print('Checking output folder dir...')
os.makedirs(os.path.dirname(output_folder), exist_ok=True)
if verbose:
print('Done!')
if verbose:
print('=' * 70)
print('Writing images...')
matrix = np.array(image_matrix)
image_array = []
for i in range(0, max(1, matrix.shape[0]), overlap):
submatrix = matrix[i:i+step, :]
if submatrix.shape[0] < 128:
zeros_array = np.zeros((128-submatrix.shape[0], 128))
submatrix = np.vstack((submatrix, zeros_array))
if n_mat_channels == 3:
r = (submatrix // (256*256)) % 256
g = (submatrix // 256) % 256
b = submatrix % 256
rgb_image = np.stack((r, g, b), axis=-1).astype(np.uint8)
img = Image.fromarray(rgb_image, 'RGB')
else:
grayscale_image = submatrix.astype(np.uint8)
img = Image.fromarray(grayscale_image, 'L')
if save_to_array:
image_array.append(np.array(img))
else:
img.save(output_folder + output_img_prefix + '_' + str(matrix.shape[1]) + '_' + str(i).zfill(7) + output_img_ext)
if verbose:
print('Done!')
print('=' * 70)
print('Saved', (matrix.shape[0] // min(step, overlap))+1, 'imges!')
print('=' * 70)
if save_to_array:
return np.array(image_array).tolist()
################################################################################
def images_to_image_matrix(list_of_images,
num_img_channels=3
):
if num_img_channels > 1:
n_mat_channels = 3
else:
n_mat_channels = 1
image_array = np.array(list_of_images)
original_matrix = []
for img in image_array:
if num_img_channels == 3:
rgb_array = np.array(img)
matrix = (rgb_array[..., 0].astype(np.int64) * 256*256 +
rgb_array[..., 1].astype(np.int64) * 256 +
rgb_array[..., 2].astype(np.int64))
else:
matrix = np.array(img)
original_matrix.extend(matrix)
return original_matrix
################################################################################
def square_matrix_to_RGB_matrix(square_matrix):
smatrix = np.array(square_matrix)
sq_matrix = smatrix[:smatrix.shape[1]]
r = (sq_matrix // (256 ** 2)) % 256
g = (sq_matrix // 256) % 256
b = sq_matrix % 256
rgb_array = np.stack((r, g, b), axis=-1)
return rgb_array.tolist()
################################################################################
def upsample_square_matrix(square_matrix, upsampling_factor=4):
smatrix = np.array(square_matrix)
sq_matrix = smatrix[:smatrix.shape[1]]
scaling_array = np.ones((upsampling_factor, upsampling_factor))
scaled_array = np.kron(sq_matrix, scaling_array)
scaled_array = scaled_array.astype('int')
return scaled_array.tolist()
################################################################################
def downsample_square_matrix(square_matrix, downsampling_factor=4):
smatrix = np.array(square_matrix)
sq_matrix = smatrix[:smatrix.shape[1]]
dmatrix = sq_matrix[::downsampling_factor, ::downsampling_factor]
dmatrix = dmatrix.astype('int')
return dmatrix.tolist()
################################################################################
def plot_parsons_code(parsons_code,
start_pitch=60,
return_plot_dict=False,
return_plot_string=False,
plot_size=(10, 10),
labels_size=16,
save_plot=''
):
'''
Plot parsons code string
'''
if parsons_code[0] != "*":
return None
contour_dict = {}
pitch = 0
index = 0
maxp = 0
minp = 0
contour_dict[(pitch, index)] = "*"
for point in parsons_code:
if point == "R":
index += 1
contour_dict[(pitch, index)] = "-"
index += 1
contour_dict[(pitch, index)] = "*"
elif point == "U":
index += 1
pitch -= 1
contour_dict[(pitch, index)] = "/"
index += 1
pitch -= 1
contour_dict[(pitch, index)] = "*"
if pitch < maxp:
maxp = pitch
elif point == "D":
index += 1
pitch += 1
contour_dict[(pitch, index)] = "\\"
index += 1
pitch += 1
contour_dict[(pitch, index)] = "*"
if pitch > minp:
minp = pitch
if return_plot_dict:
return contour_dict
if return_plot_string:
plot_string = ''
for pitch in range(maxp, minp+1):
line = [" " for _ in range(index + 1)]
for pos in range(index + 1):
if (pitch, pos) in contour_dict:
line[pos] = contour_dict[(pitch, pos)]
plot_string = "".join(line)
return plot_string
labels = []
pitches = []
positions = []
cur_pitch = start_pitch
pitch_idx = 0
for k, v in contour_dict.items():
if v != '*':
pitches.append(cur_pitch)
positions.append(pitch_idx)
if v == '/':
cur_pitch += 1
labels.append('U')
elif v == '\\':
cur_pitch -= 1
labels.append('D')
elif v == '-':
labels.append('R')
pitch_idx += 1
plt.figure(figsize=plot_size)
plt.plot(pitches)
for i, point in enumerate(zip(positions, pitches)):
plt.annotate(labels[i], point, fontsize=labels_size)
plt.title('Parsons Code with Labels', fontsize=labels_size)
plt.xlabel('Position', fontsize=labels_size)
plt.ylabel('Pitch', fontsize=labels_size)
if save_plot != '':
plt.savefig(save_plot, bbox_inches="tight")
plt.close()
plt.show()
plt.close()
################################################################################
# [WIP] Future dev functions
################################################################################
'''
import umap
def reduce_dimensionality_umap(list_of_values,
n_comp=2,
n_neighbors=15,
):
"""
Reduces the dimensionality of the values using UMAP.
"""
vals = np.array(list_of_values)
umap_reducer = umap.UMAP(n_components=n_comp,
n_neighbors=n_neighbors,
n_epochs=5000,
verbose=True
)
reduced_vals = umap_reducer.fit_transform(vals)
return reduced_vals.tolist()
'''
################################################################################
'''
import alphashape
from shapely.geometry import Point
from matplotlib.tri import Triangulation, LinearTriInterpolator
from scipy.stats import zscore
#===============================================================================
coordinates = points
dist_matrix = minkowski_distance_matrix(coordinates, p=3) # You can change the value of p as needed
# Centering matrix
n = dist_matrix.shape[0]
H = np.eye(n) - np.ones((n, n)) / n
# Apply double centering
B = -0.5 * H @ dist_matrix**2 @ H
# Eigen decomposition
eigvals, eigvecs = np.linalg.eigh(B)
# Sort eigenvalues and eigenvectors
idx = np.argsort(eigvals)[::-1]
eigvals = eigvals[idx]
eigvecs = eigvecs[:, idx]
# Select the top 2 eigenvectors
X_transformed = eigvecs[:, :2] * np.sqrt(eigvals[:2])
#===============================================================================
src_points = X_transformed
src_values = np.array([[p[1]] for p in points]) #np.random.rand(X_transformed.shape[0])
#===============================================================================
# Normalize the points to the range [0, 1]
scaler = MinMaxScaler()
points_normalized = scaler.fit_transform(src_points)
values_normalized = custom_normalize(src_values)
# Remove outliers based on z-score
z_scores = np.abs(zscore(points_normalized, axis=0))
filtered_points = points_normalized[(z_scores < 3).all(axis=1)]
filtered_values = values_normalized[(z_scores < 3).all(axis=1)]
# Compute the concave hull (alpha shape)
alpha = 8 # Adjust alpha as needed
hull = alphashape.alphashape(filtered_points, alpha)
# Create a triangulation
tri = Triangulation(filtered_points[:, 0], filtered_points[:, 1])
# Interpolate the values on the triangulation
interpolator = LinearTriInterpolator(tri, filtered_values[:, 0])
xi, yi = np.meshgrid(np.linspace(0, 1, 100), np.linspace(0, 1, 100))
zi = interpolator(xi, yi)
# Mask out points outside the concave hull
mask = np.array([hull.contains(Point(x, y)) for x, y in zip(xi.flatten(), yi.flatten())])
zi = np.ma.array(zi, mask=~mask.reshape(zi.shape))
# Plot the filled contour based on the interpolated values
plt.contourf(xi, yi, zi, levels=50, cmap='viridis')
# Plot the original points
#plt.scatter(filtered_points[:, 0], filtered_points[:, 1], c=filtered_values, edgecolors='k')
plt.title('Filled Contour Plot with Original Values')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.colorbar(label='Value')
plt.show()
'''
################################################################################
#
# This is the end of TPLOTS Python modules
#
################################################################################