Создание кривой вокруг точки на точечной диаграмме

Я создаю точечную диаграмму, содержащую данные из нескольких источников, как показано ниже.

График рассеяния

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

Я реализовал решение, используя циклический поиск точек с помощью knnsearch, а затем применяя Фильтр hampel для устранения шума. В приведенном ниже примере я выбрал точку примерно посередине заштрихованной синим области. Как видите, результат далек от совершенства, и мне нужно больше точности.

Не такой уж идеальный результат

Я ищу что-то похожее на функцию boundary, но для работы с внутри облака точек, а не снаружи.


person Nikola Malešević    schedule 30.11.2016    source источник


Ответы (2)


Конечная цель - вычислить площадь между линиями на графике.

Я бы сделал это по-другому. Просто возьмите любые две линии графика, вычислите площадь под кривыми с помощью какой-либо числовой аппроксимации (например, трапециевидное численное интегрирование), затем вычтите площади и получите площадь между линиями.

person Trilarion    schedule 30.11.2016
comment
Спасибо за идею использовать кривые. Мне пришлось использовать совершенно другой подход для остальной части решения, но это заставило меня начать. - person Nikola Malešević; 01.12.2016

Благодаря идее в ответе Trilarion я смог найти лучшее решение.

Обратите внимание, что я использую обозначение для плоскости YZ вместо XY (для соответствия системе координат робота).

Решение

Создание кривых для каждого набора данных рассеяния

% Scatter data is in iy and iz vectors.
curve = fit(iy, iz, 'smoothingspline', 'SmoothingParam', 0.5);
% Remove outliers.
fdata = feval(curve, iy);
I = abs(fdata - iz) > 0.5 * std(iz);
outliers = excludedata(iy, iz, 'indices', I);
% Final curve without outliers.
curve = fit(iy, iz, 'smoothingspline', 'Exclude', outliers, 'SmoothingParam', 0.5);

Постройте кривые и данные разброса

% Color maps generated by MATLAB's colormap function.
h_curve = plot(curve);
set(h_curve, 'Color', color_map_light(i,:));    
scatter(iy, iz, '.', 'MarkerFaceColor', color_map(i,:))

Позвольте пользователю вводить данные, выбирая точки

Пользователь выбирает одну точку в качестве точки запроса и две точки для ограничения по оси Y. Это связано с тем, что некоторые кривые сближаются, но никогда не пересекаются.

[cs_position.y, cs_position.z] = ginput(1);
[cs_area_limits, ~] = ginput(2);

if cs_area_limits(1) > cs_area_limits(2)
  cs_area_limits = flipud(cs_area_limits);
end

plot_cross_section(cs_position);

Наконец вычислить и построить площадь поверхности

В этом разделе используется фантастический ответ от Doresoom.

function [ ] = plot_cross_section(query_point)
%PLOT_CROSS_SECTION Calculates and plots cross-section area.
%   query_point  Query point.

  % Find values on query point's Y on each of the curves.
  z_values = cellfun(@(x, y) feval(x, y),...
    curves, num2cell(ones(size(curves)) * query_point.y))

  % Find which curves are right above and below the query point.
  id_top = find(z_values >= query_point.z, 1, 'first')
  id_bottom = find(z_values < query_point.z, 1, 'last')

  if isempty(id_top) || isempty(id_bottom)      
    return
  end

  % Generate points along curves on the range over Y.
  y_range = cs_area_limits(1):0.1:cs_area_limits(2);
  z_top = feval(curves{id_top}, y_range).';
  z_bottom = feval(curves{id_bottom}, y_range).';

  % Plot area.
  Y = [ y_range, fliplr(y_range) ];
  Z = [ z_top, fliplr(z_bottom) ];
  fill(Y, Z, 'b', 'LineStyle', 'none')
  alpha 0.5
  hold on

  % Calculate area and show to user.
  cs_area = polyarea(Y, Z);
  area_string = sprintf('%.2f mm^2', cs_area);
  text(0, -3, area_string, 'HorizontalAlignment', 'center')
end

Результат

Изображение результата

person Nikola Malešević    schedule 01.12.2016