Рассмотрим следующую функцию.Данные будут объединены в одинаковые ячейки вдоль оси и
- , если в ячейке есть одна или две точки, перехватить эти точки,
- , если вbin, принять минимальное и максимальное значение.
- добавьте первую и последнюю точку, чтобы убедиться, что используется один и тот же диапазон данных.
Это позволяет сохранить исходные данные в регионахнизкой плотности, но значительно сокращают объем данных для построения в областях высокой плотности.В то же время все функции сохраняются с достаточно плотным биннингом.
import numpy as np; np.random.seed(42)
def filt(x,y, bins):
d = np.digitize(x, bins)
xfilt = []
yfilt = []
for i in np.unique(d):
xi = x[d == i]
yi = y[d == i]
if len(xi) <= 2:
xfilt.extend(list(xi))
yfilt.extend(list(yi))
else:
xfilt.extend([xi[np.argmax(yi)], xi[np.argmin(yi)]])
yfilt.extend([yi.max(), yi.min()])
# prepend/append first/last point if necessary
if x[0] != xfilt[0]:
xfilt = [x[0]] + xfilt
yfilt = [y[0]] + yfilt
if x[-1] != xfilt[-1]:
xfilt.append(x[-1])
yfilt.append(y[-1])
sort = np.argsort(xfilt)
return np.array(xfilt)[sort], np.array(yfilt)[sort]
Чтобы проиллюстрировать концепцию, давайте использовать некоторые игрушечные данные
x = np.array([1,2,3,4, 6,7,8,9, 11,14, 17, 26,28,29])
y = np.array([4,2,5,3, 7,3,5,5, 2, 4, 5, 2,5,3])
bins = np.linspace(0,30,7)
Затем вызовем xf, yf = filt(x,y,bins)
и построим график обоихИсходные данные и отфильтрованные данные дают:
Вариант использования вопроса с примерно 30000 точками данных будет показан ниже.Использование представленной методики позволило бы уменьшить количество нанесенных точек с 30000 до 500. Это число, конечно, будет зависеть от используемого биннинга - здесь 300 бинов.В этом случае для вычисления функции требуется ~ 10 мс.Это не супербыстрое, но все же значительное улучшение по сравнению с построением всех точек.
import matplotlib.pyplot as plt
# Generate some data
x = np.sort(np.random.rayleigh(3, size=30000))
y = np.cumsum(np.random.randn(len(x)))+250
# Decide for a number of bins
bins = np.linspace(x.min(),x.max(),301)
# Filter data
xf, yf = filt(x,y,bins)
# Plot results
fig, (ax1, ax2, ax3) = plt.subplots(nrows=3, figsize=(7,8),
gridspec_kw=dict(height_ratios=[1,2,2]))
ax1.hist(x, bins=bins)
ax1.set_yscale("log")
ax1.set_yticks([1,10,100,1000])
ax2.plot(x,y, linewidth=1, label="original data, {} points".format(len(x)))
ax3.plot(xf, yf, linewidth=1, label="binned min/max, {} points".format(len(xf)))
for ax in [ax2, ax3]:
ax.legend()
plt.show()