Upload 2 files
Browse files
TMIDIX.py
CHANGED
@@ -8,7 +8,7 @@ r'''############################################################################
|
|
8 |
# Tegridy MIDI X Module (TMIDI X / tee-midi eks)
|
9 |
# Version 1.0
|
10 |
#
|
11 |
-
# NOTE: TMIDI X Module starts after the partial MIDI.py module @ line
|
12 |
#
|
13 |
# Based upon MIDI.py module v.6.7. by Peter Billam / pjb.com.au
|
14 |
#
|
@@ -21,19 +21,19 @@ r'''############################################################################
|
|
21 |
#
|
22 |
###################################################################################
|
23 |
###################################################################################
|
24 |
-
#
|
25 |
#
|
26 |
-
#
|
27 |
-
#
|
28 |
-
#
|
29 |
#
|
30 |
-
#
|
31 |
#
|
32 |
-
#
|
33 |
-
#
|
34 |
-
#
|
35 |
-
#
|
36 |
-
#
|
37 |
###################################################################################
|
38 |
###################################################################################
|
39 |
#
|
@@ -1446,8 +1446,9 @@ def _encode(events_lol, unknown_callback=None, never_add_eot=False,
|
|
1446 |
# pjb.com.au
|
1447 |
#
|
1448 |
# Project Los Angeles
|
1449 |
-
# Tegridy Code
|
1450 |
-
#
|
|
|
1451 |
#
|
1452 |
###################################################################################
|
1453 |
###################################################################################
|
@@ -1490,6 +1491,10 @@ import math
|
|
1490 |
|
1491 |
import matplotlib.pyplot as plt
|
1492 |
|
|
|
|
|
|
|
|
|
1493 |
###################################################################################
|
1494 |
#
|
1495 |
# Original TMIDI Tegridy helper functions
|
@@ -11182,7 +11187,182 @@ def rle_decode_ones(encoding, size=(128, 128)):
|
|
11182 |
return matrix
|
11183 |
|
11184 |
###################################################################################
|
11185 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11186 |
# This is the end of the TMIDI X Python module
|
11187 |
-
#
|
11188 |
###################################################################################
|
|
|
8 |
# Tegridy MIDI X Module (TMIDI X / tee-midi eks)
|
9 |
# Version 1.0
|
10 |
#
|
11 |
+
# NOTE: TMIDI X Module starts after the partial MIDI.py module @ line 1438
|
12 |
#
|
13 |
# Based upon MIDI.py module v.6.7. by Peter Billam / pjb.com.au
|
14 |
#
|
|
|
21 |
#
|
22 |
###################################################################################
|
23 |
###################################################################################
|
24 |
+
# Copyright 2025 Project Los Angeles / Tegridy Code
|
25 |
#
|
26 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
27 |
+
# you may not use this file except in compliance with the License.
|
28 |
+
# You may obtain a copy of the License at
|
29 |
#
|
30 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
31 |
#
|
32 |
+
# Unless required by applicable law or agreed to in writing, software
|
33 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
34 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
35 |
+
# See the License for the specific language governing permissions and
|
36 |
+
# limitations under the License.
|
37 |
###################################################################################
|
38 |
###################################################################################
|
39 |
#
|
|
|
1446 |
# pjb.com.au
|
1447 |
#
|
1448 |
# Project Los Angeles
|
1449 |
+
# Tegridy Code 2025
|
1450 |
+
#
|
1451 |
+
# https://github.com/Tegridy-Code/Project-Los-Angeles
|
1452 |
#
|
1453 |
###################################################################################
|
1454 |
###################################################################################
|
|
|
1491 |
|
1492 |
import matplotlib.pyplot as plt
|
1493 |
|
1494 |
+
import psutil
|
1495 |
+
|
1496 |
+
from collections import defaultdict
|
1497 |
+
|
1498 |
###################################################################################
|
1499 |
#
|
1500 |
# Original TMIDI Tegridy helper functions
|
|
|
11187 |
return matrix
|
11188 |
|
11189 |
###################################################################################
|
11190 |
+
|
11191 |
+
def vertical_list_search(list_of_lists, trg_list):
|
11192 |
+
|
11193 |
+
src_list = list_of_lists
|
11194 |
+
|
11195 |
+
if not src_list or not trg_list:
|
11196 |
+
return []
|
11197 |
+
|
11198 |
+
num_rows = len(src_list)
|
11199 |
+
k = len(trg_list)
|
11200 |
+
|
11201 |
+
row_sets = [set(row) for row in src_list]
|
11202 |
+
|
11203 |
+
results = []
|
11204 |
+
|
11205 |
+
for start in range(num_rows - k + 1):
|
11206 |
+
valid = True
|
11207 |
+
|
11208 |
+
for offset, target in enumerate(trg_list):
|
11209 |
+
|
11210 |
+
if target not in row_sets[start + offset]:
|
11211 |
+
valid = False
|
11212 |
+
break
|
11213 |
+
|
11214 |
+
if valid:
|
11215 |
+
results.append(list(range(start, start + k)))
|
11216 |
+
|
11217 |
+
return results
|
11218 |
+
|
11219 |
+
###################################################################################
|
11220 |
+
|
11221 |
+
def smooth_values(values, window_size=3):
|
11222 |
+
|
11223 |
+
smoothed = []
|
11224 |
+
|
11225 |
+
for i in range(len(values)):
|
11226 |
+
|
11227 |
+
start = max(0, i - window_size // 2)
|
11228 |
+
end = min(len(values), i + window_size // 2 + 1)
|
11229 |
+
|
11230 |
+
window = values[start:end]
|
11231 |
+
|
11232 |
+
smoothed.append(int(sum(window) / len(window)))
|
11233 |
+
|
11234 |
+
return smoothed
|
11235 |
+
|
11236 |
+
###################################################################################
|
11237 |
+
|
11238 |
+
def is_mostly_wide_peaks_and_valleys(values,
|
11239 |
+
min_range=32,
|
11240 |
+
threshold=0.7,
|
11241 |
+
smoothing_window=5
|
11242 |
+
):
|
11243 |
+
|
11244 |
+
if not values:
|
11245 |
+
return False
|
11246 |
+
|
11247 |
+
smoothed_values = smooth_values(values, smoothing_window)
|
11248 |
+
|
11249 |
+
value_range = max(smoothed_values) - min(smoothed_values)
|
11250 |
+
|
11251 |
+
if value_range < min_range:
|
11252 |
+
return False
|
11253 |
+
|
11254 |
+
if all(v == smoothed_values[0] for v in smoothed_values):
|
11255 |
+
return False
|
11256 |
+
|
11257 |
+
trend_types = []
|
11258 |
+
|
11259 |
+
for i in range(1, len(smoothed_values)):
|
11260 |
+
if smoothed_values[i] > smoothed_values[i - 1]:
|
11261 |
+
trend_types.append(1)
|
11262 |
+
|
11263 |
+
elif smoothed_values[i] < smoothed_values[i - 1]:
|
11264 |
+
trend_types.append(-1)
|
11265 |
+
|
11266 |
+
else:
|
11267 |
+
trend_types.append(0)
|
11268 |
+
|
11269 |
+
trend_count = trend_types.count(1) + trend_types.count(-1)
|
11270 |
+
|
11271 |
+
proportion = trend_count / len(trend_types)
|
11272 |
+
|
11273 |
+
return proportion >= threshold
|
11274 |
+
|
11275 |
+
###################################################################################
|
11276 |
+
|
11277 |
+
def system_memory_utilization(return_dict=False):
|
11278 |
+
|
11279 |
+
if return_dict:
|
11280 |
+
return dict(psutil.virtual_memory()._asdict())
|
11281 |
+
|
11282 |
+
else:
|
11283 |
+
print('RAM memory % used:', psutil.virtual_memory()[2])
|
11284 |
+
print('RAM Used (GB):', psutil.virtual_memory()[3]/(1024**3))
|
11285 |
+
|
11286 |
+
###################################################################################
|
11287 |
+
|
11288 |
+
def create_files_list(datasets_paths=['./'],
|
11289 |
+
files_exts=['.mid', '.midi', '.kar', '.MID', '.MIDI', '.KAR'],
|
11290 |
+
randomize_files_list=True,
|
11291 |
+
verbose=True
|
11292 |
+
):
|
11293 |
+
if verbose:
|
11294 |
+
print('=' * 70)
|
11295 |
+
print('Searching for files...')
|
11296 |
+
print('This may take a while on a large dataset in particular...')
|
11297 |
+
print('=' * 70)
|
11298 |
+
|
11299 |
+
filez_set = defaultdict(None)
|
11300 |
+
|
11301 |
+
files_exts = tuple(files_exts)
|
11302 |
+
|
11303 |
+
for dataset_addr in tqdm.tqdm(datasets_paths):
|
11304 |
+
for dirpath, dirnames, filenames in os.walk(dataset_addr):
|
11305 |
+
for file in filenames:
|
11306 |
+
if file not in filez_set and file.endswith(files_exts):
|
11307 |
+
filez_set[os.path.join(dirpath, file)] = None
|
11308 |
+
|
11309 |
+
filez = list(filez_set.keys())
|
11310 |
+
|
11311 |
+
if verbose:
|
11312 |
+
print('Done!')
|
11313 |
+
print('=' * 70)
|
11314 |
+
|
11315 |
+
if filez:
|
11316 |
+
if randomize_files_list:
|
11317 |
+
|
11318 |
+
if verbose:
|
11319 |
+
print('Randomizing file list...')
|
11320 |
+
|
11321 |
+
random.shuffle(filez)
|
11322 |
+
|
11323 |
+
if verbose:
|
11324 |
+
print('Done!')
|
11325 |
+
print('=' * 70)
|
11326 |
+
|
11327 |
+
if verbose:
|
11328 |
+
print('Found', len(filez), 'files.')
|
11329 |
+
print('=' * 70)
|
11330 |
+
|
11331 |
+
else:
|
11332 |
+
if verbose:
|
11333 |
+
print('Could not find any files...')
|
11334 |
+
print('Please check dataset dirs and files extensions...')
|
11335 |
+
print('=' * 70)
|
11336 |
+
|
11337 |
+
return filez
|
11338 |
+
|
11339 |
+
###################################################################################
|
11340 |
+
|
11341 |
+
def has_consecutive_trend(nums, count):
|
11342 |
+
|
11343 |
+
if len(nums) < count:
|
11344 |
+
return False
|
11345 |
+
|
11346 |
+
increasing_streak = 1
|
11347 |
+
decreasing_streak = 1
|
11348 |
+
|
11349 |
+
for i in range(1, len(nums)):
|
11350 |
+
if nums[i] > nums[i - 1]:
|
11351 |
+
increasing_streak += 1
|
11352 |
+
decreasing_streak = 1
|
11353 |
+
|
11354 |
+
elif nums[i] < nums[i - 1]:
|
11355 |
+
decreasing_streak += 1
|
11356 |
+
increasing_streak = 1
|
11357 |
+
|
11358 |
+
else:
|
11359 |
+
increasing_streak = decreasing_streak = 1
|
11360 |
+
|
11361 |
+
if increasing_streak == count or decreasing_streak == count:
|
11362 |
+
return True
|
11363 |
+
|
11364 |
+
return False
|
11365 |
+
|
11366 |
+
###################################################################################
|
11367 |
# This is the end of the TMIDI X Python module
|
|
|
11368 |
###################################################################################
|
TPLOTS.py
CHANGED
@@ -4,12 +4,12 @@ r'''############################################################################
|
|
4 |
################################################################################
|
5 |
#
|
6 |
#
|
7 |
-
#
|
8 |
-
#
|
9 |
#
|
10 |
-
#
|
11 |
#
|
12 |
-
#
|
13 |
#
|
14 |
# https://github.com/asigalov61/tegridy-tools
|
15 |
#
|
@@ -33,20 +33,20 @@ r'''############################################################################
|
|
33 |
################################################################################
|
34 |
################################################################################
|
35 |
#
|
36 |
-
#
|
37 |
#
|
38 |
-
#
|
39 |
-
#
|
40 |
-
#
|
41 |
-
#
|
42 |
-
#
|
43 |
#
|
44 |
################################################################################
|
45 |
#
|
46 |
-
#
|
47 |
#
|
48 |
-
#
|
49 |
-
#
|
50 |
#
|
51 |
################################################################################
|
52 |
'''
|
@@ -1254,6 +1254,113 @@ def plot_parsons_code(parsons_code,
|
|
1254 |
|
1255 |
plt.close()
|
1256 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1257 |
################################################################################
|
1258 |
# [WIP] Future dev functions
|
1259 |
################################################################################
|
@@ -1363,7 +1470,53 @@ plt.show()
|
|
1363 |
'''
|
1364 |
|
1365 |
################################################################################
|
1366 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1367 |
# This is the end of TPLOTS Python modules
|
1368 |
-
#
|
1369 |
################################################################################
|
|
|
4 |
################################################################################
|
5 |
#
|
6 |
#
|
7 |
+
# Tegridy Plots Python Module (TPLOTS)
|
8 |
+
# Version 1.0
|
9 |
#
|
10 |
+
# Project Los Angeles
|
11 |
#
|
12 |
+
# Tegridy Code 2025
|
13 |
#
|
14 |
# https://github.com/asigalov61/tegridy-tools
|
15 |
#
|
|
|
33 |
################################################################################
|
34 |
################################################################################
|
35 |
#
|
36 |
+
# Critical dependencies
|
37 |
#
|
38 |
+
# !pip install numpy==1.24.4
|
39 |
+
# !pip install scipy
|
40 |
+
# !pip install matplotlib
|
41 |
+
# !pip install networkx
|
42 |
+
# !pip3 install scikit-learn
|
43 |
#
|
44 |
################################################################################
|
45 |
#
|
46 |
+
# Future critical dependencies
|
47 |
#
|
48 |
+
# !pip install umap-learn
|
49 |
+
# !pip install alphashape
|
50 |
#
|
51 |
################################################################################
|
52 |
'''
|
|
|
1254 |
|
1255 |
plt.close()
|
1256 |
|
1257 |
+
################################################################################
|
1258 |
+
|
1259 |
+
def plot_tokens_embeddings_constellation(tokens_embeddings,
|
1260 |
+
start_token,
|
1261 |
+
end_token,
|
1262 |
+
plot_size=(10, 10),
|
1263 |
+
labels_size=12,
|
1264 |
+
show_grid=False,
|
1265 |
+
save_plot=''):
|
1266 |
+
|
1267 |
+
"""
|
1268 |
+
Plots token embeddings constellation using MST and graph layout
|
1269 |
+
without dimensionality reduction.
|
1270 |
+
"""
|
1271 |
+
|
1272 |
+
distance_matrix = metrics.pairwise_distances(tokens_embeddings[start_token:end_token], metric='cosine')
|
1273 |
+
|
1274 |
+
token_labels = [str(i) for i in range(start_token, end_token)]
|
1275 |
+
|
1276 |
+
mst = minimum_spanning_tree(distance_matrix).toarray()
|
1277 |
+
|
1278 |
+
n = distance_matrix.shape[0]
|
1279 |
+
G = nx.Graph()
|
1280 |
+
|
1281 |
+
for i in range(n):
|
1282 |
+
for j in range(n):
|
1283 |
+
if mst[i, j] > 0:
|
1284 |
+
weight = 1 / (distance_matrix[i, j] + 1e-8)
|
1285 |
+
G.add_edge(i, j, weight=weight)
|
1286 |
+
|
1287 |
+
pos = nx.kamada_kawai_layout(G, weight='weight')
|
1288 |
+
|
1289 |
+
points = np.array([pos[i] for i in range(n)])
|
1290 |
+
|
1291 |
+
plt.figure(figsize=plot_size)
|
1292 |
+
plt.scatter(points[:, 0], points[:, 1], color='blue')
|
1293 |
+
|
1294 |
+
for i, label in enumerate(token_labels):
|
1295 |
+
plt.annotate(label, (points[i, 0], points[i, 1]),
|
1296 |
+
textcoords="offset points",
|
1297 |
+
xytext=(0, 10),
|
1298 |
+
ha='center',
|
1299 |
+
fontsize=labels_size)
|
1300 |
+
|
1301 |
+
for i in range(n):
|
1302 |
+
for j in range(n):
|
1303 |
+
if mst[i, j] > 0:
|
1304 |
+
plt.plot([points[i, 0], points[j, 0]],
|
1305 |
+
[points[i, 1], points[j, 1]],
|
1306 |
+
'k--', alpha=0.5)
|
1307 |
+
|
1308 |
+
plt.title('Token Embeddings Constellation with MST', fontsize=labels_size)
|
1309 |
+
plt.grid(show_grid)
|
1310 |
+
|
1311 |
+
if save_plot:
|
1312 |
+
plt.savefig(save_plot, bbox_inches="tight")
|
1313 |
+
plt.close()
|
1314 |
+
|
1315 |
+
else:
|
1316 |
+
plt.show()
|
1317 |
+
|
1318 |
+
plt.close()
|
1319 |
+
|
1320 |
+
################################################################################
|
1321 |
+
|
1322 |
+
def find_token_path(tokens_embeddings,
|
1323 |
+
start_token,
|
1324 |
+
end_token,
|
1325 |
+
verbose=False
|
1326 |
+
):
|
1327 |
+
|
1328 |
+
"""
|
1329 |
+
Finds the path of tokens between start_token and end_token using
|
1330 |
+
the Minimum Spanning Tree (MST) derived from the distance matrix.
|
1331 |
+
"""
|
1332 |
+
|
1333 |
+
distance_matrix = metrics.pairwise_distances(tokens_embeddings, metric='cosine')
|
1334 |
+
|
1335 |
+
token_labels = [str(i) for i in range(len(distance_matrix))]
|
1336 |
+
|
1337 |
+
if verbose:
|
1338 |
+
print('Total number of tokens:', len(distance_matrix))
|
1339 |
+
|
1340 |
+
mst = minimum_spanning_tree(distance_matrix).toarray()
|
1341 |
+
|
1342 |
+
n = distance_matrix.shape[0]
|
1343 |
+
G = nx.Graph()
|
1344 |
+
|
1345 |
+
for i in range(n):
|
1346 |
+
for j in range(n):
|
1347 |
+
if mst[i, j] > 0:
|
1348 |
+
weight = 1 / (distance_matrix[i, j] + 1e-8)
|
1349 |
+
G.add_edge(i, j, weight=weight)
|
1350 |
+
|
1351 |
+
try:
|
1352 |
+
start_idx = token_labels.index(str(start_token))
|
1353 |
+
end_idx = token_labels.index(str(end_token))
|
1354 |
+
|
1355 |
+
except ValueError:
|
1356 |
+
raise ValueError("Start or end token not found in the provided token labels.")
|
1357 |
+
|
1358 |
+
path_indices = nx.shortest_path(G, source=start_idx, target=end_idx)
|
1359 |
+
|
1360 |
+
token_path = [int(token_labels[idx]) for idx in path_indices]
|
1361 |
+
|
1362 |
+
return token_path
|
1363 |
+
|
1364 |
################################################################################
|
1365 |
# [WIP] Future dev functions
|
1366 |
################################################################################
|
|
|
1470 |
'''
|
1471 |
|
1472 |
################################################################################
|
1473 |
+
|
1474 |
+
def plot_tree_horizontal(data):
|
1475 |
+
|
1476 |
+
"""
|
1477 |
+
Given data as a list of levels (each level is a tuple or list of
|
1478 |
+
displacements for each branch), this function computes the cumulative
|
1479 |
+
value per branch (starting from 0) and plots each branch
|
1480 |
+
with the tree level mapped to the x-axis and the cumulative value mapped
|
1481 |
+
to the y-axis. This gives a left-to-right tree with branches spanning up
|
1482 |
+
(positive) and down (negative).
|
1483 |
+
|
1484 |
+
Parameters:
|
1485 |
+
data (list of tuple/list): Each element represents a tree level.
|
1486 |
+
It is assumed every level has the same length.
|
1487 |
+
"""
|
1488 |
+
|
1489 |
+
# Convert data to a NumPy array with shape (n_levels, n_branches)
|
1490 |
+
data = np.array(data)
|
1491 |
+
n_levels, n_branches = data.shape
|
1492 |
+
|
1493 |
+
# Compute cumulative sums along each branch.
|
1494 |
+
# Each branch starts at 0 at level 0.
|
1495 |
+
cum = np.zeros((n_levels + 1, n_branches))
|
1496 |
+
for i in range(n_levels):
|
1497 |
+
cum[i + 1, :] = cum[i, :] + data[i, :]
|
1498 |
+
|
1499 |
+
plt.figure(figsize=(12, 8))
|
1500 |
+
|
1501 |
+
# Plot each branch as a line. For branch j:
|
1502 |
+
# - x coordinates are the tree levels (0 to n_levels)
|
1503 |
+
# - y coordinates are the corresponding cumulative values.
|
1504 |
+
for j in range(n_branches):
|
1505 |
+
x = np.arange(n_levels + 1)
|
1506 |
+
y = cum[:, j]
|
1507 |
+
plt.plot(x, y, marker='o', label=f'Branch {j}')
|
1508 |
+
|
1509 |
+
plt.title("Horizontal Tree Visualization: Branches Spanning Up and Down", fontsize=14)
|
1510 |
+
plt.xlabel("Tree Level (Left = Root)")
|
1511 |
+
plt.ylabel("Cumulative Value (Up = Positive, Down = Negative)")
|
1512 |
+
|
1513 |
+
# Add a horizontal line at y=0 to emphasize the center.
|
1514 |
+
plt.axhline(0, color="gray", linestyle="--")
|
1515 |
+
|
1516 |
+
#plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
|
1517 |
+
plt.tight_layout()
|
1518 |
+
plt.show()
|
1519 |
+
|
1520 |
+
################################################################################
|
1521 |
# This is the end of TPLOTS Python modules
|
|
|
1522 |
################################################################################
|