scripts/plot/plotyy.m
author Ben Abbott <bpabbott@mac.com>
Tue Jun 16 06:43:56 2009 +0200 (2009-06-16)
changeset 9337 fee95bb4ee94
parent 9336 9f24c50b6fa0
permissions -rw-r--r--
plotyy.m: Fix compatibility with subplot.
jwe@8920
     1
## Copyright (C) 2007, 2008, 2009 David Bateman
dbateman@7195
     2
##
dbateman@7195
     3
## This file is part of Octave.
dbateman@7195
     4
##
dbateman@7195
     5
## Octave is free software; you can redistribute it and/or modify it
dbateman@7195
     6
## under the terms of the GNU General Public License as published by
dbateman@7195
     7
## the Free Software Foundation; either version 3 of the License, or (at
dbateman@7195
     8
## your option) any later version.
dbateman@7195
     9
##
dbateman@7195
    10
## Octave is distributed in the hope that it will be useful, but
dbateman@7195
    11
## WITHOUT ANY WARRANTY; without even the implied warranty of
dbateman@7195
    12
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
dbateman@7195
    13
## General Public License for more details.
dbateman@7195
    14
##
dbateman@7195
    15
## You should have received a copy of the GNU General Public License
dbateman@7195
    16
## along with Octave; see the file COPYING.  If not, see
dbateman@7195
    17
## <http://www.gnu.org/licenses/>.
dbateman@7195
    18
dbateman@7195
    19
## -*- texinfo -*-
dbateman@7195
    20
## @deftypefn {Function File} {} plotyy (@var{x1}, @var{y1}, @var{x2}, @var{y2})
dbateman@7195
    21
## @deftypefnx {Function File} {} plotyy (@dots{}, @var{fun})
dbateman@7195
    22
## @deftypefnx {Function File} {} plotyy (@dots{}, @var{fun1}, @var{fun2})
dbateman@7195
    23
## @deftypefnx {Function File} {} plotyy (@var{h}, @dots{})
dbateman@7195
    24
## @deftypefnx {Function File} {[@var{ax}, @var{h1}, @var{h2}] =} plotyy (@dots{})
rdrider0-list@9040
    25
## Plots two sets of data with independent y-axes.  The arguments @var{x1} and
dbateman@7195
    26
## @var{y1} define the arguments for the first plot and @var{x1} and @var{y2}
dbateman@7195
    27
## for the second. 
dbateman@7195
    28
##
dbateman@7195
    29
## By default the arguments are evaluated with 
rdrider0-list@9040
    30
## @code{feval (@@plot, @var{x}, @var{y})}.  However the type of plot can be
dbateman@7195
    31
## modified with the @var{fun} argument, in which case the plots are
rdrider0-list@9040
    32
## generated by @code{feval (@var{fun}, @var{x}, @var{y})}.  @var{fun} can be 
dbateman@7195
    33
## a function handle, an inline function or a string of a function name.
dbateman@7195
    34
##
dbateman@7195
    35
## The function to use for each of the plots can be independently defined 
dbateman@7195
    36
## with @var{fun1} and @var{fun2}.
dbateman@7195
    37
##
dbateman@7195
    38
## If given, @var{h} defines the principal axis in which to plot the @var{x1}
rdrider0-list@9040
    39
## and @var{y1} data.  The return value @var{ax} is a two element vector with
rdrider0-list@9040
    40
## the axis handles of the two plots.  @var{h1} and @var{h2} are handles to
dbateman@7195
    41
## the objects generated by the plot commands.
dbateman@7195
    42
##
dbateman@7195
    43
## @example
dbateman@7195
    44
## @group
dbateman@7195
    45
## x = 0:0.1:2*pi; 
dbateman@7195
    46
## y1 = sin (x);
jwe@7196
    47
## y2 = exp (x - 1);
jwe@7196
    48
## ax = plotyy (x, y1, x - 1, y2, @@plot, @@semilogy);
dbateman@7195
    49
## xlabel ("X");
dbateman@7195
    50
## ylabel (ax(1), "Axis 1");
dbateman@7195
    51
## ylabel (ax(2), "Axis 2");
dbateman@7195
    52
## @end group
dbateman@7195
    53
## @end example
dbateman@7195
    54
## @end deftypefn
dbateman@7195
    55
dbateman@7195
    56
function [Ax, H1, H2] = plotyy (varargin)
dbateman@7195
    57
dbateman@7665
    58
  ## Don't use __plt_get_axis_arg__ here as ax is a two vector for plotyy
dbateman@7665
    59
  if (nargin > 1 && length (varargin{1}) == 2 && ishandle(varargin{1}(1)) 
dbateman@7665
    60
      &&  ishandle(varargin{1}(2)) && 
dbateman@7665
    61
      all (floor (varargin{1}) != varargin{1}))
dbateman@7665
    62
    obj1 = get (varargin{1}(1));
dbateman@7665
    63
    obj2 = get (varargin{1}(2));
dbateman@7665
    64
    if (strcmp (obj1.type, "axes") || strcmp (obj2.type, "axes"))
dbateman@7665
    65
      ax = [obj1, obj2];
dbateman@7665
    66
      varargin(1) = [];
dbateman@7665
    67
      if (isempty (varargin))
dbateman@7665
    68
	varargin = {};
dbateman@7665
    69
      endif
dbateman@7665
    70
    else
dbateman@7665
    71
      error ("plotyy: expecting first argument to be axes handle");
dbateman@7665
    72
    endif
dbateman@7665
    73
  else
dbateman@7665
    74
    f = get (0, "currentfigure");
dbateman@7665
    75
    if (isempty (f))
bpabbott@9336
    76
      f = figure ();
bpabbott@9336
    77
    endif
bpabbott@9337
    78
    ca = get (f, "currentaxes");
bpabbott@9337
    79
    if (isempty (ca))
bpabbott@9337
    80
      ax = [];
bpabbott@9337
    81
    elseif (strcmp (get (ca, "tag"), "plotyy"));
bpabbott@9337
    82
      ax = get (ca, "__plotyy_axes__");
bpabbott@9337
    83
    else
bpabbott@9337
    84
      ax = ca;
bpabbott@9337
    85
    endif
bpabbott@9336
    86
    if (length (ax) > 2)
bpabbott@9336
    87
      for i = 3 : length (ax)
bpabbott@9336
    88
        delete (ax (i));
bpabbott@9336
    89
      endfor
bpabbott@9336
    90
      ax = ax(1:2);
bpabbott@9336
    91
    elseif (length (ax) == 1)
bpabbott@9336
    92
      ax(2) = axes ();
bpabbott@9336
    93
    elseif (isempty (ax))
dbateman@7665
    94
      ax(1) = axes ();
dbateman@7665
    95
      ax(2) = axes ();
dbateman@7665
    96
    endif
dbateman@7665
    97
    if (nargin < 2)
dbateman@7665
    98
      varargin = {};
dbateman@7665
    99
    endif
dbateman@7665
   100
  endif 
jwe@7215
   101
jwe@7215
   102
  if (nargin < 4)
jwe@7215
   103
    print_usage ();
jwe@7215
   104
  endif
jwe@7216
   105
jwe@7215
   106
  oldh = gca ();
jwe@7215
   107
  unwind_protect
jwe@7215
   108
    [ax, h1, h2] = __plotyy__ (ax, varargin{:});
jwe@7215
   109
  unwind_protect_cleanup
dbateman@8237
   110
    ## Only change back to the old axis if we didn't delete it
dbateman@8237
   111
    if (ishandle(oldh) && strcmp (get (oldh, "type"), "axes"))
dbateman@8237
   112
      axes (oldh);
dbateman@8237
   113
    endif
jwe@7215
   114
  end_unwind_protect
dbateman@7195
   115
dbateman@7195
   116
  if (nargout > 0)
dbateman@7195
   117
    Ax = ax;
dbateman@7195
   118
    H1 = h1;
dbateman@7195
   119
    H2 = h2;
dbateman@7195
   120
  endif
jwe@7196
   121
dbateman@7195
   122
endfunction
dbateman@7195
   123
dbateman@7195
   124
function [ax, h1, h2] = __plotyy__ (ax, x1, y1, x2, y2, varargin)
dbateman@7195
   125
  if (nargin > 5)
dbateman@7195
   126
    fun1 = varargin{1};
dbateman@7195
   127
  else
dbateman@7195
   128
    fun1 = @plot;
dbateman@7195
   129
  endif
dbateman@7195
   130
  if (nargin > 6)
dbateman@7195
   131
    fun2 = varargin{2};
dbateman@7195
   132
  else
dbateman@7195
   133
    fun2 = fun1;
dbateman@7195
   134
  endif
dbateman@7195
   135
dbateman@7195
   136
  xlim = [min([x1(:); x2(:)]), max([x1(:); x2(:)])];
dbateman@7195
   137
dbateman@8237
   138
  if (ishandle(ax(1)) && strcmp (get (ax(1), "type"), "axes"))
dbateman@8237
   139
    axes (ax(1));
dbateman@8237
   140
  else
dbateman@8237
   141
    ax(1) = axes ();
dbateman@8237
   142
  endif
dbateman@7665
   143
  newplot ();
dbateman@7195
   144
  h1 = feval (fun1, x1, y1);
jwe@7220
   145
jwe@7220
   146
  set (ax(1), "ycolor", getcolor (h1(1)));
dbateman@7195
   147
  set (ax(1), "xlim", xlim);
dbateman@7195
   148
dbateman@7195
   149
  cf = gcf ();
dbateman@7195
   150
  set (cf, "nextplot", "add");
dbateman@8237
   151
dbateman@8237
   152
  if (ishandle(ax(2)) && strcmp (get (ax(2), "type"), "axes"))
dbateman@8237
   153
    axes (ax(2));
dbateman@8237
   154
  else
dbateman@8237
   155
    ax(2) = axes ();
dbateman@8237
   156
  endif
dbateman@7665
   157
  newplot ();
dbateman@7665
   158
dbateman@7195
   159
  colors = get (ax(1), "colororder");
dbateman@7195
   160
  set (ax(2), "colororder", [colors(2:end,:); colors(1,:)]);
dbateman@7195
   161
dbateman@7195
   162
  h2 = feval (fun2, x2, y2);
jwe@7206
   163
  set (ax(2), "yaxislocation", "right");
jwe@7220
   164
  set (ax(2), "ycolor", getcolor (h2(1)));
dbateman@7240
   165
  set (ax(2), "position", get (ax(1), "position"));
dbateman@7195
   166
  set (ax(2), "xlim", xlim);
dbateman@7240
   167
  set (ax(2), "color", "none");
jwe@8208
   168
jwe@8208
   169
  ## Add invisible text objects that when destroyed, 
jwe@8208
   170
  ## also remove the other axis
jwe@8208
   171
  t1 = text (0, 0, "", "parent", ax(1), "tag", "plotyy", 
jwe@8208
   172
	     "handlevisibility", "off", "visible", "off",
jwe@8208
   173
	     "xliminclude", "off", "yliminclude", "off");
jwe@8208
   174
  t2 = text (0, 0, "", "parent", ax(2), "tag", "plotyy", 
jwe@8208
   175
	     "handlevisibility", "off", "visible", "off",
jwe@8208
   176
	     "xliminclude", "off", "yliminclude", "off");
jwe@8208
   177
jwe@8208
   178
  set (t1, "deletefcn", {@deleteplotyy, ax(2), t2});
jwe@8208
   179
  set (t2, "deletefcn", {@deleteplotyy, ax(1), t1});
jwe@8208
   180
jwe@8208
   181
  addlistener (ax(1), "position", {@update_position, ax(2)});
jwe@8208
   182
  addlistener (ax(2), "position", {@update_position, ax(1)});
jwe@8208
   183
  addlistener (ax(1), "view", {@update_position, ax(2)});
jwe@8208
   184
  addlistener (ax(2), "view", {@update_position, ax(1)});
bpabbott@9337
   185
  addlistener (ax(1), "dataaspectratio", {@update_position, ax(2)});
bpabbott@9337
   186
  addlistener (ax(2), "dataaspectratio", {@update_position, ax(1)});
jwe@8208
   187
jwe@8208
   188
  ## Tag the plotyy axes, so we can use that information
jwe@8208
   189
  ## not to mirror the y axis tick marks
jwe@8208
   190
  set (ax, "tag", "plotyy")
jwe@8208
   191
bpabbott@9337
   192
  ## Store the axes handles for the sister axes.
bpabbott@9337
   193
  addproperty ("__plotyy_axes__", ax(1), "data", ax);
bpabbott@9337
   194
  addproperty ("__plotyy_axes__", ax(2), "data", ax);
bpabbott@9337
   195
jwe@8208
   196
endfunction
jwe@8208
   197
jwe@8208
   198
%!demo
bpabbott@8790
   199
%! clf
jwe@8208
   200
%! x = 0:0.1:2*pi; 
jwe@8208
   201
%! y1 = sin (x);
jwe@8208
   202
%! y2 = exp (x - 1);
jwe@8208
   203
%! ax = plotyy (x, y1, x - 1, y2, @plot, @semilogy);
jwe@8208
   204
%! xlabel ("X");
jwe@8208
   205
%! ylabel (ax(1), "Axis 1");
jwe@8208
   206
%! ylabel (ax(2), "Axis 2");
jwe@8208
   207
bpabbott@9337
   208
%!demo
bpabbott@9337
   209
%! clf
bpabbott@9337
   210
%! x = linspace (-1, 1, 201);
bpabbott@9337
   211
%! subplot (2, 2, 1)
bpabbott@9337
   212
%! plotyy (x, sin(pi*x), x, 10*cos(pi*x))
bpabbott@9337
   213
%! subplot (2, 2, 2)
bpabbott@9337
   214
%! surf (peaks (25))
bpabbott@9337
   215
%! subplot (2, 2, 3)
bpabbott@9337
   216
%! contour (peaks (25))
bpabbott@9337
   217
%! subplot (2, 2, 4)
bpabbott@9337
   218
%! plotyy (x, 10*sin(2*pi*x), x, cos(2*pi*x))
bpabbott@9337
   219
%! axis square
bpabbott@9337
   220
jwe@8208
   221
function deleteplotyy (h, d, ax2, t2)
jwe@8208
   222
  if (ishandle (ax2) && strcmp (get (ax2, "type"), "axes") && 
jwe@8208
   223
      (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off")) &&
jwe@8208
   224
      strcmp (get (ax2, "beingdeleted"), "off"))
jwe@8208
   225
    set (t2, "deletefcn", []);
jwe@8208
   226
    delete (ax2);
jwe@8208
   227
  endif
jwe@8208
   228
endfunction
jwe@8208
   229
jwe@8208
   230
function update_position (h, d, ax2)
jwe@8208
   231
  persistent recursion = false;
jwe@8208
   232
jwe@8208
   233
  ## Don't allow recursion
jwe@8208
   234
  if (! recursion)
jwe@8208
   235
    unwind_protect
jwe@8208
   236
      recursion = true;
jwe@8208
   237
      position = get (h, "position");
jwe@8208
   238
      view = get (h, "view");
bpabbott@9337
   239
      dataaspectratio = get (h, "dataaspectratio");
jwe@8208
   240
      oldposition = get (ax2, "position");
jwe@8208
   241
      oldview = get (ax2, "view");
bpabbott@9337
   242
      olddataaspectratio = get (ax2, "dataaspectratio");
bpabbott@9337
   243
      if (! (isequal (position, oldposition)
bpabbott@9337
   244
             && isequal (view, oldview)
bpabbott@9337
   245
             && isequal (dataaspectratio, olddataaspectratio)))
bpabbott@9337
   246
	set (ax2, "position", position,
bpabbott@9337
   247
                  "view", view,
bpabbott@9337
   248
		  "dataaspectratio", dataaspectratio);
jwe@8208
   249
      endif
jwe@8208
   250
    unwind_protect_cleanup
jwe@8208
   251
      recursion = false;
jwe@8208
   252
    end_unwind_protect
jwe@8208
   253
  endif  
dbateman@7195
   254
endfunction
jwe@7220
   255
jwe@7220
   256
function color = getcolor (ax)
jwe@7220
   257
  obj = get (ax);
jwe@7220
   258
  if (isfield (obj, "color"))
jwe@7220
   259
    color = obj.color;
jwe@7220
   260
  elseif (isfield (obj, "facecolor") && ! ischar (obj.facecolor))
jwe@7220
   261
    color = obj.facecolor;
jwe@7220
   262
  elseif (isfield (obj, "edgecolor") && !  ischar (obj.edgecolor))
jwe@7220
   263
    color = obj.edgecolor;
jwe@7220
   264
  else
jwe@7220
   265
    color = [0, 0, 0];
jwe@7220
   266
  endif
jwe@7220
   267
endfunction
jwe@7245
   268