## 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 = [], scale = 1) ## 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, sprintf ("\\begin{tikzpicture}[scale=%d]\n", scale)); ## 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 "-." retval = "dash pattern=on 2pt off 1pt on 1pt off 1pt"; 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.015 * get (kid, "markersize") * paper.in2cm; linewidth = get (kid, "linewidth"); ## 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 ,line width=%f]\n", num_call, deflinestyle, linewidth); 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 [draw=%s] ', edge_name); else intro = sprintf ('\\draw [draw=%s, fill=%s] ', edge_name, face_name); endif switch (marker (1)) case "o" cmd = @(x, y) print_circle (x, y, intro, markersize); case "." cmd = @(x, y) print_circle (x, y, intro, 0.2*markersize); case "+" cmd = @(x, y) print_plus (x, y, intro, markersize); case "x" cmd = @(x, y) print_x (x, y, intro, markersize); case "*" cmd = @(x, y) print_asterix (x, y, intro, markersize); case "p" cmd = @(x, y) print_pentagram (x, y, intro, markersize); case "h" cmd = @(x, y) print_hexagram (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 "^" cmd = @(x, y) print_triangle (x, y, 0, intro, markersize); case "v" cmd = @(x, y) print_triangle (x, y, pi, intro, markersize); case ">" cmd = @(x, y) print_triangle (x, y, pi/2, intro, markersize); case "<" cmd = @(x, y) print_triangle (x, y, 3*pi/2, 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_circle (x, y, intro, markersize) retval = sprintf ('%s (%f, %f) circle (%f); \n', intro, x, y, markersize); endfunction function retval = print_x (x, y, intro, markersize) delta = markersize; retval = sprintf (repmat ('%s (%f, %f) -- (%f, %f);\n', 1, 2), intro, x-delta, y+delta, x+delta, y-delta, intro, x+delta, y+delta, x-delta, y-delta); endfunction function retval = print_plus (x, y, intro, markersize) delta = markersize; retval = sprintf (repmat ('%s (%f, %f) -- (%f, %f);\n', 1, 2), intro, x-delta, y, x+delta, y, intro, x, y-delta, x, y+delta); 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 = markersize; 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 = print_closed_polygon (x_nodes, y_nodes); retval = strcat (intro, star, ";\n"); endfunction function retval = print_hexagram (x, y, intro, markersize) ## XXX: This approach is just waaay to hacky t = linspace (0, 2*pi, 7); innerscale = 0.3 * markersize; outerscale = markersize; x_nodes (1:2:14) = outerscale * sin (t) + x; x_nodes (2:2:14) = innerscale * sin (t+0.5) + x; y_nodes (1:2:14) = outerscale * cos (t) + y; y_nodes (2:2:14) = innerscale * cos (t+0.5) + y; star = print_closed_polygon (x_nodes, y_nodes); retval = strcat (intro, star, ";\n"); endfunction function retval = print_asterix (x, y, intro, markersize) delta = markersize; x11 = 0; y11 = delta; x12 = 0; y12 = -delta; x21 = sin ( pi/3) * delta; y21 = cos (pi/3) * delta; x22 = sin (4*pi/3) * delta; y22 = cos (4*pi/3) * delta; x31 = sin (2*pi/3) * delta; y31 = cos (2*pi/3) * delta; x32 = sin (5*pi/3) * delta; y32 = cos (5*pi/3) * delta; retval = sprintf (repmat ('%s (%f, %f) -- (%f, %f);\n', 1, 3), intro, x + x11, y + y11, x + x12, y + y12, intro, x + x21, y + y21, x + x22, y + y22, intro, x + x31, y + y31, x + x32, y + y32); 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_triangle (x, y, angle, intro, markersize) radius = markersize / cos (pi/6); angles = angle + [0, 2*pi/3, 4*pi/3]; X = x + radius * sin (angles); Y = y + radius * cos (angles); triangle = print_closed_polygon (X, Y); retval = strcat (intro, triangle, ";\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", [10, 6], "paperposition", [1, 0.5, 8, 5]); %! 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], 'linewidth', 3); %! plot (x, cos (x), "r:+", 'linewidth', 1.5); %! 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)+4, sin (t)+5, "kd"); %! plot (rand (1, 100), 2*rand (1, 100)+3, 'k.'); %! plot (rand (1, 100)+1, 2*rand (1, 100)+3, 'r^'); %! plot (rand (1, 100)+2, 2*rand (1, 100)+3, 'g>'); %! plot (rand (1, 100)+3, 2*rand (1, 100)+3, 'bv'); %! plot (rand (1, 100)+4, 2*rand (1, 100)+3, 'c<', 'markerfacecolor', [0.5, 0.5, 0.5]); %! plot (x, (x-3).^2 - 1, 'g*-.', 'markersize', 10) %! plot (x, repmat (6, size (x)), 'gh', 'markerfacecolor', [0, 1, 0], 'markersize', 20, %! 'markeredgecolor', [0, 0, 0]) %! hold off %! set (gca, "ytick", [0, 2.5]); %! set (gca, "yticklabel", {"cheese", "$\\cos (\\omega) \\neq \\mathrm{cheese}$"}); %! #axis off %! print_tikz (:, "mytest.tex"); % !demo % ! figure ("paperunits", "centimeters", "papersize", [10, 6], "paperposition", [1, 0.5, 8, 5]); % ! data = randn (1000, 1); % ! hist (data) % ! print_tikz (:, "mytest2.tex");