16

Although PGFplots is the perfect tool for many depictions, it unfortunately does not have a properly working z buffer for intersecting surfaces (at this time, 10-09-2015). I'm trying to overcome this problem by plotting in gnuplot with set terminal tikz and then putting the plots in a PGFplots axis environment. I cannot seem to manage the latter, though.

I use the picture

from http://gnuplot.sourceforge.net/demo_5.0/surface2.9.gnu as an example, where I changed the terminal to tikz:

set terminal tikz standalone
set output 'main.tex'
set dummy u, v
set key bmargin center horizontal Right noreverse enhanced autotitle nobox
set parametric
set view 50, 30, 1, 1
set isosamples 50, 20
set hidden3d back offset 1 trianglepattern 3 undefined 1 altdiagonal bentover
set style data lines
set ticslevel 0
set title "Interlocking Tori" 
set urange [ -3.14159 : 3.14159 ] noreverse nowriteback
set vrange [ -3.14159 : 3.14159 ] noreverse nowriteback
splot cos(u)+.5*cos(u)*cos(v),sin(u)+.5*sin(u)*cos(v),.5*sin(v) with lines,       1+cos(u)+.5*cos(u)*cos(v),.5*sin(v),sin(u)+.5*sin(u)*cos(v) with lines

The resulting tex file main.tex has the following content

\documentclass[10pt]{article}
\usepackage[T1]{fontenc}
\usepackage{textcomp}

\usepackage[utf8x]{inputenc}

\usepackage{gnuplot-lua-tikz}
\pagestyle{empty}
\usepackage[active,tightpage]{preview}
\PreviewEnvironment{tikzpicture}
\setlength\PreviewBorder{\gpbboxborder}
\begin{document}

\begin{tikzpicture}[gnuplot]
%% generated with GNUPLOT 4.6p5 (Lua 5.1; terminal rev. 99, script rev. 100)
%% Thu 10 Sep 2015 01:40:19 PM CEST
\path (0.000,0.000) rectangle (12.500,8.750);
\gpcolor{color=gp lt color border}
\node[gp node center] at (6.250,8.163) {Interlocking Tori};
\gpcolor{color=gp lt color 0}
\gpsetlinetype{gp lt plot 0}
\gpsetlinewidth{1.00}
\draw[gp path] (6.400,6.200)--(6.110,6.207);

(...A lot of \draw[gp path] commands...)
%% coordinates of the plot area
\gpdefrectangularnode{gp plot 1}{\pgfpoint{1.800cm}{1.387cm}}{\pgfpoint{10.700cm}{7.979cm}}
\end{tikzpicture}
%% gnuplot variables
\end{document}

from which it is clear that there is no use of a PGFplots axis environment.

Compiling with lualatex -shell-escape main.tex gives , which 'solves' the z buffer problem. But how do I get these drawings in a nice PGFplots axis enviroment?

7
  • 1
    I suppose that it makes little difference between \includegraphics{gnuplotresult.pdf} and typesetting the tikz file generated by gnuplot. What you need to is to couple the existing 2d projection generated by gnuplot with the axis of pgfplots; and that is a use-case of \addplot3 graphics. I suppose the associated sections in the reference manual are the best at hand; the key idea is to map a couple of 2d locations to their 3d coordinates and tell that to pgfplots. Sep 11, 2015 at 20:18
  • related (although it might be distracting/misleading since the solution is closely tied to matlab): tex.stackexchange.com/questions/52987/… . Another one tex.stackexchange.com/questions/78855/… Sep 11, 2015 at 20:19
  • @ChristianFeuersänger I understand your 'key idea', but this would just be reverse engineering, right? Since gnuplot has already determined the projection of the 3d coordinates into 2d, all I need from gnuplot is to tell me which 3d coordinates it projected into 2d. This is dependent on the azimuth and elevation of the view, based on which gnuplot does z buffering. Unfortunately, I do not know how to get this information from gnuplot.
    – Adriaan
    Sep 14, 2015 at 7:25
  • @ChristianFeuersänger Nonetheless, don't you think it would be better if a proper z buffer (for multiple plot objects) is built for pgfplots? I believe this is the only feature that is really missing from pgfplots and withholds it from being the perfect tool for making graphs in LaTeX, not only in 2D, but then also in 3D. It would solve this particular Stack Exchange question, and many many others. Perhaps I could even help you out. You have my contact data, so let me know ;).
    – Adriaan
    Sep 14, 2015 at 7:32
  • Regarding the first comment: it is somewhat more than reverse engineering because it would fix the rotation (which, as you said, is already known and will be simple to migrate) but also the alignment with the descriptions (i.e. the shifts). But: yes, you could include it as graphics and overlay a suitable axis (perhaps with empty tick labels). Sep 14, 2015 at 21:33

1 Answer 1

4

Before @Christian Feuersänger introduces any good interface, we may parameterize the surfaces carefully and make use of the existing sorting algorithm.

\documentclass[border=9,tikz]{standalone}
\usepackage{pgfplots}\pgfplotsset{compat=newest}
\begin{document}

\pgfmathdeclarefunction{X}{0}{%
    \pgfmathparse{
        y<121?
            cos(x)*(3+cos(3*y))
            :
            (y<139?
                inf
                :
                3+cos(x)*(3+cos(3*y))
            )
    }%
}
\pgfmathdeclarefunction{Y}{0}{%
    \pgfmathparse{
        y<121?
            sin(x)*(3+cos(3*y))
            :
            (y<139?
                inf
                :
                sin(3*y)
            )
    }%
}
\pgfmathdeclarefunction{Z}{0}{%
    \pgfmathparse{
        y<121?
            sin(3*y)
            :
            (y<139?
                inf
                :
                sin(x)*(3+cos(3*y))
            )
    }%
}

\tikz[cap=round,join=round]{
    \begin{axis}[axis equal]
        \addplot3[surf,unbounded coords=jump,
                  domain  =0:360,samples  =27,
                  domain y=0:260,samples y=27,
                  z buffer=sort,point meta=x]
            (X,Y,Z);
    \end{axis}
}

\end{document}

Even more carefully

\documentclass[border=9,tikz]{standalone}
\usepackage{pgfplots}\pgfplotsset{compat=newest}
\begin{document}

\pgfmathdeclarefunction{X}{0}{%
    \pgfmathparse{
        y<121?
            cos(x)*(3+cos(3*y))
            :
            (y<139?
                inf
                :
                (y<261?
                    4+cos(x)*(3+cos(3*y))
                    :
                    (y<279?
                        inf
                        :
                        8+cos(x)*(3+cos(3*y))
                    )
                )
            )
    }%
}
\pgfmathdeclarefunction{Y}{0}{%
    \pgfmathparse{
        y<121?
            sin(x)*(3+cos(3*y))
            :
            (y<139?
                inf
                :
                (y<261?
                    sin(3*y)
                    :
                    (y<279?
                        inf
                        :
                        sin(x)*(3+cos(3*y))
                    )
                )
            )
    }%
}
\pgfmathdeclarefunction{Z}{0}{%
    \pgfmathparse{
        y<121?
            sin(3*y)
            :
            (y<139?
                inf
                :
                (y<261?
                    sin(x)*(3+cos(3*y))
                    :
                    (y<279?
                        inf
                        :
                        sin(3*y)
                    )
                )
            )
    }%
}

\tikz[cap=round,join=round]{
    \begin{axis}[axis equal]
        \addplot3[surf,unbounded coords=jump,
                  domain  =0:360,samples  =27,
                  domain y=0:400,samples y=41,
                  z buffer=sort,point meta=x]
            (X,Y,Z);
    \end{axis}
}

\end{document}

Edit

Similar tricks is used in

So basically the setting

                  domain  =0:360,samples  =36,
                  domain y=0:260,samples y=27,

will set up the domain

and the setting

                  domain  =0:360,samples  =36,
                  domain y=0:400,samples y=41,

will set up the domain

By giving that unbounded coords=jump, pgfplots will drop the coordinates that maps to infinity and cut the surface into two pieces. In three-tours case, of course, pgfplots cuts the surface into three pieces.

2
  • Nice to see that this topic is still of interest ;). I don't understand where the values 121, 139, 261 and 279 come from. Can you please explain this to me? Could you perhaps document your code a bit so that the idea is more clear? Thanks.
    – Adriaan
    Apr 21, 2017 at 10:03
  • @ Adriaan See my edit. So 121 is merely something between 120 and 130.
    – Symbol 1
    Apr 21, 2017 at 13:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.