Документация Engee
Notebook

Усреднение близко расположенных точек в рамках допуска

Покажем, как можно сократить количество точек на графике, оставив только те, которые отличаются от остальных по какому-то критерию.

Исходные данные

Воспользуемся функцией из файла peaks.jl, которая создаст нам гладкую поверхность с несколькими выступами в интервале [-3,3], [-3,3]. Добавим к данным шума немного по оси Z. Теперь облако точек уже не лежит на одной поверхности, а разбросано вокруг нее.

In [ ]:
gr( format=:png ) # Обратите внимание, теперь все графики, в рамках
                  # текущей рабочей сессии, будут выводиться в PNG

include( "$(@__DIR__)/peaks.jl" );

xy = rand(10000, 2) .* 6 .- 3; 
z = peaks.( xy[:,1], xy[:,2] ) .+ 0.5 .- rand(10000,1);
A = [xy z]

scatter( A[:,1], A[:,2], A[:,3], camera=(45, 20), ms=2, markerstrokewidth=0.1, leg=false )
Out[0]:
No description has been provided for this image

Восстановление гладкой поверхности

Внутри этого облака точек мы поищем те точки, которые можно было бы объединить по следующим признакам:

  • расстояние между точками не превышает tol,
  • не интересуемся осью Z, сравниваем только X и Y.
In [ ]:
tol = 0.33;

Чтобы выделить идентичные области, огрубим исходный набор данных, округлив все координаты каждой точки до целого числа, предварительно умножив на 1/tol.

In [ ]:
aA = round.( (1/tol) .* A[:,1:2], digits=0);

Наша матрица теперь состоит из большого количества групп векторов с идентичными значениями. Как нам их сгрупипровать? Можно поэлементно сравнивать векторы между собой, но более короткий путь.

Эту операцию можно выплонить при помощи функции groupslices из библиотеки GroupSlices (при необходимости, чтобы ее поставить, раскомментируйте и выполните следующую ячейку):

In [ ]:
#]add GroupSlices
In [ ]:
using GroupSlices
C = groupslices( aA, dims=1 );

Функция groupslices для каждой строки r матрицы возвращает индекс *первой встреченной строчки, идентичной r.

Усредним точки в каждой подгруппе.

In [ ]:
using Statistics
avgA = [  mean( A[C .== c, :], dims=1) for c in unique( C ) ]
avgA = vcat( avgA... ); # Мы получили матрицу из матриц; осуществим вертикальную конкатенацию строчек

Теперь мы можем построить график из усредненных точек, отметив для себя что хотя набор данных и не стал структурированным, но мы избавились от вариативности по оси Z, сохранив общий вид исходных данных.

In [ ]:
scatter( A[:,1], A[:,2], A[:,3], camera=(45, 20), ms=2, markerstrokewidth=0.1, leg=false )
scatter!( avgA[:,1], avgA[:,2], avgA[:,3], color=:red, ms=3, legend=false )
Out[0]:
No description has been provided for this image

Отдельные области можно увидеть, раскрасив их следующим образом:

In [ ]:
scatter( A[:,1], A[:,2], A[:,3], camera=(45, 20), ms=2, markerstrokewidth=0.1, leg=false, zcolor=C./maximum(C), c=:prism )
scatter!( avgA[:,1], avgA[:,2], avgA[:,3], color=:white, ms=3, legend=false, camera=(0,90) )
Out[0]:
No description has been provided for this image

Заключение

Мы отфильтровали зашумленную функцию, отобрав некоторые уникальные точки. В их отборе мы опирались на допустимую близость между опорными точками по осям X и Y.