生成散点图上点周围的曲线

时间:2016-11-30 15:06:21

标签: matlab plot curve-fitting area best-fit-curve

我正在生成包含来自多个来源的数据的散点图,如下所示。

Scatter plot

我希望能够生成围绕任意查询点并在散点图上传递点的曲线。最终目标是计算图上线之间的面积。

我已经使用循环方式使用knnsearch查找点,然后应用hampel过滤器来消除噪音。在下面的例子中,我在蓝色阴影区域的中间选择了一个点。如您所见,结果远非完美,我需要更高的精度。

Not so perfect result

我正在寻找与boundary函数类似的东西,但是要从点云的内部工作,而不是从外部工作。

2 个答案:

答案 0 :(得分:1)

  

最终目标是计算图上线条之间的区域。

我会以不同的方式做到这一点。只需绘制图中的任意两行,使用某种数值近似计算曲线下的面积(例如trapezoidal numerical integration),然后减去这些面积并获得线之间的区域。

答案 1 :(得分:1)

感谢Trilarion answer的想法,我能够提出更好的解决方案。

请注意,我使用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的fantastic answer

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

结果

Result image