3

Consider the following 3D surface graphs created using the tikz-3dplot package:

\documentclass{article}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\usepackage{caption}
\usepackage{subcaption}
\usepackage[outline]{contour}
\contourlength{0.05em}

\begin{document}

\begin{figure}[ht]
 \hfill
 \begin{subfigure}{.333333\linewidth}
  \centering
  \tdplotsetmaincoords{70}{-22.5}
  \begin{tikzpicture}[scale=2.8,tdplot_main_coords]
  \foreach \index in {1,...,9}
   {\draw[domain=0:1,smooth]
      plot
        (\x,\index/10,
         {\x*\index/10*(\x+\index/10-\x*\index/10)});
    \draw[domain=0:1,smooth]
      plot
        (\index/10,\x,
         {\x*\index/10*(\x+\index/10-\x*\index/10)});}
  \draw
    (0,1,0) -- (1,1,1) -- (1,0,0);
  \draw[dashed]
    (0,0,1) node[left] {$1$} --
    (1,0,1) -- (1,1,1) -- (0,1,1) -- cycle;
  \draw[dashed]
    (1,0,1) -- (1,0,0) node[below] {$1\mathstrut$};
  \draw[dashed]
    (0,1,1) -- (0,1,0) node[below] {$1\mathstrut$};
  \draw[thick,latex-latex]
    (0,1.2,0) node[below] {$v\mathstrut$} --
    (0,0,0)   node[below] {$O\mathstrut$} --
    (1.2,0,0) node[below] {$u\mathstrut$};
  \draw[thick,-latex]
    (0,0,0) --
    (0,0,1.2) node[above] {\contour{white}{$C_{-1}(u,v)$}};
  \end{tikzpicture}
  \caption{$C_{-1}(u,v)$.}
 \end{subfigure}%
 \hfill
 \begin{subfigure}{.333333\linewidth}
  \centering
  \tdplotsetmaincoords{70}{-22.5}
  \begin{tikzpicture}[scale=2.8,tdplot_main_coords]
  \foreach \index in {1,...,9}
   {\draw[domain=0:1,smooth]
      plot
        (\x,\index/10,
         {\x*\index/10*(2-\x-\index/10+\x*\index/10)});
    \draw[domain=0:1,smooth]
      plot
        (\index/10,\x,
         {\x*\index/10*(2-\x-\index/10+\x*\index/10)});}
  \draw
    (0,1,0) -- (1,1,1) -- (1,0,0);
  \draw[dashed]
    (0,0,1) node[left] {$1$} --
    (1,0,1) -- (1,1,1) -- (0,1,1) -- cycle;
  \draw[dashed]
    (1,0,1) -- (1,0,0) node[below] {$1\mathstrut$};
  \draw[dashed]
    (0,1,1) -- (0,1,0) node[below] {$1\mathstrut$};
  \draw[thick,latex-latex]
    (0,1.2,0) node[below] {$v\mathstrut$} --
    (0,0,0)   node[below] {$O\mathstrut$} --
    (1.2,0,0) node[below] {$u\mathstrut$};
  \draw[thick,-latex]
    (0,0,0) --
    (0,0,1.2) node[above] {\contour{white}{$C_1(u,v)$}};
  \end{tikzpicture}
  \caption{$C_1(u,v)$.}
 \end{subfigure}%
 \hfill\strut
\caption{Plots of the Farlie--Gumbel--Morgenstern copulae~$C_{-1}$ and~$C_1$.}
\end{figure}

\end{document}

copulae


Is there a method to create the above 3D graphs, with perspective? More precisely, can anyone create a perspective drawing with two vanishing points on the horizon, which automates all necessary computations?

This answer by @JanHlavacek attempted to draw a cube with perspective, but I doubt the application to my situation.

  • 1
    Yes, but the only example I am aware of is this one. Terribly undervoted IMHO. Of course, asymptote does this, too. – user121799 Sep 4 '18 at 14:57
  • 1
    I need to correct myself. Here seems to be another package that deals with perspectives. Just found it now, and have no idea what is status is, nor have I tried it out. It is used in this answer. – user121799 Sep 4 '18 at 23:25
5

All the conceptual issues have been solved by Max in this fantastic answer, which I just copied in the updated answer. In my original answer, I used a more clumsy syntax, but this is no longer necessary since Max has fixed it.

UPDATED ANSWER: Max' coordinate parser works, according to what I find, just great. The only exception is when the coordinates contain a newline, i.e. stretch over more than one line. FIXED BY MAX It is just Max' stellar transformations + your code + tpp cs: added to all coordinates.

\documentclass{article}
% Max preamble
\usepackage{tikz}
\usepackage{tikz-3dplot}
\usepgfmodule{nonlineartransformations}
\usepackage{mathtools}
% Ruixi packages
\usepackage{caption}
\usepackage{subcaption}
\usepackage[outline]{contour}
\contourlength{0.05em}
% Max magic
\makeatletter 
% the first part is not in use here
\def\tikz@scan@transform@one@point#1{%
  \tikz@scan@one@point\pgf@process#1%
  \pgf@pos@transform{\pgf@x}{\pgf@y}}
\tikzset{%
  grid source opposite corners/.code args={#1and#2}{%
   \pgfextract@process\tikz@transform@source@southwest{%
     \tikz@scan@transform@one@point{#1}}%
   \pgfextract@process\tikz@transform@source@northeast{%
     \tikz@scan@transform@one@point{#2}}%
  },
  grid target corners/.code args={#1--#2--#3--#4}{%
   \pgfextract@process\tikz@transform@target@southwest{%
     \tikz@scan@transform@one@point{#1}}%
   \pgfextract@process\tikz@transform@target@southeast{%
     \tikz@scan@transform@one@point{#2}}%
   \pgfextract@process\tikz@transform@target@northeast{%
     \tikz@scan@transform@one@point{#3}}%
   \pgfextract@process\tikz@transform@target@northwest{%
     \tikz@scan@transform@one@point{#4}}%
  }
}

\def\tikzgridtransform{%
  \pgfextract@process\tikz@current@point{}%
  \pgf@process{%
    \pgfpointdiff{\tikz@transform@source@southwest}%
      {\tikz@transform@source@northeast}%
  }%
  \pgf@xc=\pgf@x\pgf@yc=\pgf@y%
  \pgf@process{%
    \pgfpointdiff{\tikz@transform@source@southwest}{\tikz@current@point}%
  }%
  \pgfmathparse{\pgf@x/\pgf@xc}\let\tikz@tx=\pgfmathresult%
  \pgfmathparse{\pgf@y/\pgf@yc}\let\tikz@ty=\pgfmathresult%
  %
  \pgfpointlineattime{\tikz@ty}{%
    \pgfpointlineattime{\tikz@tx}{\tikz@transform@target@southwest}%
      {\tikz@transform@target@southeast}}{%
    \pgfpointlineattime{\tikz@tx}{\tikz@transform@target@northwest}%
      {\tikz@transform@target@northeast}}%
}

% Initialize H matrix for perspective view
\pgfmathsetmacro\H@tpp@aa{1}\pgfmathsetmacro\H@tpp@ab{0}\pgfmathsetmacro\H@tpp@ac{0}%\pgfmathsetmacro\H@tpp@ad{0}
\pgfmathsetmacro\H@tpp@ba{0}\pgfmathsetmacro\H@tpp@bb{1}\pgfmathsetmacro\H@tpp@bc{0}%\pgfmathsetmacro\H@tpp@bd{0}
\pgfmathsetmacro\H@tpp@ca{0}\pgfmathsetmacro\H@tpp@cb{0}\pgfmathsetmacro\H@tpp@cc{1}%\pgfmathsetmacro\H@tpp@cd{0}
\pgfmathsetmacro\H@tpp@da{0}\pgfmathsetmacro\H@tpp@db{0}\pgfmathsetmacro\H@tpp@dc{0}%\pgfmathsetmacro\H@tpp@dd{1}

%Initialize H matrix for main rotation
\pgfmathsetmacro\H@rot@aa{1}\pgfmathsetmacro\H@rot@ab{0}\pgfmathsetmacro\H@rot@ac{0}%\pgfmathsetmacro\H@rot@ad{0}
\pgfmathsetmacro\H@rot@ba{0}\pgfmathsetmacro\H@rot@bb{1}\pgfmathsetmacro\H@rot@bc{0}%\pgfmathsetmacro\H@rot@bd{0}
\pgfmathsetmacro\H@rot@ca{0}\pgfmathsetmacro\H@rot@cb{0}\pgfmathsetmacro\H@rot@cc{1}%\pgfmathsetmacro\H@rot@cd{0}
%\pgfmathsetmacro\H@rot@da{0}\pgfmathsetmacro\H@rot@db{0}\pgfmathsetmacro\H@rot@dc{0}\pgfmathsetmacro\H@rot@dd{1}

\pgfkeys{
    /three point perspective/.cd,
        p/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#1))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ba{#2/#1}
                \pgfmathsetmacro\H@tpp@ca{#3/#1}
                \pgfmathsetmacro\H@tpp@da{ 1/#1}
                \coordinate (vp-p) at (#1,#2,#3);
            \fi
        },
        q/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#2))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ab{#1/#2}
                \pgfmathsetmacro\H@tpp@cb{#3/#2}
                \pgfmathsetmacro\H@tpp@db{ 1/#2}
                \coordinate (vp-q) at (#1,#2,#3);
            \fi
        },
        r/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#3))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ac{#1/#3}
                \pgfmathsetmacro\H@tpp@bc{#2/#3}
                \pgfmathsetmacro\H@tpp@dc{ 1/#3}
                \coordinate (vp-r) at (#1,#2,#3);
            \fi
        },
        coordinate/.code args={#1,#2,#3}{
           \pgfmathsetmacro\tpp@x{#1} %<- Max' fix
            \pgfmathsetmacro\tpp@y{#2}
            \pgfmathsetmacro\tpp@z{#3}
        },
}

\tikzset{
    view/.code 2 args={
        \pgfmathsetmacro\rot@main@theta{#1}
        \pgfmathsetmacro\rot@main@phi{#2}
        % Row 1
        \pgfmathsetmacro\H@rot@aa{cos(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@ab{sin(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@ac{0}
        % Row 2
        \pgfmathsetmacro\H@rot@ba{-cos(\rot@main@theta)*sin(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@bb{cos(\rot@main@phi)*cos(\rot@main@theta)}
        \pgfmathsetmacro\H@rot@bc{sin(\rot@main@theta)}
        % Row 3
        \pgfmathsetmacro\H@m@ca{sin(\rot@main@phi)*sin(\rot@main@theta)}
        \pgfmathsetmacro\H@m@cb{-cos(\rot@main@phi)*sin(\rot@main@theta)}
        \pgfmathsetmacro\H@m@cc{cos(\rot@main@theta)}
        % Set vector values
        \pgfmathsetmacro\vec@x@x{\H@rot@aa}
        \pgfmathsetmacro\vec@y@x{\H@rot@ab}
        \pgfmathsetmacro\vec@z@x{\H@rot@ac}
        \pgfmathsetmacro\vec@x@y{\H@rot@ba}
        \pgfmathsetmacro\vec@y@y{\H@rot@bb}
        \pgfmathsetmacro\vec@z@y{\H@rot@bc}
        % Set pgf vectors
        \pgfsetxvec{\pgfpoint{\vec@x@x cm}{\vec@x@y cm}}
        \pgfsetyvec{\pgfpoint{\vec@y@x cm}{\vec@y@y cm}}
        \pgfsetzvec{\pgfpoint{\vec@z@x cm}{\vec@z@y cm}}
    },
}

\tikzset{
    perspective/.code={\pgfkeys{/three point perspective/.cd,#1}},
    perspective/.default={p={(15,0,0)},q={(0,15,0)},r={(0,0,50)}},
}

\tikzdeclarecoordinatesystem{three point perspective}{
    \pgfkeys{/three point perspective/.cd,coordinate={#1}}
    \pgfmathsetmacro\temp@p@w{\H@tpp@da*\tpp@x + \H@tpp@db*\tpp@y + \H@tpp@dc*\tpp@z + 1}
    \pgfmathsetmacro\temp@p@x{(\H@tpp@aa*\tpp@x + \H@tpp@ab*\tpp@y + \H@tpp@ac*\tpp@z)/\temp@p@w}
    \pgfmathsetmacro\temp@p@y{(\H@tpp@ba*\tpp@x + \H@tpp@bb*\tpp@y + \H@tpp@bc*\tpp@z)/\temp@p@w}
    \pgfmathsetmacro\temp@p@z{(\H@tpp@ca*\tpp@x + \H@tpp@cb*\tpp@y + \H@tpp@cc*\tpp@z)/\temp@p@w}
    \pgfpointxyz{\temp@p@x}{\temp@p@y}{\temp@p@z}
}
\tikzaliascoordinatesystem{tpp}{three point perspective}

\makeatother


\begin{document}
\begin{figure}[ht]
 \hfill
 \begin{subfigure}{.333333\linewidth}
  \centering
  \tdplotsetmaincoords{70}{-22.5}
  \begin{tikzpicture}[scale=pi,%tdplot_main_coords
  view={\tdplotmaintheta}{\tdplotmainphi},
            perspective={
                p = {(4,0,1.5)},
                q = {(0,4,1.5)},
            }
  ]
  \foreach \index in {1,...,9}
   {\draw[domain=0:1,smooth]
      plot
        (tpp cs:\x,\index/10,{\x*\index/10*(\x+\index/10-\x*\index/10)});
    \draw[domain=0:1,smooth]
      plot
        (tpp cs:\index/10,\x,{\x*\index/10*(\x+\index/10-\x*\index/10)});}
  \draw
    (tpp cs:0,1,0) -- (tpp cs:1,1,1) -- (tpp cs:1,0,0);
  \draw[dashed]
    (tpp cs:0,0,1) node[left] {$1$} --
    (tpp cs:1,0,1) -- (tpp cs:1,1,1) -- (tpp cs:0,1,1) -- cycle;
  \draw[dashed]
    (tpp cs:1,0,1) -- (tpp cs:1,0,0) node[below] {$1\mathstrut$};
  \draw[dashed]
    (tpp cs:0,1,1) -- (tpp cs:0,1,0) node[below] {$1\mathstrut$};
  \draw[thick,latex-latex]
    (tpp cs:0,1.2,0) node[below] {$v\mathstrut$} --
    (tpp cs:0,0,0)   node[below] {$O\mathstrut$} --
    (tpp cs:1.2,0,0) node[below] {$u\mathstrut$};
  \draw[thick,-latex]
    (tpp cs:0,0,0) --
    (tpp cs:0,0,1.2) node[above] {\contour{white}{$C_{-1}(u,v)$}};
  \end{tikzpicture}
  \caption{$C_{-1}(u,v)$.}
 \end{subfigure}%
 \hfill
 \begin{subfigure}{.333333\linewidth}
  \centering
  \tdplotsetmaincoords{70}{-22.5}
  \begin{tikzpicture}[scale=pi,%tdplot_main_coords]
  view={\tdplotmaintheta}{\tdplotmainphi},
            perspective={
                p = {(4,0,1.5)},
                q = {(0,4,1.5)},
            }
  ]
  \foreach \index in {1,...,9}
   {\draw[domain=0:1,smooth]
      plot
        (tpp cs:\x,\index/10,{\x*\index/10*(2-\x-\index/10+\x*\index/10)});
    \draw[domain=0:1,smooth]
      plot
        (tpp cs:\index/10,\x,{\x*\index/10*(2-\x-\index/10+\x*\index/10)});}
  \draw
    (tpp cs:0,1,0) -- (tpp cs:1,1,1) -- (tpp cs:1,0,0);
  \draw[dashed]
    (tpp cs:0,0,1) node[left] {$1$} --
    (tpp cs:1,0,1) -- (tpp cs:1,1,1) -- (tpp cs:0,1,1) -- cycle;
  \draw[dashed]
    (tpp cs:1,0,1) -- (tpp cs:1,0,0) node[below] {$1\mathstrut$};
  \draw[dashed]
    (tpp cs:0,1,1) -- (tpp cs:0,1,0) node[below] {$1\mathstrut$};
  \draw[thick,latex-latex]
    (tpp cs:0,1.2,0) node[below] {$v\mathstrut$} --
    (tpp cs:0,0,0)   node[below] {$O\mathstrut$} --
    (tpp cs:1.2,0,0) node[below] {$u\mathstrut$};
  \draw[thick,-latex]
    (tpp cs:0,0,0) --
    (tpp cs:0,0,1.2) node[above] {\contour{white}{$C_1(u,v)$}};
  \end{tikzpicture}
  \caption{$C_1(u,v)$.}
 \end{subfigure}%
 \hfill\strut
\caption{Plots of the Farlie--Gumbel--Morgenstern copulae~$C_{-1}$ and~$C_1$.}
\end{figure}
\end{document}

The perspective is defined in

perspective={
                p = {(4,0,1.5)},
                q = {(0,4,1.5)},
            }

which you may adjust to your needs.

enter image description here

  • 1
    Oh! I so wish @Max turned the code into a package. – Ruixi Zhang Sep 5 '18 at 14:27
  • @RuixiZhang Me too. He could then add this code as well... – user121799 Sep 5 '18 at 14:33
  • 2
    @RuixiZhang In this answer by marmot, the vanishing point in z-direction is already turned off. The default value of (0,0,50) only gets activated when you call perspective without argument. If you specify only one or two vanishing points in the argument of perspective, the remaining points simply get turned off. I figured that would be the most intuitive option – Max Sep 5 '18 at 17:39
  • 2
    @RuixiZhang And about turning it into a package, I was thinking about that but it seems to me that a Tikz library would be more appropriate (still have to figure out how to implement that). In a few weeks I will have some more time to work on this probably. – Max Sep 6 '18 at 6:25
  • 1
    @Max Yes, this package is a start, but there is certainly some room for improvement. What I wanted to say is that a simple collection of the nice things you have created in a single package would be a great thing to have. – user121799 Sep 7 '18 at 17:59

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.