Source code for muprocdurham.ngram

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm

from pitchtypes import EnharmonicPitchClass, EnharmonicPitch


[docs] def bigram_matrix_from_model(n_gram_model, counts=False): min_val = min(n_gram_model.alphabet) max_val = max(n_gram_model.alphabet) n = max_val - min_val + 1 if counts: mat = np.zeros((n, n), dtype=int) else: mat = np.zeros((n, n)) for from_idx, from_symbol in enumerate(range(min_val, max_val + 1)): for to_idx, to_symbol in enumerate(range(min_val, max_val + 1)): if counts: mat[from_idx, to_idx] = n_gram_model.c((from_symbol, to_symbol)) else: mat[from_idx, to_idx] = n_gram_model.p((from_symbol, to_symbol)) return mat, (min_val, max_val)
[docs] def show_bigram_matrix(mat, minmax=None, show_values=False, names=False, pitch_classes=False, origin='upper', show=True, key_depth=3, black_key_depth=2): assert mat.shape[0] == mat.shape[1], f"Bigram matrix must be square, but has shape {mat.shape}" assert np.all(mat >= 0), "Values in 'mat' must be non-negative" if origin not in ['upper', 'lower']: raise ValueError(f"'origin' has to be 'upper' or 'lower' but provided value was: '{origin}'") black_key_depth = min(black_key_depth, key_depth) # get basic heatmap norm = plt.Normalize(vmin=0) img1 = cm.viridis(norm(mat)) # add piano keys if minmax is provided if minmax is None: # minmax not provided: use basic heatmap extent = np.array([0, mat.shape[0] - 1, 0, mat.shape[1] - 1]) - 0.5 value_extent = extent img2 = img1 else: # minmax IS provided: add row/column with b/w piano keys min_val, max_val = minmax img2 = np.ones((img1.shape[0] + key_depth, img1.shape[1] + key_depth, img1.shape[2]), dtype=img1.dtype) img2[key_depth:, key_depth:] = img1 idx = np.arange(img1.shape[0]) + key_depth pitch = idx + min_val black_keys = (((pitch - 5 - key_depth) % 12) * 7) % 12 > 6 img2[0:black_key_depth, idx[black_keys], 0:3] = 0 # x-axis if origin == 'upper': img2[idx[black_keys], key_depth - black_key_depth:key_depth, 0:3] = 0 # y-axis else: # 'lower' img2[idx[black_keys], 0:black_key_depth, 0:3] = 0 # y-axis value_extent = np.array([min_val, max_val + 1, min_val, max_val + 1]) - 0.5 extent = value_extent - [key_depth, 0, key_depth, 0] plt.imshow(img2, origin='lower', extent=extent) plt.gca().xaxis.set_major_locator(plt.MaxNLocator(integer=True)) plt.gca().yaxis.set_major_locator(plt.MaxNLocator(integer=True)) if origin == 'upper': plt.gca().invert_yaxis() plt.gca().xaxis.tick_top() plt.gca().xaxis.set_label_position('top') if show_values: for i, x in enumerate(np.linspace(value_extent[0] + 0.5, value_extent[1] - 0.5, mat.shape[0], endpoint=True)): for j, y in enumerate(np.linspace(value_extent[2] + 0.5, value_extent[3] - 0.5, mat.shape[1], endpoint=True)): plt.text(x, y, str(mat[j, i]), ha='center', va='center') plt.ylabel("from") plt.xlabel("to") if names: if pitch_classes: def name_func(x): return str(EnharmonicPitchClass(x)) else: def name_func(x): return str(EnharmonicPitch(x)) plt.gca().xaxis.set_major_formatter(lambda x, pos: name_func(x)) plt.gca().yaxis.set_major_formatter(lambda x, pos: name_func(x)) plt.colorbar(cm.ScalarMappable(norm=norm), ax=plt.gca()) if show: plt.show()
[docs] def show_unigram_distribution(n_gram_model, counts=False, sort=False, show=True, names=False, pitch_classes=False): k = len(n_gram_model.alphabet) p = np.zeros(k) alphabet = n_gram_model.alphabet if sort: alphabet = sorted(alphabet) for i, a in enumerate(alphabet) : if counts: p[i] = n_gram_model.c((a,)) else: p[i] = n_gram_model.p((a,)) plt.bar(np.arange(k), p) if names: if pitch_classes: alphabet = [EnharmonicPitchClass(a) for a in alphabet] else: alphabet = [EnharmonicPitch(a) for a in alphabet] plt.xticks(np.arange(k), alphabet) if show: plt.show()