## Copyright (C) 2009 Soren Hauberg ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn{Function File} print_tikz () ## @deftypefnx{Function File} print_tikz (@var{fig}) ## @deftypefnx{Function File} print_tikz (@var{fig}, @var{filename}) ## @deftypefnx{Function File} address@hidden =} print_tikz (@dots{}) ## @end deftypefn function retval = print_tikz (fig = gcf (), filename = []) ## Make sure we got a figure type = get (fig, "type"); if (!strcmp (type, "figure")) error ("print_tikz: first argument must be a valid figure handle"); endif figure (fig); # XXX: can we avoid this? ## Paper information paperunits = get (fig, "paperunits"); papersize = get (fig, "papersize"); paperposition = get (fig, "paperposition"); paperorientation = get (fig, "paperorientation"); paper = struct ("units", paperunits, "size", papersize, "position", paperposition, "orientation", paperorientation); ## Compute transformation between units if (strcmpi (paperunits, "inches")) paper.in2cm = 2.54; else paper.in2cm = 1; endif xl = xlim (); yl = ylim (); paper.ax = paper.in2cm * paperposition (3) / (xl (2) - xl (1)); paper.ay = paper.in2cm * paperposition (4) / (yl (2) - yl (1)); paper.bx = paper.in2cm * paperposition (1); paper.by = paper.in2cm * paperposition (2); ## Write header children = get (fig, "children"); text = "\ \\documentclass{minimal}\n\ \\usepackage{tikz}\n\ \\usepackage{lscape}\n\ \n\ \\begin{document}\n\ \n"; if (strcmp (paperorientation, "landscape")) text = strcat (text, "\\begin{lscape}\n"); endif text = strcat (text, "\\begin{tikzpicture}[scale=2]\n"); ## Traverse children for i = 1:length (children) kid = children (i); t = print_kid (kid, paper); text = strcat (text, t); endfor ## Write footer text = strcat (text, "\\end{tikzpicture}\n"); if (strcmp (paperorientation, "landscape")) text = strcat (text, "\\end{lscape}\n"); endif text = strcat (text, "\\end{document}\n"); ## Return output or write it to a file if (nargout > 0) retval = text; elseif (ischar (filename)) fid = fopen (filename, "w"); if (fid < 0) error ("print_tikz: couldn't open '%s' for writing", filename); endif fputs (fid, text); fclose (fid); elseif (isnumeric (filename)) fputs (filename, text); ## Treat 'filename' as a file ID else disp (text); endif endfunction function retval = print_kid (kid, paper) persistent num_call = 0; num_call ++; retval = ""; visible = get (kid, "visible"); if (!strcmp (visible, "off")) type = get (kid, "type"); switch (type) case "line" retval = draw_line (kid, num_call, paper); case "axes" retval = draw_axes (kid, paper); otherwise printf ("Skipping type = %s\n", type); endswitch endif # if visible children = get (kid, "children"); for i = 1:length (children) kid = children (i); t = print_kid (kid, paper); retval = strcat (retval, t); endfor endfunction function retval = linestyle_to_tikz (linestyle) switch (linestyle) case "-" retval = ""; case "--" retval = "dashed"; case ":" retval = "dotted"; case "none" retval = "none"; otherwise warning ("print_tikz: unsupported linestyle '%s'", linestyle); retval = ""; endswitch endfunction function retval = draw_line (kid, num_call, paper) ## Get data xdata = paper.ax * get (kid, "xdata") + paper.bx; ydata = paper.ay * get (kid, "ydata") + paper.by; color = get (kid, "color"); linestyle = get (kid, "linestyle"); marker = get (kid, "marker"); markeredgecolor = get (kid, "markeredgecolor"); markerfacecolor = get (kid, "markerfacecolor"); markersize = 0.005 * get (kid, "markersize") * paper.in2cm; ## Setup line style deflinecolor = sprintf ("\\definecolor{linecolor%d}{rgb}{%f, %f, %f}\n", num_call, color (1), color (2), color (3)); deflinestyle = linestyle_to_tikz (linestyle); ## The actual line drawing command if (!strcmp (deflinestyle, "none")) intro = sprintf ("\\draw [color=linecolor%d, %s]\n", num_call, deflinestyle); val = strcat (sprintf ("(%f, %f) -- ", [xdata(1:end-1).', ydata(1:end-1).'].'), sprintf ("(%f, %f)", xdata (end), ydata (end))); outro = ";\n"; line = strcat (deflinecolor, intro, val, outro); else line = ""; endif ## Define marker colors edge_name = sprintf ("markeredgecolor%d", num_call); [markeredgecolor, edge_name] = get_marker_color (markeredgecolor, edge_name, color); face_name = sprintf ("markerfacecolor%d", num_call); [markerfacecolor, face_name] = get_marker_color (markerfacecolor, face_name, color); ## The actual marker drawing command markers = ""; if (!isempty (markeredgecolor) || !isempty (markerfacecolor)) markers = strcat (markeredgecolor, markerfacecolor); if (isempty (markeredgecolor)) intro = sprintf ('\\draw [fill=%s] ', face_name); elseif (isempty (markerfacecolor)) intro = sprintf ('\\draw [thick,draw=%s] ', edge_name); else intro = sprintf ('\\draw [thick,draw=%s,fill=%s] ', edge_name, face_name); endif switch (marker) case "o" cmd = @(x, y) sprintf ('%s (%f, %f) circle (%f); \n', intro, x, y, markersize); case "." cmd = @(x, y) sprintf ('%s (%f, %f) circle (%f); \n', intro, x, y, 0.1*markersize); case "+" delta = markersize; cmd = @(x, y) sprintf ('%s (%f, %f) -- (%f, %f);\n%s (%f, %f) -- (%f, %f);\n', intro, x-delta, y, x+delta, y, intro, x, y-delta, x, y+delta); case "x" delta = markersize; cmd = @(x, y) sprintf ('%s (%f, %f) -- (%f, %f);\n%s (%f, %f) -- (%f, %f);\n', intro, x-delta, y+delta, x+delta, y-delta, intro, x+delta, y+delta, x-delta, y-delta); case "*" cmd = @(x, y) sprintf ('%s (%f, %f) node {*}; \n', intro, x, y); case "p" cmd = @(x, y) print_pentagram (x, y, intro, markersize); case "s" cmd = @(x, y) print_square (x, y, intro, markersize); case "d" cmd = @(x, y) print_diamond (x, y, intro, markersize); case "none" cmd = []; otherwise cmd = []; warning ("print_tikz: no support for marker '%s'", marker); endswitch if (!isempty (cmd)) for k = 1:length (xdata) val = cmd (xdata (k), ydata (k)); markers = strcat (markers, val); endfor else markers = ""; endif endif retval = strcat (line, markers); endfunction function retval = draw_axes (kid, paper) xlim = paper.ax * get (kid, "xlim") + paper.bx; ylim = paper.ay * get (kid, "ylim") + paper.by; xtick = paper.ax * get (kid, "xtick") + paper.bx; ytick = paper.ay * get (kid, "ytick") + paper.by; xticklabel = get (kid, "xticklabel"); yticklabel = get (kid, "yticklabel"); ## Draw axes fmt = "\\draw [thick] (%f, %f) -- (%f, %f) -- (%f, %f) -- (%f, %f) -- (%f, %f);\n"; ax = sprintf (fmt, xlim (1), ylim (1), xlim (1), ylim (2), xlim (2), ylim (2), xlim (2), ylim (1), xlim (1), ylim (1)); ## Draw tics ticsize = 0.1; # XXX: compute this from data xt = yt = ""; for k = 1:length (xtick) xt1 = sprintf ("\\draw [thick] (%f, %f) -- (%f, %f) ", xtick (k), ylim (1), xtick (k), ylim (1) - ticsize); xt2 = sprintf ("node [anchor=north] {%s};\n", xticklabel {k}); xt = strcat (xt, xt1, xt2); endfor for k = 1:length (ytick) yt1 = sprintf ("\\draw [thick] (%f, %f) -- (%f, %f) ", xlim (1), ytick (k), xlim (1) - ticsize, ytick (k)); yt2 = sprintf ("node [anchor=east] {%s};\n", yticklabel {k}); yt = strcat (yt, yt1, yt2); endfor retval = strcat (ax, xt, yt); endfunction function [define, name] = get_marker_color (markercolor, name, color) if (strcmp (markercolor, "auto")) markercolor = color; endif if (strcmp (markercolor, "none")) define = ""; name = ""; else define = sprintf ("\\definecolor{%s}{rgb}{%f, %f, %f}\n", name, markercolor); endif endfunction function retval = print_pentagram (x, y, intro, markersize) ## XXX: This approach is just waaay to hacky t = linspace (0, 2*pi, 6); innerscale = 0.3 * markersize; outerscale = innerscale; x_nodes (1:2:12) = outerscale * sin (t) + x; x_nodes (2:2:12) = innerscale * sin (t+0.5) + x; y_nodes (1:2:12) = outerscale * cos (t) + y; y_nodes (2:2:12) = innerscale * cos (t+0.5) + y; star = sprintf ('(%f, %f) -- ', [x_nodes(1:end-1).', y_nodes(1:end-1).'].'); star = strcat (star, sprintf ('(%f, %f)', x_nodes (end), y_nodes (end))); retval = strcat (intro, star, ";\n"); endfunction function retval = print_square (x, y, intro, markersize) delta = markersize; square = print_closed_polygon ([x-delta, x-delta, x+delta, x+delta], [y-delta, y+delta, y+delta, y-delta]); retval = strcat (intro, square, ";\n"); endfunction function retval = print_diamond (x, y, intro, markersize) delta = markersize; diamond = print_closed_polygon ([x-delta, x, x+delta, x], [y, y+delta, y, y-delta]); retval = strcat (intro, diamond, ";\n"); endfunction function retval = print_closed_polygon (x, y) polygon = sprintf ('(%f, %f) -- ', [x.', y.'].'); closed = sprintf ('(%f, %f)', x (1), y (1)); retval = strcat (polygon, closed, ";\n"); endfunction %!demo %! figure ("paperunits", "centimeters", "papersize", [6, 4], "paperposition", [1, 0.5, 5, 3]); %! x = linspace (0, 5, 15); %! t = linspace (0, 2*pi, 25); %! plot (x, sqrt (x), "p", "linestyle", "none", "markerfacecolor", [0.1, 0.9, 0.1]); %! hold on %! plot (x, sin (x), "b-o", "markeredgecolor", [0.1, 0.9, 0.1], %! "markerfacecolor", [0.4, 0.4, 0.4]); %! plot (x, cos (x), "r:x"); %! plot (x, sqrt (1 + cos (x)), "--s", "color", [0.9, 0.1, 0.9], %! "markersize", 10, "markerfacecolor", [0.1, 0.9, 0.9]); %! plot (cos (t), sin (t), "d"); %! plot (5*rand (1, 1000), 2*rand (1, 1000)-2, 'k.'); %! plot (x, (x-3).^2, '*') %! hold off %! set (gca, "ytick", [0, 1.5]); %! set (gca, "yticklabel", {"cheese", "$\\cos (\\omega) \\neq \\mathrm{cheese}$"}); %! #axis off %! print_tikz (:, "mytest.tex");