[Pkg-octave-devel] Bug#365757: plotcollapse

Francesco Potorti` Potorti at isti.cnr.it
Mon May 15 17:39:22 UTC 2006


This function solves a problem of mine when plotting data.  It often
happens to me to have a lot of redundant points for measured data,
points that are mostly invisible on paper or screen because they are
very near one another.  Moreover, when plotting lines, often a straight
line is composed by a great number of small segments, which makes a huge
.eps file.

This function can be called on data to be plotted to optimise them by
removing unnecessary points before generating the plot.  Data that I use
are typically reduced by ten times.  You will appreciate this if you
happen to plot data series of simulated or measured data with hundreds
or more samples.

Segment optimisation can be disabled for point plots.  Point plot
optimisation is done as a special case of general segment optimisation,
but it could probably be rewritten with a separate vectorialised
algorithm that makes it much faster.

Only the common case of points with increasing abscissae is optimised.
Optimisation in the general case is more complex and probably not worth
doing for plotting.

If you try it on your data please let me know how it works.


## Copyright © 2006  Francesco Potortì
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software Foundation,
## Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301, USA.

## -*- texinfo -*-
## @deftypefn {Function File} {} plotcollapse (@var{P})
## @deftypefnx {Function File} {} plotcollapse (@var{P}, @var{so})
## @deftypefnx {Function File} {} plotcollapse (@var{P}, @var{so}, @var{res})
##
## Optimise plot data by removing redundant points and segments
##
## The first parameter @var{P} is a two-column matrix, abscissae and
## ordinates, to be plotted with a line.  The second optional argument
## @var{so}, defaulting to @var{true}, disables segment optimisation when
## set to @var{false}. The third optional argument @var{res} is the size of
## the largest error on the plot with respect to the range of values; it
## defaults to 1/1000.  Returns a two-column matrix containing a subset of
## the rows of @var{P}. A line plot of @var{P} has the same appearance as a
## line plot of the output, with errors smaller than @var{res}.  When
## creating point plots, set @var{so} to @var{false}.
## @end deftypefn

## Author: Francesco Potortì <Potorti at isti.cnr.it>
## $Revision: 1.4 $
## Usage: plotcollapse(P[, so[, res]])
## Description: Optimise plot data by removing redundant points and segments

function C = plotcollapse (P, so, res)
  ## Only the common case of points with increasing abscissae is optimised.
  ## Optimisation in the general case is more complex and probably not worth
  ## doing for plotting.

  if (columns(P) != 2 || rows(P) < 1)
    error("P must contain at least one point");
  endif
  if (nargin < 2)
    so = true;			# do segment optimisation
  endif
  if (nargin < 3 || res <= 0)
    res = 1e-3;			# default resolution is 1000 dots/axis
  endif

  l = rows(P);			# length of P
  E = range(P)' * res;		# slack: admissible error on coordinates
  V = !zeros(l,1);		# valid points

  # For each segment, r and s are its extremes
  r = 1; R = P(1,:)';		# start of the latest segment
  s = 0;			# end of the latest segment undefined
  M = [];			# rotation matrix

  for t = r+1:l
    T = P(t,:)';

    if (s == 0)			# searching for end of segment
      if (norm((T-R)./E) < 1)	# t too near to r
	V(t) = false;		# do not plot t
	continue;
      endif
    elseif (norm((T-S)./E) < 1)	# t too near to s
      V(t) = false;		# do not plot t
      continue;
    elseif (T(1) < S(1))	# going back
      r = t; R = T;		# restart from here
      s = 0;			# and go looking for end of segment
      M = [];			# reset rotation matrix
      continue;
    elseif (so)			# we have a segment and not going back
      if (abs(dot(T-R,D)) < 1)	# we can collapse
	V(s) = false;		# do not plot s
      else			# set a new segment
	r = s; R = S;		# new start
	M = [];			# rebuild rotation matrix
      endif
    endif
    s = t; S = T;		# new end of segment

    if (so && rows(M) == 0)
      M = inv([(S-R), [0,-1;1,0]*(S-R)]); # rotation matrix
      MS = M*E;			# rotated slack
      D = M(2,:)'/MS(2);	# projection vector for distance
    endif
  endfor

  C = P(V,:);
endfunction




More information about the Pkg-octave-devel mailing list