Plot data with gaps (xfig example)

From Remeis-Wiki
Revision as of 03:33, 4 April 2019 by Stierhof (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Plot data over range with gaps

Plot with gaps jjs.png
%% Found yourself with data that is only interesting in some parts of the
%% plot range? Ever wondered how you can do this with XFig? Here is your chance!
%% 
%% The idea: Give the ranges of interest and the data to plot. Arrange the data
%% in subplots and add a visible marker to make the seperation clear.

require("xfig");

% Some function do demonstrate the feature
define zp (x) { return 1./sqrt(2*PI)*exp(-x*x/2.); }

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  Here is where the plotting begins              %%

%-----------------------
%  Do a plot where the x-axis has a gap

variable x = [-20:20:0.001]; % The x-grid for the full function
variable y1 = zp(x); % Use the function, we shift it later when plotting
variable y2 = zp(.3*x)+.7*zp(x-4);

%% In xranges and yranges the plot range of interest are given. Make sure
%% they do not overlap (or the scale would be messed up).

% Environment setup
variable xranges = [{5,17},{989,1010}]; % Min and Max values for the subplots
variable yranges = [{0,.5}];
variable xlabel = "Random test [a.u.]";
variable ylabel = "Probability";
variable title = "Plot with Gaps";

%% NSUBn is the number of subplots. In XDIM, YDIM the size of the total plot
%% can be set.

variable NSUBX = length(xranges); % Number of x splittings
variable NSUBY = length(yranges); % Number of y splittings
variable XDIM = 15.; % Plots total x width
variable YDIM = 10.; % Plots total y width

%% Set some variables we use to store different stuff. xsepsize, ysepsize
%% determines how large the visible seperator should be. 0.5 is twice the
%% default major tic mark length, which seems to be a good value.

% Define the plot variables
variable P = {}; % collector for plot structures
variable i,j;
variable dx=0.,dy=0.; % Shift pannels
variable ddx, ddy; % Data of plot
variable xsepsize = 0.5; % Seperator size in x
variable ysepsize = 0.5; % Seperator size in y
variable XSEP1,XSEP2; % x seperator
variable YSEP1,YSEP2; % y seperator

%% Calculate the total x- and yrange we are covering. We need this to
%% set the plot panel size matching the relative range size.

variable sumxrange = 0.; % Total covered ranges for scaling
variable sumyrange = 0.;

foreach i (xranges) { sumxrange += _max(i[0], i[1])-_min(i[0],i[1]); }
foreach j (yranges) { sumyrange += _max(j[0], j[1])-_min(j[0],j[1]); }

%% Some more variable we need to set the spacing between panels right.

variable thisxmin, thisxmax; % Current panels min and max range
variable thisymin, thisymax;

variable xspace = 0.; % Extra space so the total size is reached
variable yspace = 0.;

%% Loop over all ranges and create a panel for each. Remove the tics in
%%  between and insert the visible seperator. Finally plot the data and
%%  adjust the panels.

_for j (0, NSUBY-1, 1)
{
  thisymin = _min(yranges[j][0], yranges[j][1]);
  thisymax = _max(yranges[j][0], yranges[j][1]);
  dx = 0.;
  
  % Set extra y space as necessary
  if (NSUBY > 1) {
    if (j > 0 && j < NSUBY-1)
      yspace = ysepsize;
    else
      yspace = ysepsize/2.;
  }
  
  _for i (0, NSUBX-1, 1) {
    thisxmin = _min(xranges[i][0], xranges[i][1]);
    thisxmax = _max(xranges[i][0], xranges[i][1]);
    
    % Set extra x space as necessary
    if (NSUBX > 1) {
      if (i > 0 && i < NSUBX-1)
	xspace = xsepsize;
      else
	xspace = xsepsize/2.;
    }

    % Create plot object for each section
    list_append(P, xfig_plot_new(XDIM*(thisxmax-thisxmin)/sumxrange-xspace,
			         YDIM*(thisymax-thisymin)/sumyrange-yspace));

    % Set world according to given ranges
    P[-1].world(xranges[i][0], xranges[i][1], yranges[j][0], yranges[j][1]);
    
    % Set axis to confine plot labels so they do not overlap
    %P[-1].axis(; ticlabels_confine);

    % Start with top left panel and go right to bottom to remove tic marks
    variable this = P[-1].plot_data;
    if (j > 0) % All panels that are not the first one (y) do not need x2axis tics
      P[-1].x2axis(;off);
    if (i > 0) % All panels not the first (x) do not need y1axis tics
      P[-1].y1axis(;off);
    if (j < NSUBY-1) % All panels not the last (y) do not need x1axis tics
      P[-1].x1axis(;off);
    if (i < NSUBX-1) % All panels not the last (x) do not need y2axis tics
      P[-1].y2axis(;off);
    
    % Plot into panels
    P[-1].plot(x+10, y1; color="#CC0033");
    P[-1].plot(x+1000, y2; color="#0033CC");

    % Create plot objects for seperators (unfortunately the implementation does not
    % allow to reuse objects)
    XSEP1 = xfig_plot_new(1,1); XSEP2 = xfig_plot_new(1,1);
    XSEP1.world(-1,1,-1,1); XSEP2.world(-1,1,-1,1);
    XSEP1.axis(;off); XSEP2.axis(;off);
    XSEP1.plot([-1,-.25], [0,0]; width=1); XSEP2.plot([-1,-.25], [0,0]; width=1);
    XSEP1.plot([.25,1], [0,0]; width=1); XSEP2.plot([.25,1], [0,0]; width=1);
    XSEP1.plot([-.75,.25], [-1,1]; width=1); XSEP2.plot([-.75,.25], [-1,1]; width=1);
    XSEP1.plot([-.25,.75], [-1,1]; width=1); XSEP2.plot([-.25,.75], [-1,1]; width=1);
    XSEP1.axis(;off); XSEP2.axis(;off);
    XSEP1.scale(xsepsize); XSEP2.scale(xsepsize);
    
    YSEP1 = xfig_plot_new(1,1); YSEP2 = xfig_plot_new(1,1);
    YSEP1.world(-1,1,-1,1); YSEP2.world(-1,1,-1,1);
    YSEP1.axis(;off); YSEP2.axis(;off);
    YSEP1.plot([0,0],[-1,-.25]; width=1); YSEP2.plot([0,0],[-1,-.25]; width=1);
    YSEP1.plot([0,0], [.25,1]; width=1); YSEP2.plot([0,0], [.25,1]; width=1);
    YSEP1.plot([-1,1], [-.75,.25]; width=1); YSEP2.plot([-1,1], [-.75,.25]; width=1);
    YSEP1.plot([-1,1], [-.25,.75]; width=1); YSEP2.plot([-1,1], [-.25,.75]; width=1);
    YSEP1.scale(ysepsize); YSEP2.scale(ysepsize);

    % Append seperators
    if (i != NSUBX-1) {
      if (j == NSUBY-1)
	P[-1].add_object(XSEP1, 1,0,-.5,0; world0);
      if (j == 0)
	P[-1].add_object(XSEP2, 1,1,-.5,0; world0);
    }
    if (j != NSUBY-1) {
      if (i == NSUBX-1)
	P[-1].add_object(YSEP1, 0,0,0,.5; world0);
      if (i == 0)
	P[-1].add_object(YSEP2, 1,0,0,.5; world0);
    }

    % Shift pannel to negative y values
    if (i == 0) dy -= P[-1].plot_data.plot_height+ysepsize;
    ddx = P[-1].plot_data.X;
    P[-1].translate(vector(dx-ddx.x, dy-ddx.y, -ddx.z));
    dx += P[-1].plot_data.plot_width+xsepsize;
  }
}

%% Combine all the panels into one compound. We reverse the list to
%% keep the order from left-right top-bottom

list_reverse(P); % need to reverse to get the order right
variable PP = xfig_new_compound( __push_list(P)); % Combine panels
dy *= -1; % Set origin back to bottom left
PP.translate(vector(0, dy, 0));

variable xmin, xmax, ymin, ymax;
(xmin,xmax,ymin,ymax,,) = PP.get_bbox(); % Get total plot dimensions

%% When everything is set, add x- and y-labels and the title.

variable ptxt;
if (NSUBX == 1) % If only one use existing label
  P[0].xlabel(xlabel); % Only passed by reference, so we can change label here
else {
  ptxt = xfig_new_text(xlabel);
  xfig_justify_object(ptxt, vector(.5*dx, ymin, 0), vector(0, 1, 0));
  PP.append(ptxt);
}
if (NSUBY == 1)
  P[-1].ylabel(ylabel); % Same as for xlabel
else {
  ptxt = xfig_new_text(ylabel);
  ptxt.rotate_pict(90);
  xfig_justify_object(ptxt, vector(xmin, .5*dy, 0), vector(1, 0, 0));
  PP.append(ptxt);
}

% Set title
(xmin,xmax,ymin,ymax,,) = PP.get_bbox(); % Update dimensions
if (NSUBX == 1)
  P[-1].title(title);
else {
  ptxt = xfig_new_text(title);
  xfig_justify_object(ptxt, vector(.5*dx, ymax, 0), vector(0, -1, 0));
  PP.append(ptxt);
}

%% Here you go! Output the plot and enjoy it!
%% 
%% One cautious note: as with xfig_multiplot it may happen that tic labels
%% are overlapping. To circumvent this either give major tic marks or change
%% the plotting ranges.

PP.render("plot_with_gaps.pdf");

<\pre>