Closed Ajstros closed 2 years ago
This code below is what I am thinking.
import matplotlib.pyplot as plt
import numpy as np
import time
def plt_uniques(data, ax=None):
"""Plot only the first and last of each group of unique data points to save time and memory.
Parameters
----------
data : np.ndarray
Data to plot.
"""
if len(data.shape) < 1:
raise Exception(f'expected data.shape >= 1 but data.shape is {data.shape}')
if ax is None:
# No axis provided, create new
fig, ax = plt.subplots()
if len(data.shape) > 1:
# 2-dimensional, plot each row as a separate line
for d in data:
plt_uniques(data=d, ax=ax)
else:
# len(data.shape) == 1, we can plot as normal
uniques, indices = np.unique(data, return_index=True) # Get indices of first appearance of unique values
indices = np.append(indices, indices - 1) # Get indices from just before unique values to get first and last of each group of unique values
indices = np.append(indices, len(data) - 1) # Add last index so full data is plotted
indices = np.sort(indices[indices >= 0]) # Sort data for plotting and remove negative indices (-1 from unique at 0)
unique_data = data[indices] # Grab data at indices
plt.plot(indices, unique_data, linestyle='dotted') # Plot dotted line so we can see original underneath
plt.show(block=False)
data = np.array([i // 100 for i in range(1000)])
fig, ax = plt.subplots()
start = time.time()
ax.plot(data)
plt.show(block=False)
end = time.time()
print(f'Normal plotting: {end - start} seconds')
start = time.time()
plt_uniques(data, ax)
end = time.time()
print(f'Unique plotting: {end - start} seconds')
plt_uniques(data=np.array([[i // 100 for i in range(1000)], [i // 100 + 1 for i in range(1000)]]))
plt_uniques(data=np.array([[[i // 100 for i in range(1000)], [i // 100 + 1 for i in range(1000)]], [[i // 100 for i in range(1000)], [i // 100 + 1 for i in range(1000)]]]))
try:
plt_uniques(data = np.array(0))
except Exception as e:
print('Got expected error:', e)
plt.show()
When run, that outputs
Normal plotting: 0.0652000904083252 seconds
Unique plotting: 0.002001047134399414 seconds
Got expected error: expected data.shape >= 1 but data.shape is ()
which shows a decent speed up.
The function in the above code would likely go in the pyripherals.utils
module.
Is your feature request related to a problem? Please describe. For debugging purposes especially, it is convenient to plot the data in the DDR3 data_arrays to make sure it matches what we expect. However, these arrays are very long and thus take some time and memory to print.
Describe the solution you'd like Because the data in these arrays often represents a flat or square wave, where several values are repeated, the high length of the arrays becomes a hindrance without providing any other helpful information. Because
matplotlib
can plot line graphs, connecting points automatically, several points in a flat section can be represented by two points instead: a beginning and an end. For example, a 1001 point array following the pattern [0, 0.001, 0.002, ..., 1] will appear the same on the graph as the 2 point array [0, 1]. I would like a solution that plots only the first and last points of a section of repeated values to save time and memory.Describe alternatives you've considered One alternative would be cutting down the dataset without regard to repeated values. For example, just taking every other data point. This would help and would actually outperform my above suggestion in cases without repeated values, like a sine wave, but it leaves the chance to change the plot image and would underperform against my above solution in cases of long sections of repeated values.