view scripts/plot/util/private/__gnuplot_draw_axes__.m @ 31253:a40c0b7aa376

maint: changes to follow Octave coding conventions. * NEWS.8.md: Wrap lines to 72 chars. * LSODE-opts.in: Use two spaces after sentence ending period. * LSODE.cc: Use minimum of two spaces between code and start of comment. * MemoizedFunction.m: Change copyright date to 2022 since this is the year it was accepted into core. Don't wrap error() lines to 80 chars. Use newlines to improve readability of switch statements. Use minimum of two spaces between code and start of comment. * del2.m, integral.m, interp1.m, interp2.m, griddata.m, inpolygon.m, waitbar.m, cubehelix.m, ind2x.m, importdata.m, textread.m, logm.m, lighting.m, shading.m, xticklabels.m, yticklabels.m, zticklabels.m, colorbar.m, meshc.m, print.m, __gnuplot_draw_axes__.m, struct2hdl.m, ppval.m, ismember.m, iqr.m: Use a space between comment character '#' and start of comment. Use hyphen for adjectives describing dimensions such as "1-D". * vectorize.m, ode23s.m: Use is_function_handle() instead of "isa (x, "function_handle")" for clarity and performance. * clearAllMemoizedCaches.m: Change copyright date to 2022 since this is the year it was accepted into core. Remove input validation which is done by interpreter. Use two newlines between end of code and start of BIST tests. * memoize.m: Change copyright date to 2022 since this is the year it was accepted into core. Re-wrap documentation to 80 chars. Use is_function_handle() instead of "isa (x, "function_handle")" for clarity and performance. Use two newlines between end of code and start of BIST tests. Use semicolon for assert statements within %!test block. Re-write BIST tests for input validation. * __memoize__.m: Change copyright date to 2022 since this is the year it was accepted into core. Use spaces in for statements to improve readability. * unique.m: Add FIXME note to commented BIST test * dec2bin.m: Remove stray newline at end of file. * triplequad.m: Reduce doubly-commented BIST syntax using "#%!#" to "#%!". * delaunayn.m: Use input variable names in error() statements. Use minimum of two spaces between code and start of comment. Use hyphen for describing dimensions. Use two newlines between end of code and start of BIST tests. Update BIST tests to pass.
author Rik <rik@octave.org>
date Mon, 03 Oct 2022 18:06:55 -0700
parents 796f54d4ddbf
children 597f3ee61a48
line wrap: on
line source

########################################################################
##
## Copyright (C) 2005-2022 The Octave Project Developers
##
## See the file COPYRIGHT.md in the top-level directory of this
## distribution or <https://octave.org/copyright/>.
##
## This file is part of Octave.
##
## Octave 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 3 of the License, or
## (at your option) any later version.
##
## Octave 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 Octave; see the file COPYING.  If not, see
## <https://www.gnu.org/licenses/>.
##
########################################################################

## -*- texinfo -*-
## @deftypefn {} {} __gnuplot_draw_axes__ (@var{h}, @var{plot_stream}, @var{enhanced}, @var{bg_is_set}, @var{fg_is_set}, @var{hlgnd})
## Undocumented internal function.
## @end deftypefn

function __gnuplot_draw_axes__ (h, plot_stream, enhanced, bg_is_set,
                                fg_is_set, hlgnd)

  showhiddenhandles = get (0, "showhiddenhandles");
  unwind_protect
    set (0, "showhiddenhandles", "on");
    axis_obj = __get__ (h);
  unwind_protect_cleanup
    set (0, "showhiddenhandles", showhiddenhandles);
  end_unwind_protect

  parent_figure_obj = get (axis_obj.parent);
  gnuplot_term = __gnuplot_get_var__ (axis_obj.parent, "GPVAL_TERM");

  ## Set to false for plotyy axes.
  ymirror = true;
  if (isfield (axis_obj, "__plotyy_axes__"))
    if (all (ishghandle (axis_obj.__plotyy_axes__)))
      ymirror = false;
    else
      h = axis_obj.__plotyy_axes__;
      h = h(ishghandle (h));
      h = h(isprop (h, "__plotyy_axes__"));
      rmappdata (h, "__plotyy_axes__");
    endif
  endif

  nd = __calc_dimensions__ (h);
  if (nd == 2 && (any (get (h, "view") != [0, 90])))
    ## view() only works correctly on 3-D axes in gnuplot (bug #58526).
    nd = 3;
  endif

  if (strcmp (axis_obj.dataaspectratiomode, "manual")
      && strcmp (axis_obj.xlimmode, "manual")
      && strcmp (axis_obj.ylimmode, "manual"))
    ## All can't be "manual"
    axis_obj.plotboxaspectratiomode = "auto";
  endif

  if (strcmp (axis_obj.dataaspectratiomode, "manual")
      && strcmp (axis_obj.xlimmode, "manual")
      && strcmp (axis_obj.ylimmode, "manual")
      && (nd == 2 || all (mod (axis_obj.view, 90) == 0)))
    ## FIXME: adjust plotboxaspectratio to respect other
    fpos = get (axis_obj.parent, "position");
    apos = axis_obj.position;
  endif

  pos = __actual_axis_position__ (h);

  if (strcmp (axis_obj.dataaspectratiomode, "manual"))
    dr = axis_obj.dataaspectratio;
    if (nd == 2 || all (mod (axis_obj.view, 90) == 0))
      dr = dr(1) / dr(2);
    else
      ## FIXME: need to properly implement 3-D
      dr = mean (dr(1:2)) / dr(3);
    endif
  else
    dr = 1;
  endif

  if (strcmp (axis_obj.positionconstraint, "innerposition"))
    if (nd == 2 || all (mod (axis_obj.view, 90) == 0))
      x = [1, 1];
    else
      ## 3-D plots need to be sized down to fit in the window.
      x = 1.0 ./ sqrt ([2, 2.5]);
    endif
    fprintf (plot_stream, "set tmargin screen %.15g;\n",
             pos(2)+pos(4)/2+x(2)*pos(4)/2);
    fprintf (plot_stream, "set bmargin screen %.15g;\n",
             pos(2)+pos(4)/2-x(2)*pos(4)/2);
    fprintf (plot_stream, "set lmargin screen %.15g;\n",
             pos(1)+pos(3)/2-x(1)*pos(3)/2);
    fprintf (plot_stream, "set rmargin screen %.15g;\n",
             pos(1)+pos(3)/2+x(1)*pos(3)/2);
    sz_str = "";
  else  # positionconstraint == outerposition
    fprintf (plot_stream, "unset tmargin;\n");
    fprintf (plot_stream, "unset bmargin;\n");
    fprintf (plot_stream, "unset lmargin;\n");
    fprintf (plot_stream, "unset rmargin;\n");
    fprintf (plot_stream, "set origin %g, %g;\n", pos(1:2));
    if (strcmp (axis_obj.dataaspectratiomode, "manual"))
      sz_str = sprintf ("ratio %g", -dr);
    else
      sz_str = "noratio";
    endif
    sz_str = sprintf ("set size %s %g, %g;\n", sz_str, pos(3:4));
  endif
  if (! isempty (sz_str))
    fputs (plot_stream, sz_str);
  endif

  ## Code above uses axis size for the data aspect ratio, which isn't
  ## quite correct.  The only fine control is to set all axes units equal.
  if (nd == 3
      && strcmp (axis_obj.dataaspectratiomode, "manual")
      && axis_obj.dataaspectratio(1) == axis_obj.dataaspectratio(2))
    if (axis_obj.dataaspectratio(1) == axis_obj.dataaspectratio(3))
      zstr = "z";
    else
      zstr = "";
    endif
    fprintf (plot_stream, "set view equal xy%s;\n", zstr);
  endif

  ## Reset all labels, axis-labels, tick-labels, and title
  ## FIXME: We should have an function to initialize the axis.
  ##        Presently, this is dispersed in this function.
  fputs (plot_stream, "unset label;\n");
  fputs (plot_stream, "unset arrow;\n");
  fputs (plot_stream, "unset xtics;\n");
  fputs (plot_stream, "unset ytics;\n");
  fputs (plot_stream, "unset ztics;\n");
  fputs (plot_stream, "unset x2tics;\n");
  fputs (plot_stream, "unset y2tics;\n");

  if (isempty (axis_obj.title) || isempty (get (axis_obj.title, "string")))
    fputs (plot_stream, "unset title;\n");
  else
    if (nd == 2)
      t = get (axis_obj.title);
      colorspec = get_text_colorspec (t.color);
      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", ...
                                         t.interpreter, gnuplot_term);
      fontspec = create_fontspec (f, s, gnuplot_term);
      fprintf (plot_stream, ['set title "%s" %s %s %s;' "\n"],
               tt, fontspec, colorspec, __do_enhanced_option__ (enhanced, t));
    else
      ## Change meaning of "normalized", but it at least gives user some control
      if (! strcmp (get (axis_obj.title, "units"), "normalized"))
        unwind_protect
          set (axis_obj.title, "units", "normalized",
                               "position", [0.5 1.02 0.5]);
        unwind_protect_cleanup
        end_unwind_protect
      endif
      t = get (axis_obj.title);
      axispos = axis_obj.position;
      screenpos = t.position;
      screenpos(1) = axispos(1)+screenpos(1)*axispos(3);
      screenpos(2) = axispos(2)+screenpos(2)*axispos(4);
      fputs (plot_stream, "unset title;\n");
      do_text (plot_stream, gnuplot_term, enhanced, t, h, screenpos);
    endif
  endif

  if (! isempty (axis_obj.xlabel))
    t = get (axis_obj.xlabel);
    angle = t.rotation;
    colorspec = get_text_colorspec (t.color);
    if (isempty (t.string))
      fprintf (plot_stream, "unset xlabel;\n");
      fprintf (plot_stream, "unset x2label;\n");
    else
      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", ...
                                         t.interpreter, gnuplot_term);
      fontspec = create_fontspec (f, s, gnuplot_term);
      if (strcmp (axis_obj.xaxislocation, "top"))
        fprintf (plot_stream, 'set x2label "%s" %s %s %s',
                 tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
      else
        fprintf (plot_stream, 'set xlabel "%s" %s %s %s',
                 tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
      endif
      fprintf (plot_stream, " rotate by %f;\n", angle);
      if (strcmp (axis_obj.xaxislocation, "top"))
        fprintf (plot_stream, "unset xlabel;\n");
      else
        fprintf (plot_stream, "unset x2label;\n");
      endif
    endif
  endif

  if (! isempty (axis_obj.ylabel))
    t = get (axis_obj.ylabel);
    angle = t.rotation;
    colorspec = get_text_colorspec (t.color);
    if (isempty (t.string))
      fprintf (plot_stream, "unset ylabel;\n");
      fprintf (plot_stream, "unset y2label;\n");
    else
      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", ...
                                         t.interpreter, gnuplot_term);
      fontspec = create_fontspec (f, s, gnuplot_term);
      if (strcmp (axis_obj.yaxislocation, "right"))
        fprintf (plot_stream, 'set y2label "%s" %s %s %s',
                 tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
      else
        fprintf (plot_stream, 'set ylabel "%s" %s %s %s',
                 tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
      endif
      fprintf (plot_stream, " rotate by %f;\n", angle);
      if (strcmp (axis_obj.yaxislocation, "right"))
        fprintf (plot_stream, "unset ylabel;\n");
      else
        fprintf (plot_stream, "unset y2label;\n");
      endif
    endif
  endif

  if (! isempty (axis_obj.zlabel))
    t = get (axis_obj.zlabel);
    angle = t.rotation;
    colorspec = get_text_colorspec (t.color);
    if (isempty (t.string))
      fputs (plot_stream, "unset zlabel;\n");
    else
      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", ...
                                         t.interpreter, gnuplot_term);
      fontspec = create_fontspec (f, s, gnuplot_term);
      fprintf (plot_stream, 'set zlabel "%s" %s %s %s',
               tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
      fprintf (plot_stream, " rotate by %f;\n", angle);
    endif
  endif

  if (strcmp (axis_obj.xaxislocation, "top"))
    xaxisloc = "x2";
    xaxisloc_using = "x2";
  else
    xaxisloc = "x";
    xaxisloc_using = "x1";
    if (strcmp (axis_obj.xaxislocation, "origin"))
      fputs (plot_stream, "set xzeroaxis;\n");
    endif
  endif
  if (strcmp (axis_obj.yaxislocation, "right"))
    yaxisloc = "y2";
    yaxisloc_using = "y2";
  else
    yaxisloc = "y";
    yaxisloc_using = "y1";
    if (strcmp (axis_obj.yaxislocation, "origin"))
      fputs (plot_stream, "set yzeroaxis;\n");
    endif
  endif

  have_major_grid = false;
  have_minor_grid = false;
  visible_gls = ! strcmp (axis_obj.gridlinestyle, "none") ...
                && ! strcmp (axis_obj.gridcolor, "none");
  visible_mgls = ! strcmp (axis_obj.minorgridlinestyle, "none") ...
                 && ! strcmp (axis_obj.minorgridcolor, "none");

  if (strcmp (axis_obj.xgrid, "on") && visible_gls)
    have_major_grid = true;
    fprintf (plot_stream, "set grid %stics;\n", xaxisloc);
  else
    fprintf (plot_stream, "set grid no%stics;\n", xaxisloc);
  endif

  if (strcmp (axis_obj.ygrid, "on") && visible_gls)
    have_major_grid = true;
    fprintf (plot_stream, "set grid %stics;\n", yaxisloc);
  else
    fprintf (plot_stream, "set grid no%stics;\n", yaxisloc);
  endif

  if (strcmp (axis_obj.zgrid, "on") && visible_gls)
    have_major_grid = true;
    fputs (plot_stream, "set grid ztics;\n");
  else
    fputs (plot_stream, "set grid noztics;\n");
  endif

  if (strcmp (axis_obj.xminorgrid, "on") && visible_mgls)
    have_minor_grid = true;
    if (strcmp (axis_obj.xscale, "log"))
      m = 10;
    else
      m = 5;
    endif
    fprintf (plot_stream, "set m%stics %d;\n", xaxisloc, m);
    fprintf (plot_stream, "set grid m%stics;\n", xaxisloc);
  else
    fprintf (plot_stream, "set grid nom%stics;\n", xaxisloc);
  endif

  if (strcmp (axis_obj.yminorgrid, "on") && visible_mgls)
    have_minor_grid = true;
    if (strcmp (axis_obj.yscale, "log"))
      m = 10;
    else
      m = 5;
    endif
    fprintf (plot_stream, "set m%stics %d;\n", yaxisloc, m);
    fprintf (plot_stream, "set grid m%stics;\n", yaxisloc);
  else
    fprintf (plot_stream, "set grid nom%stics;\n", yaxisloc);
  endif

  if (strcmp (axis_obj.zminorgrid, "on") && visible_mgls)
    have_minor_grid = true;
    if (strcmp (axis_obj.zscale, "log"))
      m = 10;
    else
      m = 5;
    endif
    fprintf (plot_stream, "set mztics %d;\n", m);
    fputs (plot_stream, "set grid mztics;\n");
  else
    fputs (plot_stream, "set grid nomztics;\n");
  endif

  ## The grid front/back/layerdefault option also controls the
  ## appearance of tics, so it is used even if the grid is absent.
  if (strcmp (axis_obj.layer, "top"))
    fputs (plot_stream, "set grid front;\n");
    fputs (plot_stream, "set border front;\n");
  else
    fputs (plot_stream, "set grid layerdefault;\n");
  endif

  xlogscale = strcmp (axis_obj.xscale, "log");
  ylogscale = strcmp (axis_obj.yscale, "log");
  zlogscale = strcmp (axis_obj.zscale, "log");

  ## Detect logscale and negative lims
  if (xlogscale && all (axis_obj.xlim < 0))
    axis_obj.xsgn = -1;
    if (strcmp (axis_obj.xdir, "reverse"))
      axis_obj.xdir = "normal";
    elseif (strcmp (axis_obj.xdir, "normal"))
      axis_obj.xdir = "reverse";
    endif
    axis_obj.xtick = -flip (axis_obj.xtick);
    axis_obj.xticklabel = flip (axis_obj.xticklabel);
    axis_obj.xlim = -flip (axis_obj.xlim);
  else
    axis_obj.xsgn = 1;
  endif
  if (ylogscale && all (axis_obj.ylim < 0))
    axis_obj.ysgn = -1;
    if (strcmp (axis_obj.ydir, "reverse"))
      axis_obj.ydir = "normal";
    elseif (strcmp (axis_obj.ydir, "normal"))
      axis_obj.ydir = "reverse";
    endif
    axis_obj.ytick = -flip (axis_obj.ytick);
    axis_obj.yticklabel = flip (axis_obj.yticklabel);
    axis_obj.ylim = -flip (axis_obj.ylim);
  else
    axis_obj.ysgn = 1;
  endif
  if (zlogscale && all (axis_obj.zlim < 0))
    axis_obj.zsgn = -1;
    if (strcmp (axis_obj.zdir, "reverse"))
      axis_obj.zdir = "normal";
    elseif (strcmp (axis_obj.zdir, "normal"))
      axis_obj.zdir = "reverse";
    endif
    axis_obj.ztick = -flip (axis_obj.ztick);
    axis_obj.zticklabel = flip (axis_obj.zticklabel);
    axis_obj.zlim = -flip (axis_obj.zlim);
  else
    axis_obj.zsgn = 1;
  endif

  xlim = axis_obj.xlim;
  ylim = axis_obj.ylim;
  zlim = axis_obj.zlim;
  clim = axis_obj.clim;

  do_tics (axis_obj, plot_stream, ymirror, gnuplot_term);

  fputs (plot_stream, "unset logscale;\n");
  if (xlogscale)
    fprintf (plot_stream, "set logscale %s;\n", xaxisloc);
  endif
  if (ylogscale)
    fprintf (plot_stream, "set logscale %s;\n", yaxisloc);
  endif
  if (zlogscale)
    fputs (plot_stream, "set logscale z;\n");
  endif

  xautoscale = strcmp (axis_obj.xlimmode, "auto");
  yautoscale = strcmp (axis_obj.ylimmode, "auto");
  zautoscale = strcmp (axis_obj.zlimmode, "auto");
  cautoscale = strcmp (axis_obj.climmode, "auto");

  fputs (plot_stream, "set clip two;\n");

  kids = axis_obj.children;
  ## Remove the axis labels and title from the children, and
  ## preserved the original order.
  [jnk, k] = setdiff (kids, [axis_obj.xlabel; axis_obj.ylabel; ...
                             axis_obj.zlabel; axis_obj.title]);
  kids = kids(sort (k));

  if (nd == 3)
    fputs (plot_stream, "set parametric;\n");
    fputs (plot_stream, "set style data lines;\n");
    fputs (plot_stream, "set surface;\n");
    fputs (plot_stream, "unset contour;\n");
  endif

  data_idx = 0;
  data = cell ();
  is_image_data = [];
  hidden_removal = NaN;
  view_map = false;

  if (cautoscale)
    ## First pass to get cdata limits, maybe general graphics should do this
    kids1 = kids;
    clim = [Inf -Inf];

    while (! isempty (kids1))
      obj = get (kids1(end));
      kids1 = kids1(1:(end-1));

      switch (obj.type)
        case {"image", "patch", "surface"}
          if (isfield (obj, "cdatamapping")
              && strcmp (obj.cdatamapping, "scaled")
              && isfield (obj, "cdata")
              && ! isempty (obj.cdata))
            clim(1) = min (clim(1), min (obj.cdata(:)));
            clim(2) = max (clim(2), max (obj.cdata(:)));
          endif

        case "hggroup"
          ## Push group children into the kid list.
          if (isempty (kids1))
            kids1 = obj.children;
          elseif (! isempty (obj.children))
            kids1 = [kids1; obj.children];
          endif
      endswitch
    endwhile

    if (clim(1) == Inf)
      clim = axis_obj.clim;
    endif

  elseif (clim(1) == clim(2))
    clim(2)++;
  endif

  if (rows (parent_figure_obj.colormap) != 2)
    kids1 = kids;
    while (! isempty (kids1))
      obj = get (kids1(end));
      kids1 = kids1(1:(end-1));

      switch (obj.type)
        case "hggroup"
          ## Push group children into the kid list.
          if (isempty (kids1))
            kids1 = obj.children;
          elseif (! isempty (obj.children))
            kids1 = [kids1; obj.children];
          endif
      endswitch
    endwhile
  endif

  cmap = axis_obj.colormap;
  cmap_sz = rows (cmap);
  addedcmap = [];

  ximg_data = {};
  ximg_data_idx = 0;

  if (! isempty (hlgnd))
    hlgndntrp = hlgnd.interpreter;
  else
    hlgndntrp = "none";
  endif

  while (! isempty (kids))

    h_obj = kids(end);
    kids = kids(1:(end-1));

    obj = get (h_obj);

    if (isfield (obj, "xdata"))
      obj.xdata = double (obj.xdata);
    endif
    if (isfield (obj, "ydata"))
      obj.ydata = double (obj.ydata);
    endif
    if (isfield (obj, "zdata"))
      obj.zdata = double (obj.zdata);
    endif

    if (strcmp (obj.type, "text"))
      units = obj.units;
      unwind_protect
        set (h_obj, "units", "data");
        obj = get (h_obj);
      unwind_protect_cleanup
        set (h_obj, "units", units);
      end_unwind_protect
    endif

    if (strcmp (obj.visible, "off"))
      continue;
    endif

    if (xlogscale && isfield (obj, "xdata"))
      obj.xdata = axis_obj.xsgn * obj.xdata;
      obj.xdata(obj.xdata<=0) = NaN;
    endif
    if (ylogscale && isfield (obj, "ydata"))
      obj.ydata = axis_obj.ysgn * obj.ydata;
      obj.ydata(obj.ydata<=0) = NaN;
    endif
    if (zlogscale && isfield (obj, "zdata"))
      obj.zdata = axis_obj.zsgn * obj.zdata;
      obj.zdata(obj.zdata<=0) = NaN;
    endif

    switch (obj.type)
      case "image"
        img_data = mapcdata (obj.cdata, obj.cdatamapping, clim, cmap_sz);
        img_xdata = obj.xdata;
        img_ydata = obj.ydata;

        data_idx += 1;
        is_image_data(data_idx) = true;
        parametric(data_idx) = false;
        have_cdata(data_idx) = false;
        have_3d_patch(data_idx) = false;

        if (img_xdata(2) < img_xdata(1))
          img_xdata = img_xdata(2:-1:1);
          img_data = img_data(:,end:-1:1,:);
        elseif (img_xdata(1) == img_xdata(2))
          img_xdata = img_xdata(1) + [0, columns(img_data)-1];
        endif
        if (img_ydata(2) < img_ydata(1))
          img_ydata = img_ydata(2:-1:1);
          img_data = img_data(end:-1:1,:,:);
        elseif (img_ydata(1) == img_ydata(2))
          img_ydata = img_ydata(1) + [0, rows(img_data)-1];
        endif

        x_origin = min (img_xdata);
        y_origin = min (img_ydata);

        [y_dim, x_dim] = size (img_data(:,:,1));
        if (x_dim > 1)
          dx = abs (img_xdata(2)-img_xdata(1))/(x_dim-1);
        else
          x_dim = 2;
          img_data = [img_data, img_data];
          dx = abs (img_xdata(2)-img_xdata(1));
          if (dx < 1)
            ## Correct gnuplot string for 1-D images
            dx       = 0.5;
            x_origin = 0.75;
          endif
        endif
        if (y_dim > 1)
          dy = abs (img_ydata(2)-img_ydata(1))/(y_dim-1);
        else
          y_dim = 2;
          img_data = [img_data; img_data];
          dy = abs (img_ydata(2)-img_ydata(1));
          if (dy < 1)
            ## Correct gnuplot string for 1-D images
            dy       = 0.5;
            y_origin = 0.75;
          endif
        endif

        if (ndims (img_data) == 3)
          data{data_idx} = permute (img_data, [3, 1, 2])(:);
          format = "1:2:3";
          imagetype = "rgbimage";
        else
          data{data_idx} = img_data(:);
          format = "1";
          imagetype = "image";
        endif

        titlespec{data_idx} = 'title ""';
        usingclause{data_idx} = sprintf ("binary array=%dx%d scan=yx origin=(%.15g,%.15g) dx=%.15g dy=%.15g using %s",
            x_dim, y_dim, x_origin, y_origin, dx, dy, format);
        withclause{data_idx} = sprintf ("with %s", imagetype);

      case "line"
        if (strcmp (get (obj.parent, "type"), "hggroup"))
          hg = get (obj.parent, "children");
          if (hg(1) == h_obj && ! isempty (get (obj.parent, "displayname")))
            data_idx += 1;
            is_image_data(data_idx) = false;
            parametric(data_idx) = false;
            have_cdata(data_idx) = false;
            have_3d_patch(data_idx) = false;
            tmpdispname = obj.displayname;
            obj.displayname = get (obj.parent, "displayname");
            tmp = __maybe_munge_text__ (enhanced, obj, "displayname", ...
                                        hlgndntrp, gnuplot_term);
            titlespec{data_idx} = ['title "' tmp '"'];
            obj.displayname = tmpdispname;
            if (! isempty (findobj (obj.parent, "-property", "format", "-depth", 0)))
              ## Place phantom errorbar data for legend
              data{data_idx} = NaN (4,1);
              usingclause{data_idx} = sprintf ("record=1 using ($1):($2):($3):($4)");
              switch (get (obj.parent, "format"))
                case {"box" "boxy" "boxxy"}
                  errbars = "boxxy";
                case "xyerr"
                  errbars = "xyerrorbars";
                case "yerr"
                  errbars = "yerrorbars";
                case "xerr"
                  errbars = "xerrorbars";
                otherwise
                  errbars = "xerrorbars";
              endswitch
              withclause{data_idx} = sprintf ("with %s linestyle %d", ...
                                              errbars, sidx(1));
            else
              ## Place phantom stemseries data for legend
              data{data_idx} = NaN (2,1);
              usingclause{data_idx} = sprintf ("record=1 using ($1):($2)");
              hgobj = get (obj.parent);
              [hgstyle, hgsidx] = do_linestyle_command (hgobj, hgobj.color, ...
                                                        data_idx, plot_stream);
              withclause{data_idx} = sprintf ("with %s linestyle %d",
                                              hgstyle{1}, hgsidx(1));
            endif
          endif
        endif

        if (strcmp (obj.linestyle, "none")
            && (! isfield (obj, "marker")
                || (isfield (obj, "marker")
                    && strcmp (obj.marker, "none"))))
          continue;
        endif
        data_idx += 1;
        is_image_data(data_idx) = false;
        parametric(data_idx) = true;
        have_cdata(data_idx) = false;
        have_3d_patch(data_idx) = false;
        if (isempty (obj.displayname))
          titlespec{data_idx} = 'title ""';
        else
          tmp = __maybe_munge_text__ (enhanced, obj, "displayname", ...
                                      hlgndntrp, gnuplot_term);
          titlespec{data_idx} = ['title "' tmp '"'];
        endif
        usingclause{data_idx} = sprintf ("record=%d", numel (obj.xdata));
        if (nd == 3)
          xdat = obj.xdata(:);
          ydat = obj.ydata(:);
          if (! isempty (obj.zdata))
            zdat = obj.zdata(:);
          else
            zdat = zeros (size (xdat));
          endif
          data{data_idx} = [xdat, ydat, zdat]';
          usingclause{data_idx} = sprintf ("record=%d using ($1):($2):($3)",
                                           numel (xdat));
          ## fputs (plot_stream, "set parametric;\n");
        else
          xdat = obj.xdata(:);
          ydat = obj.ydata(:);
          data{data_idx} = [xdat, ydat]';
          usingclause{data_idx} = ...
            sprintf ("record=%d using ($1):($2) axes %s%s",
                     rows (xdat), xaxisloc_using, yaxisloc_using);
        endif

        [style, sidx] = do_linestyle_command (obj, obj.color, data_idx,
                                              plot_stream);

        if (isempty (style{1}))
          style{1} = "points";
          data{data_idx} = {};
        endif
        withclause{data_idx} = sprintf ("with %s linestyle %d",
                                        style{1}, sidx(1));

        if (length (style) > 1)
          data_idx += 1;
          is_image_data(data_idx) = is_image_data(data_idx - 1);
          parametric(data_idx) = parametric(data_idx - 1);
          have_cdata(data_idx) = have_cdata(data_idx - 1);
          have_3d_patch(data_idx) = have_3d_patch(data_idx - 1);
          titlespec{data_idx} = 'title ""';
          usingclause{data_idx} = usingclause{data_idx - 1};
          data{data_idx} = data{data_idx - 1};
          withclause{data_idx} = sprintf ("with %s linestyle %d",
                                          style{2}, sidx(2));
        endif
        if (length (style) > 2)
          data_idx += 1;
          is_image_data(data_idx) = is_image_data(data_idx - 1);
          parametric(data_idx) = parametric(data_idx - 1);
          have_cdata(data_idx) = have_cdata(data_idx - 1);
          have_3d_patch(data_idx) = have_3d_patch(data_idx - 1);
          titlespec{data_idx} = 'title ""';
          usingclause{data_idx} = usingclause{data_idx - 1};
          data{data_idx} = data{data_idx - 1};
          withclause{data_idx} = sprintf ("with %s linestyle %d",
                                          style{3}, sidx(3));
        endif

      case "patch"
        persistent do_interp_warning = true;

        if (strcmp (get (obj.parent, "type"), "hggroup"))
          obj.displayname = get (obj.parent, "displayname");
        endif

        [nr, nc] = size (obj.xdata);

        if (! isempty (obj.cdata))
          cdat = obj.cdata;
        else
          cdat = [];
        endif

        data_3d_idx = NaN;
        for i = 1:nc
          xcol = obj.xdata(:,i);
          ycol = obj.ydata(:,i);
          if (nd == 3)
            if (! isempty (obj.zdata))
              zcol = obj.zdata(:,i);
            else
              zcol = zeros (size (xcol));
            endif
          endif

          if (! isnan (xcol) && ! isnan (ycol))
            ## Is the patch closed or not
            if (! strcmp (obj.facecolor, "none"))
              hidden_removal = true;
              if (nd == 3)
                if (numel (xcol) > 3)
                  error ("__gnuplot_draw_axes__: gnuplot (as of v4.2) only supports 3-D filled triangular patches");
                else
                  if (isnan (data_3d_idx))
                    data_idx += 1;
                    data_3d_idx = data_idx;
                    is_image_data(data_idx) = false;
                    parametric(data_idx) = false;
                    have_cdata(data_idx) = true;
                    have_3d_patch(data_idx) = true;
                    withclause{data_3d_idx} = sprintf ("with pm3d");
                    usingclause{data_3d_idx} =  "using 1:2:3:4";
                    data{data_3d_idx} = [];
                  endif
                  local_idx = data_3d_idx;
                  ccdat = NaN;
                endif
              else
                data_idx += 1;
                local_idx = data_idx;
                is_image_data(data_idx) = false;
                parametric(data_idx) = false;
                have_cdata(data_idx) = false;
                have_3d_patch(data_idx) = false;
              endif

              if (i > 1 || isempty (obj.displayname))
                titlespec{local_idx} = 'title ""';
              else
                tmp = __maybe_munge_text__ (enhanced, obj, "displayname", ...
                                            hlgndntrp, gnuplot_term);
                titlespec{local_idx} = ['title "' tmp '"'];
              endif
              if (isfield (obj, "facecolor"))
                if ((strcmp (obj.facecolor, "flat")
                    || strcmp (obj.facecolor, "interp"))
                    && isfield (obj, "cdata"))
                  if (ndims (obj.cdata) == 2
                      && (columns (obj.cdata) == nc
                          && (rows (obj.cdata) == 1
                              || rows (obj.cdata) == 3)))
                    ccol = cdat(:, i);
                  elseif (ndims (obj.cdata) == 2
                      && (rows (obj.cdata) == nc
                          && (columns (obj.cdata) == 1
                              || columns (obj.cdata) == 3)))
                    ccol = cdat(i, :);
                  elseif (ndims (obj.cdata) == 3)
                    ccol = permute (cdat (:, i, :), [1, 3, 2]);
                  else
                    ccol = cdat;
                  endif
                  if (strcmp (obj.facecolor, "flat"))
                    if (isequal (size (ccol), [1, 3]))
                      ## RGB Triplet
                      color = ccol;
                    else
                      ccdat = mapcdata (ccol, obj.cdatamapping, clim, cmap_sz);
                      if (nd == 3 && numel (xcol) == 3)
                        color = cmap(ccdat(1), :);
                      else
                        color = cmap(ccdat, :);
                      endif
                    endif
                  elseif (strcmp (obj.facecolor, "interp"))
                    if (nd == 3 && numel (xcol) == 3)
                      ccdat = ccol;
                      if (! isvector (ccdat))
                        tmp = cmap_sz + rows (addedcmap) + ...
                             [1 : rows(ccdat)];
                        addedcmap = [addedcmap; ccdat];
                        ccdat = tmp(:);
                      else
                        ccdat = mapcdata (ccdat(:), obj.cdatamapping, clim, cmap_sz);
                      endif
                    else
                      if (do_interp_warning && sum (diff (ccol)))
                        warning ('"interp" not supported, using 1st entry of cdata');
                        do_interp_warning = false;
                      endif
                      r = mapcdata (ccol, obj.cdatamapping, clim, cmap_sz);
                      color = cmap(r(1),:);
                    endif
                  endif
                elseif (isnumeric (obj.facecolor))
                  color = obj.facecolor;
                else
                  color = [0, 1, 0];
                endif
              else
                color = [0, 1, 0];
              endif

              if (nd == 3 && numel (xcol) == 3)
                if (isnan (ccdat))
                  ccdat = (cmap_sz + rows (addedcmap) + 1) * ones (3, 1);
                  addedcmap = [addedcmap; reshape(color, 1, 3)];
                elseif (numel (ccdat) == 1)
                  ccdat = ccdat * ones (size (zcol));
                elseif (numel (ccdat) < 1)
                  ccdat = zcol;
                endif
                data{data_3d_idx} = [data{data_3d_idx}, ...
                                     [[xcol; xcol(end)], [ycol; ycol(end)], ...
                                     [zcol; zcol(end)], [ccdat; ccdat(end)]]'];
              else
                if (isscalar (obj.facealpha))
                  colorspec = sprintf ('lc rgb "#%02x%02x%02x" fillstyle transparent solid %f',
                                       round (255*color), obj.facealpha);
                else
                  colorspec = sprintf ('lc rgb "#%02x%02x%02x"',
                                       round (255*color));
                endif

                withclause{data_idx} = sprintf ("with filledcurve %s",
                                              colorspec);
                data{data_idx} = [xcol, ycol]';
                usingclause{data_idx} = sprintf ("record=%d using ($1):($2)",
                                                 numel (xcol));
              endif
            endif
          endif

          ## patch outline
          if (!(strcmp (obj.edgecolor, "none")
                 && (strcmp (obj.marker, "none")
                     || (strcmp (obj.markeredgecolor, "none")
                         && strcmp (obj.markerfacecolor, "none")))))

            data_idx += 1;
            is_image_data(data_idx) = false;
            parametric(data_idx) = false;
            have_cdata(data_idx) = false;
            have_3d_patch(data_idx) = false;
            titlespec{data_idx} = 'title ""';
            usingclause{data_idx} = sprintf ("record=%d", numel (obj.xdata));

            if (isfield (obj, "markersize"))
              mdat = obj.markersize / 3;
            endif

            if (isfield (obj, "edgecolor"))
              ## FIXME: This is the wrong thing to do as edgecolor,
              ## markeredgecolor and markerfacecolor can have different values
              ## and we should treat them separately.  However, the code below
              ## allows the scatter functions to work as expected, where only
              ## one of these values is set.
              if (strcmp (obj.edgecolor, "none"))
                if (strcmp (obj.markeredgecolor, "none"))
                  ec = obj.markerfacecolor;
                else
                  ec = obj.markeredgecolor;
                endif
              else
                ec = obj.edgecolor;
              endif

              if ((strcmp (ec, "flat") || strcmp (ec, "interp"))
                  && isfield (obj, "cdata"))
                if (ndims (obj.cdata) == 2
                    && (columns (obj.cdata) == nc
                        && (rows (obj.cdata) == 1
                            || rows (obj.cdata) == 3)))
                  ccol = cdat(:, i);
                elseif (ndims (obj.cdata) == 2
                        && (rows (obj.cdata) == nc
                            && (columns (obj.cdata) == 1
                                || columns (obj.cdata) == 3)))
                  ccol = cdat(i, :);
                elseif (ndims (obj.cdata) == 3)
                  ccol = permute (cdat (:, i, :), [1, 3, 2]);
                else
                  ccol = cdat;
                endif
                if (strcmp (ec, "flat"))
                  if (isequal (size (ccol), [1, 3]))
                    color = ccol;
                  else
                    if (columns (ccol) != 3)
                      ccol = mapcdata (ccol, obj.cdatamapping, clim, cmap_sz);
                    endif
                    if (isscalar (ccol))
                      ccol = repmat (ccol, numel (xcol), 1);
                    endif
                    color = "flat";
                    have_cdata(data_idx) = true;
                  endif
                elseif (strcmp (ec, "interp"))
                  if (do_interp_warning && numel (ccol) == 3)
                    warning ('"interp" not supported, using 1st entry of cdata');
                    do_interp_warning = false;
                    color = mapcdata (ccol(:), obj.cdatamapping, clim, cmap_sz);
                  else
                    if (isscalar (ccol))
                      ccol = repmat (ccol, numel (xcol), 1);
                    endif
                    color = "interp";
                    have_cdata(data_idx) = true;
                  endif
                  ccol = mapcdata (ccol, obj.cdatamapping, clim, cmap_sz);
                endif
              elseif (isnumeric (ec))
                color = ec;
              else
                color = [0, 0, 0];
              endif
            else
              color = [0, 0, 0];
            endif

            lt = gnuplot_linestyletype (obj);

            if (isfield (obj, "linewidth"))
              lw = sprintf ("linewidth %f", obj.linewidth);
            else
              lw = "";
            endif

            [pt, pt2, obj] = gnuplot_pointtype (obj);
            if (! isempty (pt))
              pt = sprintf ("pointtype %s", pt);
            endif
            if (! isempty (pt2))
              pt2 = sprintf ("pointtype %s", pt2);
            endif

            if (ischar (color))
              if (columns (ccol) == 1)
                colorspec = "palette";
              elseif (columns (ccol) == 3)
                colorspec = "lc rgb variable";
                ccol = 255*ccol*double ([0x00_00_01; 0x00_01_00; 0x01_00_00]);
              endif
            else
              colorspec = sprintf ('lc rgb "#%02x%02x%02x"',
                                   uint8 (255*color));
            endif

            sidx = 1;
            if (isempty (lt))
              style = "";
            else
              style = "lines";
            endif
            tmpwith = {};

            facesame = true;
            if (! isequal (pt, pt2) && isfield (obj, "markerfacecolor")
                && ! strcmp (obj.markerfacecolor, "none"))
              if (strcmp (obj.markerfacecolor, "auto")
                  || ! isnumeric (obj.markerfacecolor)
                  || (isnumeric (obj.markerfacecolor)
                      && isequal (color, obj.markerfacecolor)))
                style = [style "points"];
                if (isfield (obj, "markersize"))
                  if (length (mdat) == nc)
                    m = mdat(i);
                  else
                    m = mdat;
                  endif
                  ps = sprintf ("pointsize %f", m / 3);
                else
                  ps = "";
                endif

                tmpwith{sidx} = sprintf ("with %s %s %s %s %s %s",
                                         style, lw, pt2, lt, ps,
                                         colorspec);
              else
                facesame = false;
                if (! isempty (style))
                  tmpwith{sidx} = sprintf ("with %s %s %s %s",
                                           style, lw, lt,
                                           colorspec);
                  sidx += 1;
                endif
                if (isnumeric (obj.markerfacecolor))
                  colorspec = sprintf ('lc rgb "#%02x%02x%02x"',
                                       round (255*obj.markerfacecolor));
                endif
                style = "points";
                if (isfield (obj, "markersize"))
                  if (length (mdat) == nc)
                    m = mdat(i);
                  else
                    m = mdat;
                  endif
                  ps = sprintf ("pointsize %f", m / 3);
                else
                  ps = "";
                endif
                tmpwith{sidx} = sprintf ("with %s %s %s %s %s %s",
                                         style, lw, pt2, lt, ps,
                                         colorspec);
              endif
            endif

            if (isfield (obj, "markeredgecolor")
                && ! strcmp (obj.markeredgecolor, "none"))
              if (facesame && ! isempty (pt)
                  && (strcmp (obj.markeredgecolor, "auto")
                      || ! isnumeric (obj.markeredgecolor)
                      || (isnumeric (obj.markeredgecolor)
                          && isequal (color, obj.markeredgecolor))))
                if (sidx == 1 && ((length (style) == 5
                         && strncmp (style, "lines", 5))
                        || isempty (style)))
                  style = [style, "points"];
                  if (isfield (obj, "markersize"))
                    if (length (mdat) == nc)
                      m = mdat(i);
                    else
                      m = mdat;
                    endif
                    ps = sprintf ("pointsize %f", m / 3);
                  else
                    ps = "";
                  endif
                  tmpwith{sidx} = sprintf ("with %s %s %s %s %s %s",
                                           style, lw, pt, lt, ps,
                                           colorspec);
                endif
              else
                if (! isempty (style))
                  if (length (tmpwith) < sidx || isempty (tmpwith{sidx}))
                    tmpwith{sidx} = sprintf ("with %s %s %s %s",
                                             style, lw, lt,
                                             colorspec);
                  endif
                  sidx += 1;
                endif

                if (! isempty (pt))
                  if (strcmp (obj.markeredgecolor, "auto"))
                    colorspec = sprintf ('lc rgb "#%02x%02x%02x"',
                                         round (255*color));
                  elseif (isnumeric (obj.markeredgecolor))
                    colorspec = sprintf ('lc rgb "#%02x%02x%02x"',
                                         round (255*obj.markeredgecolor));
                  endif
                  style = "points";
                  if (isfield (obj, "markersize"))
                    if (length (mdat) == nc)
                      m = mdat(i);
                    else
                      m = mdat;
                    endif
                    ps = sprintf ("pointsize %f", m / 3);
                  else
                    ps = "";
                  endif
                  tmpwith{sidx} = sprintf ("with %s %s %s %s %s %s",
                                           style, lw, pt, lt, ps,
                                           colorspec);
                endif
              endif
            endif

            if (! isempty (tmpwith))
              withclause{data_idx} = tmpwith{1};
            else
              if (! isempty (style))
                withclause{data_idx} = sprintf ("with %s %s %s %s %s",
                                                style, lw, pt, lt,
                                                colorspec);
              else
                withclause{data_idx} = "";
              endif
            endif
            if (nd == 3)
              if (ischar (color))
                if (! isnan (xcol) && ! isnan (ycol) && ! isnan (zcol))
                  data{data_idx} = [[xcol; xcol(1)], [ycol; ycol(1)], ...
                                    [zcol; zcol(1)], [ccol; ccol(1)]]';
                else
                  data{data_idx} = [xcol, ycol, zcol, ccol]';
                endif
                usingclause{data_idx} = sprintf ("record=%d using ($1):($2):($3):($4)", columns (data{data_idx}));
              else
                if (! isnan (xcol) && ! isnan (ycol) && ! isnan (zcol))
                  data{data_idx} = [[xcol; xcol(1)], [ycol; ycol(1)], ...
                                    [zcol; zcol(1)]]';
                else
                  data{data_idx} = [xcol, ycol, zcol]';
                endif
                usingclause{data_idx} = sprintf ("record=%d using ($1):($2):($3)", columns (data{data_idx}));
              endif
            else
              if (ischar (color))
                if (! isnan (xcol) && ! isnan (ycol))
                  data{data_idx} = [[xcol; xcol(1)], [ycol; ycol(1)], ...
                                    [ccol; ccol(1)]]';
                else
                  data{data_idx} = [xcol, ycol, ccol]';
                endif
                usingclause{data_idx} = sprintf ("record=%d using ($1):($2):($3)", columns (data{data_idx}));
              else
                if (! isnan (xcol) && ! isnan (ycol))
                  data{data_idx} = [[xcol; xcol(1)], [ycol; ycol(1)]]';
                else
                  data{data_idx} = [xcol, ycol]';
                endif
                usingclause{data_idx} = sprintf ("record=%d using ($1):($2)", columns (data{data_idx}));
              endif
            endif

            if (length (tmpwith) > 1)
              data_idx += 1;
              is_image_data(data_idx) = is_image_data(data_idx - 1);
              parametric(data_idx) = parametric(data_idx - 1);
              have_cdata(data_idx) = have_cdata(data_idx - 1);
              have_3d_patch(data_idx) = have_3d_patch(data_idx - 1);
              titlespec{data_idx} = 'title ""';
              usingclause{data_idx} = usingclause{data_idx - 1};
              data{data_idx} = data{data_idx - 1};
              withclause{data_idx} = tmpwith{2};
            endif
            if (length (tmpwith) > 2)
              data_idx += 1;
              is_image_data(data_idx) = is_image_data(data_idx - 1);
              parametric(data_idx) = parametric(data_idx - 1);
              have_cdata(data_idx) = have_cdata(data_idx - 1);
              have_3d_patch(data_idx) = have_3d_patch(data_idx - 1);
              titlespec{data_idx} = 'title ""';
              usingclause{data_idx} = usingclause{data_idx - 1};
              data{data_idx} = data{data_idx - 1};
              withclause{data_idx} = tmpwith{3};
            endif
          endif
        endfor

      case "surface"
        view_map = true;
        tspec = 'title ""';
        if (! isempty (obj.displayname))
          ## Place phantom line data for approximate legend symbol
          data_idx += 1;
          is_image_data(data_idx) = false;
          parametric(data_idx) = false;
          have_cdata(data_idx) = false;
          have_3d_patch(data_idx) = false;
          tmp = __maybe_munge_text__ (enhanced, obj, "displayname", ...
                                      hlgndntrp, gnuplot_term);
          titlespec{data_idx} = ['title "' tmp '"'];
          data{data_idx} = NaN (3,1);
          usingclause{data_idx} = sprintf ("record=1 using ($1):($2):($3)");
          withclause{data_idx} = sprintf ('with line linewidth 10 linecolor rgb "#%02x%02x%02x"',
                                          round (255*cmap(end/2,:)));
        endif

        xdat = obj.xdata;
        ydat = obj.ydata;
        zdat = obj.zdata;
        cdat = mapcdata (obj.cdata, obj.cdatamapping, clim, cmap_sz);
        err = false;
        if (! size_equal (zdat, cdat))
          err = true;
        endif
        if (isvector (xdat) && isvector (ydat) && ismatrix (zdat))
          if (rows (zdat) == length (ydat)
              && columns (zdat) == length (xdat))
            [xdat, ydat] = meshgrid (xdat, ydat);
          else
            err = true;
          endif
        elseif (ismatrix (xdat) && ismatrix (ydat) && ismatrix (zdat))
          if (! size_equal (xdat, ydat, zdat))
            err = true;
          endif
        else
          err = true;
        endif
        if (err)
          error ("__gnuplot_draw_axes__: invalid grid data");
        endif
        xlen = columns (zdat);
        ylen = rows (zdat);

        if (! strcmp (obj.facecolor, "none"))
          data_idx += 1;
          is_image_data(data_idx) = false;
          parametric(data_idx) = false;
          have_cdata(data_idx) = true;
          have_3d_patch(data_idx) = false;

          titlespec{data_idx} = tspec;
          tspec = 'title ""';

          flat_interp_face = (strcmp (obj.facecolor, "flat")
                              || strcmp (obj.facecolor, "interp"));

          if (xlen == columns (xdat) && xlen == columns (ydat)
              && ylen == rows (xdat) && ylen == rows (ydat))
            len = 4 * xlen;
            zz = zeros (ylen, len);
            if (! flat_interp_face)
              addedcmap = [addedcmap; obj.facecolor];
            endif
            k = 1;
            for kk = 1:4:len
              zz(:,kk)   = xdat(:,k);
              zz(:,kk+1) = ydat(:,k);
              zz(:,kk+2) = zdat(:,k);
              if (flat_interp_face)
                zz(:,kk+3) = cdat(:,k);
              else
                zz(:,kk+3) = cmap_sz + rows (addedcmap);
              endif
              k += 1;
            endfor
            data{data_idx} = zz.';
          endif

          doing_interp_color = strcmp (obj.facecolor, "interp");
          if (doing_interp_color)
            interp_str = "interpolate 0, 0";
          else
            ## No interpolation of facecolors.
            interp_str = "";
          endif
          usingclause{data_idx} = sprintf ("record=%dx%d using ($1):($2):($3):($4)", ylen, xlen);

          fputs (plot_stream, "unset pm3d\n");
          fputs (plot_stream, "set style increment default;\n");
          hidden_removal = true;
          withclause{data_idx} = sprintf ("with pm3d");

          if (doing_interp_color)
            ## "depthorder" interferes with interpolation of colors.
            dord = "scansautomatic";
          else
            dord = "depthorder";
          endif

          if (isscalar (obj.facealpha))
            fprintf (plot_stream,
                     "set style fill transparent solid %f;\n",
                     obj.facealpha);
          endif
          fprintf (plot_stream,
                   "set pm3d explicit at s %s %s corners2color c3;\n",
                   interp_str, dord);
        endif

        draw_surf_line = ! strcmp (obj.linestyle, "none") && ! strcmp (obj.edgecolor, "none");
        draw_surf_marker = (! strcmp (obj.marker, "none")
                             && ! (strcmp (obj.markeredgecolor, "none")
                                   && strcmp (obj.markerfacecolor, "none")));
        if (draw_surf_line || draw_surf_marker)
          flat_interp_edge = (strcmp (obj.edgecolor, "flat")
                              || strcmp (obj.edgecolor, "interp"));
          flat_marker = (strcmp (obj.markeredgecolor, "flat") || strcmp (obj.markerfacecolor, "flat")
                         || strcmp (obj.markeredgecolor, "auto") || strcmp (obj.markerfacecolor, "auto"));
          [style, sidx] = do_linestyle_command (obj, obj.edgecolor,
                                                data_idx,
                                                plot_stream);
          domeshcolumn = (strcmp (obj.meshstyle, "column")
                          || strcmp (obj.meshstyle, "both"));
          domeshrow = (strcmp (obj.meshstyle, "row")
                       || strcmp (obj.meshstyle, "both"));
          num_pass = 0;
          num_cols = 0;
          if (domeshcolumn)
            num_pass += xlen;
            num_cols = xlen;
          endif
          if (domeshrow)
            num_pass += ylen;
          endif

          for np = 1:num_pass
            for i_stl = 1:length (style)
              has_ccol = ((strncmp (style{i_stl}, "lines", 5)
                           && flat_interp_edge)
                          || (strncmp (style{i_stl}, "points", 6)
                              && flat_marker));
              if (has_ccol)
                ccol = ":($4)";
                N_tup = 4;
              else
                ccol = "";
                N_tup = 3;
              endif
              sopt = sprintf ("ls %d", sidx (i_stl));

              if (np <= num_cols)
                k = np;
                yrec = ylen;
                zz = zeros (ylen, N_tup);
                zz(:,1) = xdat(:,k);
                zz(:,2) = ydat(:,k);
                zz(:,3) = zdat(:,k);
                if (has_ccol)
                  zz(:,4) = cdat(:,k);
                endif
              else
                j = np - num_cols;
                yrec = xlen;
                zz = zeros (xlen, N_tup);
                zz(:,1) = xdat(j,:)';
                zz(:,2) = ydat(j,:)';
                zz(:,3) = zdat(j,:)';
                if (has_ccol)
                  zz(:,4) = cdat(j,:)';
                endif
              endif

              zz = zz.';

              data_idx += 1;
              is_image_data(data_idx) = false;
              parametric(data_idx) = false;
              if (has_ccol)
                have_cdata(data_idx) = true;
              else
                have_cdata(data_idx) = false;
              endif
              have_3d_patch(data_idx) = false;
              titlespec{data_idx} = tspec;
              usingclause{data_idx} = sprintf ("record=%dx1 using ($1):($2):($3)%s",
                                               yrec, ccol);
              if (isempty (style{i_stl}))
                style{i_stl} = "points";
                data{data_idx} = {};
              else
                data{data_idx} = zz;
              endif
              withclause{data_idx} = sprintf ("with %s %s",
                                              style{i_stl}, sopt);
            endfor
          endfor
        endif

      case "text"
        do_text (plot_stream, gnuplot_term, enhanced, obj, h);

      case "hggroup"
        ## Push group children into the kid list.
        if (isempty (kids))
          kids = obj.children;
        elseif (! isempty (obj.children))
          kids = [kids; obj.children];
        endif

      case "light"
        ## ignore it

      otherwise
        error ("__gnuplot_draw_axes__: unknown object class, %s", obj.type);
    endswitch

  endwhile

  ## This is needed to prevent warnings for rotations in 3-D plots, while
  ## allowing colorbars with contours.
  if (nd == 2 || (data_idx > 1 && ! view_map))
    fputs (plot_stream, "set pm3d implicit;\n");
  else
    fputs (plot_stream, "set pm3d explicit;\n");
  endif

  if (! isnan (hidden_removal) && hidden_removal)
    fputs (plot_stream, "set hidden3d front nooffset;\n");
  else
    fputs (plot_stream, "unset hidden3d;\n");
  endif

  have_data = (! (isempty (data) || all (cellfun ("isempty", data))));

  ## Note we don't use the [xy]2range of gnuplot as we don't use the
  ## dual axis plotting features of gnuplot.
  if (isempty (xlim))
    return;
  endif
  if (strcmp (axis_obj.xdir, "reverse"))
    xlim = flip (xlim);
  endif

  fprintf (plot_stream, "set xrange [%.15e:%.15e];\n", xlim);
  if (strcmp (axis_obj.xaxislocation, "top"))
    fprintf (plot_stream, "set x2range [%.15e:%.15e];\n", xlim);
  endif

  if (isempty (ylim))
    return;
  endif
  if (strcmp (axis_obj.ydir, "reverse"))
    ylim = flip (ylim);
  endif
  fprintf (plot_stream, "set yrange [%.15e:%.15e];\n", ylim);
  if (strcmp (axis_obj.yaxislocation, "right"))
    fprintf (plot_stream, "set y2range [%.15e:%.15e];\n", ylim);
  endif

  if (nd == 3)
    if (isempty (zlim))
      return;
    endif
    if (strcmp (axis_obj.zdir, "reverse"))
      zlim = flip (zlim);
    endif
    fprintf (plot_stream, "set zrange [%.15e:%.15e];\n", zlim);
  endif

  if (! any (isinf (clim)))
    if (rows (addedcmap) > 0)
      fprintf (plot_stream, "set cbrange [1:%.15e];\n",
               cmap_sz + rows (addedcmap));
    else
      fprintf (plot_stream, "set cbrange [1:%.15e];\n", max ([cmap_sz 2]));
    endif
  endif

  if (strcmp (axis_obj.visible, "off"))
    fputs (plot_stream, "unset border; unset tics\n");
  else
    fputs (plot_stream, "unset border\n");
    axis_idx = data_idx;
    if (strcmp (axis_obj.box, "on"))
      if (nd == 3)
        do_border_tick_3d (axis_obj, plot_stream);
      else
        axis_idx = do_border_2d (axis_obj, plot_stream, axis_idx);
      endif
    else
      if (nd == 3)
        do_border_tick_3d (axis_obj, plot_stream);
      else
        axis_idx = do_border_2d (axis_obj, plot_stream, axis_idx);
        if (isempty (axis_obj.xtick))
        elseif (strcmp (axis_obj.xaxislocation, "top"))
          fprintf (plot_stream, "set x2tics %s nomirror\n", axis_obj.tickdir);
        else # xaxislocation == "bottom" or "origin"
          fprintf (plot_stream, "set xtics %s nomirror\n", axis_obj.tickdir);
        endif
        if (isempty (axis_obj.ytick))
        elseif (strcmp (axis_obj.yaxislocation, "right"))
          fprintf (plot_stream, "set y2tics %s nomirror\n", axis_obj.tickdir);
        else # yaxislocation == "left" or "origin"
          fprintf (plot_stream, "set ytics %s nomirror\n",  axis_obj.tickdir);
        endif
      endif
    endif
  endif

  if (! have_major_grid && ! have_minor_grid)
    fputs (plot_stream, "unset grid;\n");
  else
    if (exist ("axis_idx", "var"))
      grid_idx = axis_idx;
    else
      grid_idx = data_idx;
    endif
    if (have_major_grid)
      grid_idx += 1;
      grid_obj.linestyle = axis_obj.gridlinestyle;
      grid_obj.linewidth = axis_obj.linewidth;
      grid_obj.alpha = axis_obj.gridalpha;
      [style, sidx_major] = do_linestyle_command (grid_obj, axis_obj.gridcolor,
                                                  grid_idx, plot_stream);
    else
      sidx_major = 0;
    endif
    if (have_minor_grid)
      grid_idx += 1;
      grid_obj.linestyle = axis_obj.minorgridlinestyle;
      grid_obj.linewidth = axis_obj.linewidth;
      grid_obj.alpha = axis_obj.minorgridalpha;
      [style, sidx_minor] = do_linestyle_command (grid_obj,
                                                  axis_obj.minorgridcolor,
                                                  grid_idx, plot_stream);
    else
      sidx_minor = 0;
    endif
    fprintf (plot_stream, "set grid linestyle %d, linestyle %d;\n",
             sidx_major, sidx_minor);
  endif

  if (! isempty (hlgnd) && strcmp (hlgnd.visible, "on")
      && ! isempty (hlgnd.children)
      && any (strcmp (get ([getappdata(hlgnd.children, "handle"){:}], "visible"),
                      "on")))

    if (strcmp (hlgnd.box, "on"))
      box = "box";
    else
      box = "nobox";
    endif
    if (strcmp (hlgnd.orientation, "vertical"))
      horzvert = "vertical";
    else
      horzvert = "horizontal";
    endif
    if (strcmp (hlgnd.textposition, "right"))
      reverse = "reverse Left";
    else
      reverse = "noreverse Right";
    endif
    inout = "inside";
    keypos = hlgnd.location;
    if (ischar (keypos))
      keypos = lower (keypos);
      keyout = strfind (keypos, "outside");
      if (! isempty (keyout))
        inout = "outside";
        keypos = keypos(1:keyout-1);
      endif
    endif
    switch (keypos)
      case "north"
        pos = "center top";
      case "south"
        pos = "center bottom";
      case "east"
        pos = "right center";
      case "west"
        pos = "left center";
      case "northeast"
        pos = "right top";
      case "northwest"
        pos = "left top";
      case "southeast"
        pos = "right bottom";
      case "southwest"
        pos = "left bottom";
      case "best"
        pos = "";
        warning ("legend: 'Best' not yet implemented for location specifier.\n");
        ## Least conflict with data in plot.
        ## Least unused space outside plot.
      otherwise
        pos = "";
    endswitch
    [fontname, fontsize] = get_fontname_and_size (hlgnd);
    fontspacespec = [create_spacingspec(fontname, fontsize, gnuplot_term),...
                     ' ', create_fontspec(fontname, fontsize, gnuplot_term)];
    textcolors = get (findobj (hlgnd.children, "type", "text"), "color");
    if (iscell (textcolors))
      textcolors = cell2mat (textcolors);
      textcolors = unique (textcolors, "rows");
    endif
    if (rows (textcolors) > 1)
      ## Gnuplot is unable to assign arbitrary colors to each text entry
      ## for the key/legend.  But, the text color can be set to match the
      ## color of the plot object.
      colorspec = "textcolor variable";
    else
      colorspec = get_text_colorspec (textcolors);
    endif
    fprintf (plot_stream, "set key %s %s;\nset key %s %s %s %s %s %s;\n",
             inout, pos, box, reverse, horzvert, fontspacespec, colorspec,
             __do_enhanced_option__ (enhanced, hlgnd));
  else
    fputs (plot_stream, "unset key;\n");
  endif
  fputs (plot_stream, "set style data lines;\n");

  cmap = [cmap; addedcmap];
  cmap_sz += rows (addedcmap);
  if (cmap_sz == 1)        # bug #48083, illegal one-element colormap
    cmap = [cmap; cmap];
    cmap_sz = 2;
  endif
  if (length (cmap) > 0)
    fprintf (plot_stream,
             "set palette positive color model RGB maxcolors %i;\n",
             cmap_sz);
    fprintf (plot_stream,
             ['set palette file "-" binary record=%d using 1:2:3:4;' "\n"],
             cmap_sz);
    fwrite (plot_stream, [1:cmap_sz; cmap.'], "float32");
    fwrite (plot_stream, "\n");
  endif

  fputs (plot_stream, "unset colorbox;\n");

  if (have_data)
    for i = 1:data_idx
      ## Images can be obscured by background or foreground image
      if (is_image_data (i))
        if (bg_is_set)
          fputs (plot_stream, ['if (GPVAL_TERM eq "qt") unset obj 1;' "\n"]);
          bg_is_set = false;
        endif
        if (fg_is_set)
          fputs (plot_stream, "unset obj 2; \\\n");
          fg_is_set = false;
        endif
        break;
      endif
    endfor
    if (nd == 2)
      plot_cmd = "plot";
    else
      plot_cmd = "splot";
      ## Wrap view correctly to match Matlab
      if (axis_obj.view(2) <= 90)
        rot_x = 90 - axis_obj.view(2);
      else
        rot_x = axis_obj.view(2) - 90;
      endif
      rot_x = mod (rot_x, 360);
      while (rot_x < 0)
        rot_x += 360;
      endwhile
      if (axis_obj.view(2) <= 90)
        rot_z = axis_obj.view(1);
      else
        rot_z = axis_obj.view(1) + 180;
      endif
      rot_z = mod (rot_z, 360);
      while (rot_z < 0)
        rot_z += 360;
      endwhile
      fputs (plot_stream, "set ticslevel 0;\n");
      if (view_map && rot_x == 0 && rot_z == 0)
        fputs (plot_stream, "set view map;\n");
      else
        fprintf (plot_stream, "set view %.15g, %.15g;\n", rot_x, rot_z);
      endif
    endif
    if (have_3d_patch (1))
      fputs (plot_stream, "set pm3d depthorder\n");
      ## FIXME: Must leave strings ending in '\', CHAR in double quotes.
      ## Otherwise, fprintf routine tries to do escape processing and fails.
      fprintf (plot_stream, "%s \"-\" %s %s %s \\\n", plot_cmd,
               usingclause{1}, titlespec{1}, withclause{1});
    elseif (is_image_data (1))
      fprintf (plot_stream, "%s \"-\" %s %s %s \\\n", plot_cmd,
               usingclause{1}, titlespec{1}, withclause{1});
    else
      fprintf (plot_stream, "%s \"-\" binary format='%%float64' %s %s %s \\\n",
               plot_cmd, usingclause{1}, titlespec{1}, withclause{1});
    endif
    for i = 2:data_idx
      if (have_3d_patch (i))
        fprintf (plot_stream, ", \"-\" %s %s %s \\\n",
                 usingclause{i}, titlespec{i}, withclause{i});
      elseif (is_image_data (i))
        fprintf (plot_stream, "%s \"-\" %s %s %s \\\n", ",",
                 usingclause{i}, titlespec{i}, withclause{i});
      else
        fprintf (plot_stream, ", \"-\" binary format='%%float64' %s %s %s \\\n",
                 usingclause{i}, titlespec{i}, withclause{i});
      endif
    endfor
    fputs (plot_stream, ";\n");
    for i = 1:data_idx
      if (have_3d_patch (i))
        ## Can't write 3d patch data as binary as can't plot more than
        ## a single patch at a time and have to plot all patches together
        ## so that the gnuplot depth ordering is done correctly
        for j = 1 : 4 : columns (data{i})
          if (j != 1)
            fputs (plot_stream, "\n\n");
          endif
          fprintf (plot_stream, "%.15g %.15g %.15g %.15g\n", data{i}(:,j).');
          fprintf (plot_stream, "%.15g %.15g %.15g %.15g\n\n", data{i}(:,j+1).');
          fprintf (plot_stream, "%.15g %.15g %.15g %.15g\n", data{i}(:,j+2).');
          fprintf (plot_stream, "%.15g %.15g %.15g %.15g\n", data{i}(:,j+3).');
        endfor
        fputs (plot_stream, "e\n");
      elseif (is_image_data(i))
        fwrite (plot_stream, data{i}, "float32");
      else
        __gnuplot_write_data__ (plot_stream, data{i}, nd, parametric(i),
                                have_cdata(i));
      endif
    endfor
    fputs (plot_stream, "\n");
  else
    fputs (plot_stream, "plot \"-\";\nInf Inf\ne\n");
  endif

  ## Needed to allow mouse rotation if gnuplot was put in map view.
  if (view_map && rot_x == 0 && rot_z == 0)
    fputs (plot_stream, "set view 0,0;\n");
  endif

  ## Undo the aspect ratio lock imposed by the gnuplot command sequence:
  ##   "set view equal xy; set view map"
  ## See bug #40686: "Incorrect colorbar size"
  if (nd == 3
      && strcmp (axis_obj.dataaspectratiomode, "manual")
      && axis_obj.dataaspectratio(1) == axis_obj.dataaspectratio(2))
    fprintf (plot_stream, "set size noratio;\n");
  endif

  if (bg_is_set)
    fputs (plot_stream, ['if (GPVAL_TERM eq "qt") unset obj 1;' "\n"]);
    bg_is_set = false;
  endif

  fflush (plot_stream);

endfunction

function x = flip (x)

  if (rows (x) == 1)
    x = fliplr (x);
  elseif (columns (x) == 1 || ischar (x))
    x = flipud (x);
  else
    x = flipud (fliplr (x));
  endif

endfunction

function spacing_spec = create_spacingspec (f, s, gp_term)

  ## The gnuplot default font size is 10, and default spacing is 1.25.
  ## gnuplot has a concept of a figure global font, and sizes everything
  ## appropriate to that, including the legend spacing.
  ##
  ## This means that if an alternative size is used, gnuplot will use an
  ## inappropriate spacing in the legend by default.
  ##
  ## FIXME: Are fractional spacing specifications allowed?  Or should this
  ##        number be rounded?
  spc = s / 10 * 1.25;
  spacing_spec = sprintf ("spacing %d", spc);

endfunction

function fontspec = create_fontspec (f, s, gp_term)

  if (isempty (f) || strcmp (f, "*") || strcmp (gp_term, "tikz"))
    fontspec = sprintf ('font ",%d"', s);
  else
    fontspec = sprintf ('font "%s,%d"', f, s);
  endif

endfunction

function idx = do_border_2d (obj, plot_stream, idx)

  fprintf (plot_stream, "set border 0\n");
  fprintf (plot_stream, "unset arrow\n");

  if (strcmp (obj.box, "on") || strcmp (obj.xaxislocation, "bottom"))
    arrow (1, obj.xcolor, obj.linewidth, [0,0,0], [1,0,0]);
  endif
  if (strcmp (obj.box, "on") || strcmp (obj.xaxislocation, "top"))
    arrow (2, obj.xcolor, obj.linewidth, [0,1,0], [1,1,0]);
  endif
  if (strcmp (obj.box, "on") || strcmp (obj.yaxislocation, "left"))
    arrow (3, obj.ycolor, obj.linewidth, [0,0,0], [0,1,0]);
  endif
  if (strcmp (obj.box, "on") || strcmp (obj.yaxislocation, "right"))
    arrow (4, obj.ycolor, obj.linewidth, [1,0,0], [1,1,0]);
  endif

  if (strcmp (obj.xaxislocation, "origin"))
    idx = zeroaxis (idx, obj.xcolor, "x");
  endif
  if (strcmp (obj.yaxislocation, "origin"))
    idx = zeroaxis (idx, obj.ycolor, "y");
  endif

  function idx = zeroaxis (idx, lc, ax)
    idx = idx + 1;
    [~, ltidx] = do_linestyle_command (obj, lc, idx, plot_stream);
    fprintf (plot_stream, "set %szeroaxis ls %d ", ax, ltidx);
    fprintf (plot_stream, "lw %.3f\n", obj.linewidth);
  endfunction

  function arrow (idx, lc, lw, from, to)
    fprintf (plot_stream, "set arrow %d ", idx);
    fprintf (plot_stream, "nohead nofilled front ");
    fprintf (plot_stream, "lc rgb ""#%02x%02x%02x"" ", round (255 * lc));
    fprintf (plot_stream, "linewidth %.3f ", obj.linewidth);
    fprintf (plot_stream, "from graph %d,%d,%d ", from);
    fprintf (plot_stream, "to graph %d,%d,%d\n", to);
  endfunction

endfunction

function idx = do_border_tick_3d (obj, plot_stream, idx)

  ## axis location has no effect

  if (strcmp (obj.box, "on"))
    fputs (plot_stream, "set border 0xFFF;\n");
    mirrorstr = "mirror";
  else
    fputs (plot_stream, "set border 0x15;\n");
    mirrorstr = "nomirror";
  endif

  tick ('x', obj.xcolor, obj.tickdir, mirrorstr);
  tick ('y', obj.ycolor, obj.tickdir, mirrorstr);
  tick ('z', obj.zcolor, obj.tickdir, mirrorstr);

  function tick (axischar, color, tickdir, mirrorstr)

    if (isnumeric (color))
      if (length (color) == 3)
        colorspec = sprintf ('rgb "#%02x%02x%02x"', round (255*color));
      else
        colorspec = sprintf ("palette %d", round (color));
      endif
    else
      colorspec = sprintf ('"%s"', color);
    endif
    fprintf (plot_stream, "set %ctics %s %s textcolor %s\n",
             axischar, tickdir, mirrorstr, colorspec);

  endfunction

endfunction

function [style, ltidx] = do_linestyle_command (obj, linecolor, idx,
                                                plot_stream)

  idx = idx + 8;
  style = {};
  ltidx = [];

  fprintf (plot_stream, "set style line %d default;\n", idx);
  fprintf (plot_stream, "set style line %d", idx);

  found_style = false;
  if (isnumeric (linecolor))
    color = linecolor;
    if (isfield (obj, "alpha")
        &&  __gnuplot_has_feature__ ("alphablend_linecolor"))
      alphastr = sprintf ("%02x", round (255*(1-obj.alpha)));
    else
      alphastr = "";
    endif
    fprintf (plot_stream, ' linecolor rgb "#%s%02x%02x%02x"',
             alphastr, round (255*color));
  else
    color = [0, 0, 0];
    flat_interp_edge = (strcmp (obj.edgecolor, "flat")
                        || strcmp (obj.edgecolor, "interp"));
    if (flat_interp_edge)
        fprintf (plot_stream, " palette");
    endif
  endif

  lt = gnuplot_linestyletype (obj);
  if (! isempty (lt))
    fprintf (plot_stream, " %s", lt);
  endif

  if (isfield (obj, "linewidth"))
    fprintf (plot_stream, " linewidth %f", obj.linewidth);
    found_style = true;
  endif

  [pt, pt2, obj] = gnuplot_pointtype (obj);

  if (! isempty (pt))
    found_style = true;
  endif

  sidx = 1;
  if (isempty (lt))
    style{sidx} = "";
  else
    style{sidx} = "lines";
  endif
  ltidx(sidx) = idx;

  facesame = true;
  if (! isequal (pt, pt2) && isfield (obj, "markerfacecolor")
      && ! strcmp (obj.markerfacecolor, "none"))
    if (strcmp (obj.markerfacecolor, "auto")
        || (isnumeric (obj.markerfacecolor)
            && isequal (color, obj.markerfacecolor)))
      if (! isempty (pt2))
        fprintf (plot_stream, " pointtype %s", pt2);
        style{sidx} = [style{sidx} "points"];
      endif
      if (isfield (obj, "markersize"))
        fprintf (plot_stream, " pointsize %f", obj.markersize / 3);
      endif
    else
      facesame = false;
      if (! found_style)
        fputs (plot_stream, " default");
      endif
      fputs (plot_stream, ";\n");
      if (! isempty (style{sidx}))
        sidx += 1;
        idx += 1;
      else
        fputs (plot_stream, ";\n");
      endif
      fprintf (plot_stream, "set style line %d default;\n", idx);
      fprintf (plot_stream, "set style line %d", idx);
      if (isnumeric (obj.markerfacecolor))
        fprintf (plot_stream, ' linecolor rgb "#%02x%02x%02x"',
                 round (255*obj.markerfacecolor));
      else
        fprintf (plot_stream, " palette");
      endif
      if (! isempty (pt2))
        style{sidx} = "points";
        ltidx(sidx) = idx;
        fprintf (plot_stream, " pointtype %s", pt2);
      endif
      if (isfield (obj, "markersize"))
        fprintf (plot_stream, " pointsize %f", obj.markersize / 3);
      endif
    endif
  endif
  if (! isempty (pt) && isfield (obj, "markeredgecolor")
      && ! strcmp (obj.markeredgecolor, "none"))
    if (facesame && (strcmp (obj.markeredgecolor, "auto")
        || (isnumeric (obj.markeredgecolor)
            && isequal (color, obj.markeredgecolor))))
      if (sidx == 1 && ((length (style{sidx}) == 5
          && strncmp (style{sidx}, "lines", 5)) || isempty (style{sidx})))
        style{sidx} = [style{sidx} "points"];
        fprintf (plot_stream, " pointtype %s", pt);
        if (isfield (obj, "markersize"))
          fprintf (plot_stream, " pointsize %f", obj.markersize / 3);
        endif
      endif
    else
      if (! found_style)
        fputs (plot_stream, " default");
      endif
      fputs (plot_stream, ";\n");
      if (! isempty (style{sidx}))
        sidx += 1;
        idx += 1;
      else
        fputs (plot_stream, ";\n");
      endif
      fprintf (plot_stream, "set style line %d default;\n", idx);
      fprintf (plot_stream, "set style line %d", idx);
      if (isnumeric (obj.markeredgecolor) || strcmp (obj.markeredgecolor, "auto"))
        if (isnumeric (obj.markeredgecolor))
          edgecolor = obj.markeredgecolor;
        else
          edgecolor = obj.color;
        endif
        fprintf (plot_stream, ' linecolor rgb "#%02x%02x%02x"',
                 round (255*edgecolor));
      else
        fprintf (plot_stream, " palette");
      endif
      style{sidx} = "points";
      ltidx(sidx) = idx;
      fprintf (plot_stream, " pointtype %s", pt);
      if (isfield (obj, "markersize"))
        fprintf (plot_stream, " pointsize %f", obj.markersize / 3);
      endif
    endif
  endif

  if (! found_style && isempty (style{1}))
    fputs (plot_stream, " default");
  endif

  fputs (plot_stream, ";\n");

endfunction

function lt = gnuplot_linestyletype (obj)

  if (isfield (obj, "linestyle"))
    if (__gnuplot_has_feature__ ("dashtype"))
      opt = "dashtype";
      switch (obj.linestyle)
        case "-"
          lt = "solid";
        case "--"
          lt = "'_ '";
        case ":"
          lt = "'. '";
        case "-."
          lt = "'-. '";
        case "none"
          lt = "";
        otherwise
          lt = "";
      endswitch
    else
      opt = "linetype";
      switch (obj.linestyle)
        case "-"
          lt = "1";
        case "--"
          lt = "2";
        case ":"
          lt = "3";
        case "-."
          lt = "6";
        case "none"
          lt = "";
        otherwise
          lt = "";
      endswitch
    endif
    if (! isempty (lt))
      lt = sprintf ("%s %s", opt, lt);
    endif
  else
    lt = "";
  endif

endfunction

function [pt, pt2, obj] = gnuplot_pointtype (obj)

  if (isfield (obj, "marker"))
    switch (obj.marker)
      case "+"
        pt = pt2 = "1";
      ## FIXME: It's not clear how to add support for these markers in gnuplot
      #{
      case "|"
        pt = "1";
        pt2 = "1";
      case "_"
        pt = "1";
        pt2 = "1";
      #}
      case "o"
        pt = "6";
        pt2 = "7";
      case "*"
        pt = pt2 = "3";
      case "."
        pt = pt2 = "7";
        if (isfield (obj, "markersize"))
          obj.markersize /= 3;
        else
          obj.markersize = 5;
        endif
      case "x"
        pt = pt2 = "2";
      case {"square", "s"}
        pt = "4";
        pt2 = "5";
      case {"diamond", "d"}
        pt = "12";
        pt2 = "13";
      case "^"
        pt = "8";
        pt2 = "9";
      case "v"
        pt = "10";
        pt2 = "11";
      case ">"
        ## FIXME: Should be triangle pointing right, use triangle pointing up
        pt = "8";
        pt2 = "9";
      case "<"
        ## FIXME: Should be triangle pointing left, use triangle pointing down
        pt = "10";
        pt2 = "11";
      case {"pentagram", "p"}
        ## FIXME: Should be pentagram, using pentagon
        pt = "14";
        pt2 = "15";
      case {"hexagram", "h"}
        ## FIXME: Should be 6 pt start, using "*" instead
        pt = pt2 = "3";
      case "none"
        pt = pt2 = "-1";
      otherwise
        pt = pt2 = "";
    endswitch
  else
    pt = pt2 = "";
  endif

endfunction

function __gnuplot_write_data__ (plot_stream, data, nd, parametric, cdata)

  ## DATA is already transposed.

  ## Convert NA elements to normal NaN values because fprintf writes
  ## "NA" and that confuses gnuplot.
  data(isna (data)) = NaN;

  if (nd == 2)
    fwrite (plot_stream, data, "float64");
  elseif (nd == 3)
    if (parametric)
      fwrite (plot_stream, data, "float64");
    else
      nr = rows (data);
      if (cdata)
        for j = 1:4:nr
          fwrite (plot_stream, data(j:j+3,:), "float64");
        endfor
      else
        for j = 1:3:nr
          fwrite (plot_stream, data(j:j+2,:), "float64");
        endfor
      endif
    endif
  endif

endfunction

function do_tics (obj, plot_stream, ymirror, gnuplot_term)

  obj.xticklabel = ticklabel_to_cell (obj.xticklabel);
  obj.yticklabel = ticklabel_to_cell (obj.yticklabel);
  obj.zticklabel = ticklabel_to_cell (obj.zticklabel);

  if (strcmp (obj.xminorgrid, "on"))
    obj.xminortick = "on";
  endif
  if (strcmp (obj.yminorgrid, "on"))
    obj.yminortick = "on";
  endif
  if (strcmp (obj.zminorgrid, "on"))
    obj.zminortick = "on";
  endif

  [fontname, fontsize] = get_fontname_and_size (obj);
  fontspec = create_fontspec (fontname, fontsize, gnuplot_term);

  ## A Gnuplot tic scale of 69 is equivalent to Octave's 0.5.
  ticklength = sprintf ("scale %4.1f", (69/0.5)*obj.ticklength(1));

  if (strcmp (obj.xaxislocation, "top"))
    do_tics_1 (obj.xtickmode, obj.xtick, obj.xminortick, obj.xticklabelmode,
               obj.xticklabel, obj.xcolor, "x2", plot_stream, true,
               "border", obj.tickdir, ticklength, fontname, fontspec,
               obj.ticklabelinterpreter, obj.xscale, obj.xsgn, gnuplot_term);
    do_tics_1 ("manual", [], "off", obj.xticklabelmode, obj.xticklabel,
               obj.xcolor, "x", plot_stream, true, "border",
               "", "", fontname, fontspec, obj.ticklabelinterpreter,
               obj.xscale, obj.xsgn, gnuplot_term);
  elseif (strcmp (obj.xaxislocation, "origin"))
    do_tics_1 (obj.xtickmode, obj.xtick, obj.xminortick, obj.xticklabelmode,
               obj.xticklabel, obj.xcolor, "x", plot_stream, true,
               "axis", obj.tickdir, ticklength, fontname, fontspec,
               obj.ticklabelinterpreter, obj.xscale, obj.xsgn, gnuplot_term);
    do_tics_1 ("manual", [], "off", obj.xticklabelmode, obj.xticklabel,
               obj.xcolor, "x2", plot_stream, true, "axis",
               "", "", fontname, fontspec, obj.ticklabelinterpreter,
               obj.xscale, obj.xsgn, gnuplot_term);
  else
    do_tics_1 (obj.xtickmode, obj.xtick, obj.xminortick, obj.xticklabelmode,
               obj.xticklabel, obj.xcolor, "x", plot_stream, true,
               "border", obj.tickdir, ticklength, fontname, fontspec,
               obj.ticklabelinterpreter, obj.xscale, obj.xsgn, gnuplot_term);
    do_tics_1 ("manual", [], "off", obj.xticklabelmode, obj.xticklabel,
               obj.xcolor, "x2", plot_stream, true, "border",
               "", "", fontname, fontspec, obj.ticklabelinterpreter,
               obj.xscale, obj.xsgn, gnuplot_term);
  endif
  if (strcmp (obj.yaxislocation, "right"))
    do_tics_1 (obj.ytickmode, obj.ytick, obj.yminortick, obj.yticklabelmode,
               obj.yticklabel, obj.ycolor, "y2", plot_stream, ymirror,
               "border", obj.tickdir, ticklength, fontname, fontspec,
               obj.ticklabelinterpreter, obj.yscale, obj.ysgn, gnuplot_term);
    do_tics_1 ("manual", [], "off", obj.yticklabelmode, obj.yticklabel,
               obj.ycolor, "y", plot_stream, ymirror, "border",
               "", "", fontname, fontspec, obj.ticklabelinterpreter,
               obj.yscale, obj.ysgn, gnuplot_term);
  elseif (strcmp (obj.yaxislocation, "origin"))
    do_tics_1 (obj.ytickmode, obj.ytick, obj.yminortick, obj.yticklabelmode,
               obj.yticklabel, obj.ycolor, "y", plot_stream, ymirror,
               "axis", obj.tickdir, ticklength, fontname, fontspec,
               obj.ticklabelinterpreter, obj.yscale, obj.ysgn, gnuplot_term);
    do_tics_1 ("manual", [], "off", obj.yticklabelmode, obj.yticklabel,
               obj.ycolor, "y2", plot_stream, ymirror, "axis",
               "", "", fontname, fontspec, obj.ticklabelinterpreter,
               obj.yscale, obj.ysgn, gnuplot_term);
  else
    do_tics_1 (obj.ytickmode, obj.ytick, obj.yminortick, obj.yticklabelmode,
               obj.yticklabel, obj.ycolor, "y", plot_stream, ymirror,
               "border", obj.tickdir, ticklength, fontname, fontspec,
               obj.ticklabelinterpreter, obj.yscale, obj.ysgn, gnuplot_term);
    do_tics_1 ("manual", [], "off", obj.yticklabelmode, obj.yticklabel,
               obj.ycolor, "y2", plot_stream, ymirror, "border",
               "", "", fontname, fontspec, obj.ticklabelinterpreter,
               obj.yscale, obj.ysgn, gnuplot_term);
  endif
  do_tics_1 (obj.ztickmode, obj.ztick, obj.zminortick, obj.zticklabelmode,
             obj.zticklabel, obj.zcolor, "z", plot_stream, true,
             "border", obj.tickdir, ticklength, fontname, fontspec,
             obj.ticklabelinterpreter, obj.zscale, obj.zsgn, gnuplot_term);

endfunction

function do_tics_1 (ticmode, tics, mtics, labelmode, labels, color, ax,
                    plot_stream, mirror, axispos, tickdir, ticklength,
                    fontname, fontspec, interpreter, scale, sgn, gnuplot_term)
  persistent warned_latex = false;

  ## Avoid emitting anything if the tics are empty, because this undoes the
  ## effect of the previous unset xtics and thereby adds back in the tics.
  if (isempty (tics))
    return;
  endif

  if (mirror)
    mirror = "mirror";
  else
    mirror = "nomirror";
  endif
  if (strcmp (interpreter, "tex"))
    for n = 1 : numel (labels)
      labels{n} = __tex2enhanced__ (labels{n}, fontname, false, false, ...
                                    gnuplot_term);
    endfor
  elseif (strcmp (interpreter, "latex"))
    if (! warned_latex)
      do_warn = (warning ("query", "Octave:text_interpreter")).state;
      if (strcmp (do_warn, "on"))
        warning ("Octave:text_interpreter",
                 "latex markup not supported for tick marks");
        warned_latex = true;
      endif
    endif
  endif
  if (strcmp (scale, "log"))
    num_mtics = 10;
    if (any (strcmp (gnuplot_term, {"cairolatex", "eepic", "epslatex", ...
        "latex", "pslatex", "pstex", "pstricks", "texdraw", "tikz"})))
      fmt = "$10^{%T}$";
    else
      fmt = "10^{%T}";
    endif
    if (sgn < 0)
      fmt = ["-" fmt];
    endif
  else
    fmt = "%g";
    num_mtics = 5;
  endif
  colorspec = get_text_colorspec (color);
  fprintf (plot_stream, ['set format %s "%s";' "\n"], ax, fmt);
  if (strcmp (ticmode, "manual") && isempty (tics))
    fprintf (plot_stream, "unset %stics;\nunset m%stics;\n", ax, ax);
    return;
  else
    k = 1;
    ntics = numel (tics);
    labels(end+1:1) = {""};
    labels = repmat (labels(:), ceil (ntics/numel (labels)), 1);
    fprintf (plot_stream, "set %stics %s %s %s %s (", ax,
             tickdir, ticklength, axispos, mirror);
    labels = strrep (labels, "%", "%%");
    for i = 1:ntics
      fprintf (plot_stream, ' "%s" %.15f', labels{k++}, tics(i));
      if (i < ntics)
        fputs (plot_stream, ", ");
      endif
    endfor
    fprintf (plot_stream, ") %s %s;\n", colorspec, fontspec);
  endif
  if (strcmp (mtics, "on"))
    fprintf (plot_stream, "set m%stics %d;\n", ax, num_mtics);
  else
    fprintf (plot_stream, "unset m%stics;\n", ax);
  endif

endfunction

function ticklabel = ticklabel_to_cell (ticklabel)

  if (ischar (ticklabel))
    ticklabel = cellstr (ticklabel);
  elseif (iscellstr (ticklabel))
    ticklabel = ticklabel;
  else
    error ("__gnuplot_draw_axes__: unsupported type of ticklabel");
  endif

endfunction

function colorspec = get_text_colorspec (color)
  colorspec = sprintf ('textcolor rgb "#%02x%02x%02x"', round (255*color));
endfunction

function [f, s, fnt, it, bld] = get_fontname_and_size (t)

  if (isempty (t.fontname) || strcmp (t.fontname, "*"))
    if (ispc ())
      ## FIXME: Should really test for "windows" terminal which is the
      ## only terminal to have a problem with a null font specification.
      ## See Bug #49135.
      fnt = "Arial";
    else
      fnt = "";
    endif
  else
    fnt = t.fontname;
  endif

  f = fnt;
  it = false;
  bld = false;
  if (! isempty (t.fontweight) && strcmp (t.fontweight, "bold"))
    if (! isempty (t.fontangle)
        && (strcmp (t.fontangle, "italic")
            || strcmp (t.fontangle, "oblique")))
      if (__gnuplot_has_feature__ ("fontspec_5"))
        f = [f ":Bold:Italic"];
      else
        f = [f "-bolditalic"];
      endif

      it = true;
      bld = true;
    else
      if (__gnuplot_has_feature__ ("fontspec_5"))
        f = [f ":Bold"];
      else
        f = [f "-bold"];
      endif

      bld = true;
    endif
  elseif (! isempty (t.fontangle)
          && (strcmp (t.fontangle, "italic")
              || strcmp (t.fontangle, "oblique")))
    if (__gnuplot_has_feature__ ("fontspec_5"))
      f = [f ":Italic"];
    else
      f = [f "-italic"];
    endif

    it = true;
  endif

  if (isempty (t.fontsize))
    s = 10;
  else
    s = t.fontsize;
  endif

endfunction

function [str, f, s] = __maybe_munge_text__ (enhanced, obj, fld, ntrp, ...
                                             gnuplot_term)
  persistent warned_latex = false;

  if (strcmp (fld, "string"))
    [f, s, fnt, it, bld] = get_fontname_and_size (obj);
  else
    f = "Helvetica";
    s = 10;
    fnt = f;
    it = false;
    bld = false;
  endif

  ## The text object may be multiline, and may be of any class
  str = getfield (obj, fld);
  if (ischar (str) && rows (str) > 1)
    str = cellstr (str);
  elseif (isnumeric (str))
    str = cellstr (num2str (str(:)));
  endif
  if (iscellstr (str))
    for n = 1:numel (str)
      if (isnumeric (str{n}))
        str{n} = num2str (str{n});
      endif
    endfor
    str = sprintf ("%s\n", str{:})(1:end-1);
  endif

  if (enhanced)
    str = regexprep (str, '(?<!\\)@', '\\@');
  endif

  if (enhanced)
    if (strcmp (ntrp, "tex"))
      if (iscellstr (str))
        for n = 1:numel (str)
          str{n} = __tex2enhanced__ (str{n}, fnt, it, bld, gnuplot_term);
        endfor
      else
        str = __tex2enhanced__ (str, fnt, it, bld, gnuplot_term);
      endif
    elseif (strcmp (ntrp, "latex"))
      if (! warned_latex)
        do_warn = (warning ("query", "Octave:text_interpreter")).state;
        if (strcmp (do_warn, "on"))
          warning ("Octave:text_interpreter",
                   "latex markup not supported for text objects");
          warned_latex = true;
        endif
      endif
    endif
  endif

endfunction

function str = __tex2enhanced__ (str, fnt, it, bld, gnuplot_term)
  persistent sym = __setup_sym_table__ ();
  persistent flds = fieldnames (sym);

  if (any (strcmp (gnuplot_term, {"postscript", "epscairo"})))
    symtype = 1;
  else
    symtype = 2;
  endif

  [s, e, m] = regexp (str, "\\\\([a-zA-Z]+|0)", "start", "end", "matches");

  for i = length (s) : -1 : 1
    ## special case for "\0"  and replace with empty set equivalent
    if (strncmp (m{i}, '\0', 2))
      str = [str(1:s(i) - 1) sym.emptyset{symtype} str(s(i) + 2:end)];
    else
      f = m{i}(2:end);
      if (isfield (sym, f))
        g = sym.(f){symtype};
        ## FIXME: The symbol font doesn't seem to support bold or italic
        ##if (bld)
        ##  if (it)
        ##    g = strrep (g, '/Symbol', '/Symbol-bolditalic');
        ##  else
        ##    g = strrep (g, '/Symbol', '/Symbol-bold');
        ##  endif
        ##elseif (it)
        ##  g = strrep (g, '/Symbol', '/Symbol-italic');
        ##endif
        str = [str(1:s(i) - 1) g str(e(i) + 1:end)];
      elseif (strncmp (f, "rm", 2))
        bld = false;
        it = false;
        str = [str(1:s(i) - 1) '{/' fnt ' ' str(s(i) + 3:end) '}'];
      elseif (strncmp (f, "it", 2) || strncmp (f, "sl", 2))
        it = true;
        if (__gnuplot_has_feature__ ("fontspec_5"))
          if (bld)
            str = [str(1:s(i)-1) '{/' fnt ':Bold:Italic ' str(s(i)+3:end) '}'];
          else
            str = [str(1:s(i)-1) '{/' fnt ':Italic ' str(s(i)+3:end) '}'];
          endif
        else
          if (bld)
            str = [str(1:s(i)-1) '{/' fnt '-bolditalic ' str(s(i)+3:end) '}'];
          else
            str = [str(1:s(i)-1) '{/' fnt '-italic ' str(s(i)+3:end) '}'];
          endif
        endif
      elseif (strncmp (f, "bf", 2))
        bld = true;
        if (__gnuplot_has_feature__ ("fontspec_5"))
          if (it)
            str = [str(1:s(i)-1) '{/' fnt ':Bold:Italic ' str(s(i)+3:end) '}'];
          else
            str = [str(1:s(i)-1) '{/' fnt ':Bold ' str(s(i)+3:end) '}'];
          endif
        else
          if (it)
            str = [str(1:s(i)-1) '{/' fnt '-bolditalic ' str(s(i)+3:end) '}'];
          else
            str = [str(1:s(i)-1) '{/' fnt '-bold ' str(s(i)+3:end) '}'];
          endif
        endif
      elseif (strcmp (f, "color"))
        ## FIXME: Ignore \color but remove trailing {} block as well
        d = strfind (str(e(i) + 1:end),'}');
        if (isempty (d))
          warning ('syntax error in \color argument');
        else
          str = [str(1:s(i) - 1) str(e(i) + d + 1:end)];
        endif
      elseif (strcmp (f, "fontname"))
        b1 = strfind (str(e(i) + 1:end),'{');
        b2 = strfind (str(e(i) + 1:end),'}');
        if (isempty (b1) || isempty (b2))
          warning ('syntax error in \fontname argument');
        else
          str = [str(1:s(i) - 1), '/', str(e(i)+b1(1) + 1:e(i)+b2(1)-1), ...
                 '{}', str(e(i) + b2(1) + 1:end)];
        endif
      elseif (strcmp (f, "fontsize"))
        b1 = strfind (str(e (i) + 1:end),'{');
        b2 = strfind (str(e (i) + 1:end),'}');
        if (isempty (b1) || isempty (b2))
          warning ('syntax error in \fontname argument');
        else
          str = [str(1:s(i) - 1), '/=', str(e(i)+b1(1) + 1:e(i)+b2(1)-1), ...
                 '{}', str(e(i) + b2(1) + 1:end)];
        endif
      else
        ## Last desperate attempt to treat the symbol.  Look for things
        ## like \pix, that should be translated to the symbol Pi and x
        for j = 1 : length (flds)
          if (strncmp (flds{j}, f, length (flds{j})))
            g = sym.(flds{j}){symtype};
            ## FIXME: The symbol font doesn't seem to support bold or italic
            ##if (bld)
            ##  if (it)
            ##    g = strrep (g, '/Symbol', '/Symbol-bolditalic');
            ##  else
            ##    g = strrep (g, '/Symbol', '/Symbol-bold');
            ##  endif
            ##elseif (it)
            ##  g = strrep (g, '/Symbol', '/Symbol-italic');
            ##endif
            str = [str(1:s(i) - 1) g str(s(i) + length (flds{j}) + 1:end)];
            break;
          endif
        endfor
      endif
    endif
  endfor

  ## Prepend @ to things like _0^x or _{-100}^{100} for alignment.
  ## But need to put the shorter of the two arguments first.
  ## Careful of nested {} and unprinted characters when defining
  ## shortest..  Don't have to worry about things like ^\theta as they
  ## are already converted.

  ## FIXME: This is a mess.  Is it worth it just for a "@" character?

  [s, m] = regexp (str,'[_\^]','start','matches');
  i = 1;
  p = 0;
  while (i < length (s))
    if (i < length (s))
      if (str(s(i) + p + 1) == "{")
        s1 = strfind (str(s(i) + p + 2:end),'{');
        si = 1;
        l1 = strfind (str(s(i) + p + 1:end),'}');
        li = 1;
        while (li <= length (l1) && si <= length (s1))
          if (l1(li) < s1(si))
            if (li == si)
              break;
            endif
            li += 1;
          else
            si += 1;
          endif
        endwhile
        l1 = l1(min (length (l1), si));
        if (s(i) + l1 + 1 == s(i+1))
          if (str(s(i + 1) + p + 1) == "{")
            s2 = strfind (str(s(i + 1) + p + 2:end),'{');
            si = 1;
            l2 = strfind (str(s(i + 1) + p + 1:end),'}');
            li = 1;
            while (li <= length (l2) && si <= length (s2))
              if (l2(li) < s2(si))
                if (li == si)
                  break;
                endif
                li += 1;
              else
                si += 1;
              endif
            endwhile
            l2 = l2(min (length (l2), si));
            if (length_string (str(s(i)+p+2:s(i)+p+l1-1)) <=
                length_string (str(s(i+1)+p+2:s(i+1)+p+l2-1)))
              ## Shortest already first!
              str = [str(1:s(i)+p-1) "@" str(s(i)+p:end)];
            else
              ## Have to swap sub/super-script to get shortest first.
              str = [str(1:s(i)+p-1), "@", str(s(i+1)+p:s(i+1)+p+l2), ...
                     str(s(i)+p:s(i)+p+l1), str(s(i+1)+p+l2+1:end)];
            endif
          else
            ## Have to swap sub/super-script to get shortest first.
            str = [str(1:s(i)+p-1), "@", str(s(i+1)+p:s(i+1)+p+1), ...
                   str(s(i)+p:s(i)+p+l1), str(s(i+1)+p+2:end)];
          endif
          i += 2;
          p += 1;
        else
          i += 1;
        endif
      else
        if (s(i+1) == s(i) + 2)
          ## Shortest already first!
          str = [str(1:s(i)+p-1) "@" str(s(i)+p:end)];
          p += 1;
          i += 2;
        else
          i += 1;
        endif
      endif
    else
      i += 1;
    endif
  endwhile

endfunction

function l = length_string (s)

  l = length (s) - length (strfind (s,'{')) - length (strfind (s,'}'));
  m = regexp (s, '/([\w-]+|[\w-]+=\d+)', 'matches');
  if (! isempty (m))
    l -= sum (cellfun ("length", m));
  endif

endfunction

function sym = __setup_sym_table__ ()

  ## Setup the translation table for TeX to gnuplot enhanced mode.
  sym.forall = {'{/Symbol \042}', '∀'};
  sym.exists = {'{/Symbol \044}', '∃'};
  sym.ni = {'{/Symbol \047}', '∋'};
  sym.cong = {'{/Symbol \100}', '≅'};
  sym.Delta = {'{/Symbol D}', 'Δ'};
  sym.Phi = {'{/Symbol F}', 'Φ'};
  sym.Gamma = {'{/Symbol G}', 'Γ'};
  sym.vartheta = {'{/Symbol J}', 'ϑ'};
  sym.Lambda = {'{/Symbol L}', 'Λ'};
  sym.Pi = {'{/Symbol P}', 'Π'};
  sym.Theta = {'{/Symbol Q}', 'Θ'};
  sym.Sigma = {'{/Symbol S}', 'Σ'};
  sym.varsigma = {'{/Symbol V}', 'ς'};
  sym.Omega = {'{/Symbol W}', 'Ω'};
  sym.Xi = {'{/Symbol X}', 'Ξ'};
  sym.Psi = {'{/Symbol Y}', 'Ψ'};
  sym.perp = {'{/Symbol \136}', '⊥'};
  sym.alpha = {'{/Symbol a}', 'α'};
  sym.beta = {'{/Symbol b}', 'β'};
  sym.chi = {'{/Symbol c}', 'χ'};
  sym.delta = {'{/Symbol d}', 'δ'};
  sym.epsilon = {'{/Symbol e}', 'ε'};
  sym.phi = {'{/Symbol f}', 'ϕ'};
  sym.gamma = {'{/Symbol g}', 'γ'};
  sym.eta = {'{/Symbol h}', 'η'};
  sym.iota = {'{/Symbol i}', 'ι'};
  sym.varphi = {'{/Symbol j}', 'φ'};              # Not in OpenGL
  sym.kappa = {'{/Symbol k}', 'κ'};
  sym.lambda = {'{/Symbol l}', 'λ'};
  sym.mu = {'{/Symbol m}', 'μ'};
  sym.nu = {'{/Symbol n}', 'ν'};
  sym.o = {'{/Symbol o}', 'ο'};
  sym.pi = {'{/Symbol p}', 'π'};
  sym.theta = {'{/Symbol q}', 'θ'};
  sym.rho = {'{/Symbol r}', 'ρ'};
  sym.sigma = {'{/Symbol s}', 'σ'};
  sym.tau = {'{/Symbol t}', 'τ'};
  sym.upsilon = {'{/Symbol u}', 'υ'};
  sym.varpi = {'{/Symbol v}', 'ϖ'};
  sym.omega = {'{/Symbol w}', 'ω'};
  sym.xi = {'{/Symbol x}', 'ξ'};
  sym.psi = {'{/Symbol y}', 'ψ'};
  sym.zeta = {'{/Symbol z}', 'ζ'};
  sym.sim = {'{/Symbol \176}', '∼'};
  sym.Upsilon = {'{/Symbol \241}', 'Υ'};
  sym.prime = {'{/Symbol \242}', '′'};
  sym.leq = {'{/Symbol \243}', '≤'};
  sym.infty = {'{/Symbol \245}', '∞'};
  sym.clubsuit = {'{/Symbol \247}', '♣'};
  sym.diamondsuit = {'{/Symbol \250}', '♢'};
  sym.heartsuit = {'{/Symbol \251}', '♡'};
  sym.spadesuit = {'{/Symbol \252}', '♠'};
  sym.leftrightarrow = {'{/Symbol \253}', '↔'};
  sym.leftarrow = {'{/Symbol \254}', '←'};
  sym.uparrow = {'{/Symbol \255}', '↑'};
  sym.rightarrow = {'{/Symbol \256}', '→'};
  sym.downarrow = {'{/Symbol \257}', '↓'};
  sym.circ = {'{/Symbol \260}', '∘'};
  ## degree symbol, not circ as in FLTK
  sym.deg = {'{/Symbol \260}', '°'};
  sym.ast = {'{/Symbol *}', '∗'};
  sym.pm = {'{/Symbol \261}', '±'};
  sym.geq = {'{/Symbol \263}', '≥'};
  sym.times = {'{/Symbol \264}', '×'};
  sym.propto = {'{/Symbol \265}', '∝'};
  sym.partial = {'{/Symbol \266}', '∂'};
  sym.bullet = {'{/Symbol \267}', '∙'};
  sym.div = {'{/Symbol \270}', '÷'};
  sym.neq = {'{/Symbol \271}', '≠'};
  sym.equiv = {'{/Symbol \272}', '≡'};
  sym.approx = {'{/Symbol \273}', '≈'};
  sym.ldots = {'{/Symbol \274}', '…'};
  sym.mid = {'{/Symbol \275}', '∣'};
  sym.aleph = {'{/Symbol \300}', 'ℵ'};
  sym.Im = {'{/Symbol \301}', 'ℑ'};
  sym.Re = {'{/Symbol \302}', 'ℜ'};
  sym.wp = {'{/Symbol \303}', '℘'};
  sym.otimes = {'{/Symbol \304}', '⊗'};
  sym.oplus = {'{/Symbol \305}', '⊕'};
  ## empty set, not circled slash division operator as in FLTK.
  sym.oslash = {'{/Symbol \306}', '⊘'};
  sym.emptyset = {'{/Symbol \306}', '∅'};
  sym.cap = {'{/Symbol \307}', '∩'};
  sym.cup = {'{/Symbol \310}', '∪'};
  sym.supset = {'{/Symbol \311}', '⊃'};
  sym.supseteq = {'{/Symbol \312}', '⊇'};
  sym.subset = {'{/Symbol \314}', '⊂'};
  sym.subseteq = {'{/Symbol \315}', '⊑'};
  sym.in = {'{/Symbol \316}', '∈'};
  sym.notin = {'{/Symbol \317}', '∋'};            # Not in OpenGL
  sym.angle = {'{/Symbol \320}', '∠'};
  sym.bigtriangledown = {'{/Symbol \321}', '▽'};  # Not in OpenGL
  sym.langle = {'{/Symbol \341}', '〈'};
  sym.rangle = {'{/Symbol \361}', '〉'};
  sym.nabla = {'{/Symbol \321}', '∇'};
  sym.prod = {'{/Symbol \325}', '∏'};             # Not in OpenGL
  sym.surd = {'{/Symbol \326}', '√'};
  sym.cdot = {'{/Symbol \327}', '⋅'};
  sym.neg = {'{/Symbol \330}', '¬'};
  sym.wedge = {'{/Symbol \331}', '∧'};
  sym.vee = {'{/Symbol \332}', '∨'};
  sym.Leftrightarrow = {'{/Symbol \333}', '⇔'};   # Not in OpenGL
  sym.Leftarrow = {'{/Symbol \334}', '⇐'};
  sym.Uparrow = {'{/Symbol \335}', '⇑'};          # Not in OpenGL
  sym.Rightarrow = {'{/Symbol \336}', '⇒'};
  sym.Downarrow = {'{/Symbol \337}', '⇓'};        # Not in OpenGL
  sym.diamond = {'{/Symbol \340}', '⋄'};          # Not in OpenGL
  sym.copyright = {'{/Symbol \343}', '©'};
  sym.lfloor = {'{/Symbol \353}', '⌊'};
  sym.lceil = {'{/Symbol \351}', '⌈'};
  sym.rfloor = {'{/Symbol \373}', '⌋'};
  sym.rceil = {'{/Symbol \371}', '⌉'};
  sym.int = {'{/Symbol \362}', '∫'};

endfunction

function retval = __do_enhanced_option__ (enhanced, obj)

  retval = "";
  if (enhanced)
    if (strcmp (obj.interpreter, "none"))
      retval = "noenhanced";
    else
      retval = "enhanced";
    endif
  endif

endfunction

function do_text (stream, gpterm, enhanced, obj, hax, screenpos)

  [label, f, s] = __maybe_munge_text__ (enhanced, obj, "string", ...
                                        obj.interpreter, gpterm);
  fontspec = create_fontspec (f, s, gpterm);
  lpos = obj.position;
  halign = obj.horizontalalignment;
  valign = obj.verticalalignment;
  angle = obj.rotation;
  units = obj.units;
  color = obj.color;
  if (nargin > 5)
    units = "screen";
    lpos = screenpos;
  elseif (strcmp (units, "normalized"))
    units = "graph";
  elseif (strcmp (get (hax, "yaxislocation"), "right")
          && strcmp (units, "data"))
    units = "second";
  else
    units = "";
  endif

  if (isnumeric (color))
    colorspec = get_text_colorspec (color);
  endif

  if (ischar (obj.string))
    num_lines = rows (obj.string);
    num_lines += numel (strfind (obj.string, "\n"));
  else
    num_lines = numel (obj.string);
  endif
  switch (valign)
    ## Text offset in characters.  Relies on gnuplot for font metrics.
    case "top"
      dy = -0.5;
    case "cap"
      dy = -0.5;
    case "middle"
      dy = 0.5 * (num_lines - 1);
    case "baseline"
      dy = 0.5 + (num_lines - 1);
    case "bottom"
      dy = 0.5 + (num_lines - 1);
  endswitch
  ## Gnuplot's Character units are different for x/y and vary with
  ## fontsize.  The aspect ratio of 1:1.7 was determined by experiment
  ## to work for eps/ps/etc.  For the MacOS aqua terminal a value of 2.5
  ## is needed.  However, the difference is barely noticeable.
  dx_and_dy = [(-dy * sind (angle)), (dy * cosd (angle))] .* [1.7 1];

  ## FIXME: Multiline text produced the gnuplot
  ##        "warning: ft_render: skipping glyph"
  if (__calc_dimensions__ (hax) == 3)
    zstr = sprintf (",%.15e", lpos(3));
  else
    zstr = "";
  endif
  fprintf (stream,
           ['set label "%s" at %s %.15e,%.15e%s %s rotate by %f offset character %f,%f %s %s front %s;' "\n"],
           label, units, lpos(1), lpos(2), zstr, halign, angle, dx_and_dy,
           fontspec, __do_enhanced_option__ (enhanced, obj), colorspec);

endfunction

function cdata = mapcdata (cdata, mode, clim, cmap_sz)

  if (ndims (cdata) == 3)
    ## True Color, clamp data to 8-bit
    clim = double (clim);
    cdata = double (cdata);
    clim_rng = clim(2) - clim(1);
    if (clim_rng != 0)
      cdata = 255 * (cdata - clim(1)) / clim_rng;
      cdata(cdata < 0) = 0;  cdata(cdata > 255) = 255;
    else
      cdata(:) = fix (255 / 2);
    endif
  else
    if (strcmp (mode, "scaled"))
      clim = double (clim);
      cdata = double (cdata);
      clim_rng = clim(2) - clim(1);
      if (clim_rng != 0)
        cdata = 1 + fix (cmap_sz * (cdata - clim(1)) / clim_rng);
      else
        cdata(:) = 1 + fix (cmap_sz / 2);
      endif
    else
      if (islogical (cdata) || isinteger (cdata))
        cdata += 1;
      else
        cdata = fix (cdata);
      endif
    endif
    cdata = max (1, min (cdata, cmap_sz));
  endif

endfunction