Truncando gráfico de superfície 3D singular com valores grandes

Truncando gráfico de superfície 3D singular com valores grandes

Eu queria saber como traçar uma superfície singular como z=1/(x*y)^2(a função na qual estou trabalhando é muito mais complicada). O que eu gostaria de alcançar é mostrado abaixo:

gráficos 3D externos

Wolfram Alpha (esquerda) faz um ótimo trabalho, e Maple (direita) também não é tão ruim. Para melhorar a integração do LaTeX no meu documento (consistência de fonte e tamanho), tentei usar pgfplots diretamente, com o seguinte resultado:

\documentclass[]{article}
\usepackage{pgfplots}

\begin{document}
\begin{tikzpicture}
\begin{axis}[zmin=0,zmax=1000,restrict z to domain=0:1000]
    \addplot3[surf,samples=50,domain=-1:1,y domain=-1:1]{1/(x*y)^2};
\end{axis}
\end{tikzpicture}
\end{document}

pgfplots

Obviamente, o truncamento no limite superior da caixa da opção restrict z to domainnão é muito bom. A remoção desta opção não resulta em nenhum truncamento, o que também não é legal. Até agora, não encontrei uma maneira de fazer isso corretamente. Definitivamente estou me perguntando como produzirum enredo tão lindodo módulo da função Gamma. Talvez exista alguma maneira adequada de importar um gráfico de superfície 3D de um software externo para o LaTeX? Alguma solução alternativa*?

*Eu estava pensando em tentar o TikZ ou Asymptote nativo, mas pode haver soluções mais simples. Usar software externo como Matlab para executar tarefas gráficas complexas é bastante comum ao trabalhar com pgfplots, mas nunca fiz isso para gráficos 3D e estou me perguntando como isso poderia funcionar. Além disso, pensei em importar dados de uma tabela, mas provavelmente enfrentarei outros problemas. Eu também tentei filtrar

\begin{axis}[zmin=0,zmax=1000,filter point/.code={%
        \pgfmathparse
        {\pgfkeysvalueof{/data point/z}>1000}%
        \ifpgfmathfloatcomparison
        \pgfkeyssetvalue{/data point/z}{nan}%
        \fi
    }]
    \addplot3[surf,unbounded coords=jump,samples=50,domain=-1:1,y domain=-1:1]{1/(x*y)^2};
\end{axis}

com o mesmo resultado feio.

Responder1

Uma primeira abordagemé parametrizar a função ou desenhá-la com coordenadas polares. Isto pode ser um desafio árduo no caso de funções complexas como aquela em que você está trabalhando.

Uma segunda abordagemé usar a opção com estrela *para restrict z to domain*=0:1000recortar os valores grandes. No entanto, a desvantagem é que a superfície de truncamento é desenhada:

insira a descrição da imagem aqui

MWE:

\documentclass[]{article}
\usepackage{pgfplots}

\begin{document}
 \pgfplotsset{compat=1.17}
\begin{tikzpicture}
\begin{axis}[zmin=0,zmax=1000,restrict z to domain*=0:1000]
    \addplot3[surf,samples=85, samples y= 85,domain=-1:1,y domain=-1:1,opacity=0.5]{1/(x*y)^2};
\end{axis}
\end{tikzpicture}
\end{document}

Uma terceira abordagembaseado em umGambiarradado porChristian Feuersänger(autor de Pgfplots) do segundo é sobrepor a superfície truncada com outra cor de superfície. Teoricamente, isso pode ser feito implementando o gráfico de contorno em contour gnuplotvez de surf. Infelizmente, isso não funciona como esperado.

insira a descrição da imagem aqui

MWE (nome do arquivo.tex):

\documentclass[]{article}
\usepackage{pgfplots}
\usepgfplotslibrary{colormaps} 
\begin{document}
 \pgfplotsset{compat=1.8}
\begin{tikzpicture}
\begin{axis}[zmin=0,zmax=1000,colormap/autumn,]
   \addplot3[surf,samples=80, restrict z to domain*=0:1000,samples y= 80,domain=-1:1,y domain=-1:1, opacity=0.5]({x},{y},{1/(x*y)^2}); %{1/(x*y)^2};

% the contour plot:
 \addplot3[
contour gnuplot={levels={1000},labels=false,contour dir=z,},samples=80,domain=-1:1,y domain=-1:1,z filter/.code={\def\pgfmathresult{1000}},]
({x},{y},{1/(x*y)^2});


%filling the contour:
  \addplot3[
  /utils/exec={\pgfplotscolormapdefinemappedcolor{1000}},
  draw=none,
  fill=mapped color] 
  file {filename_contourtmp0.table};
\end{axis}
\end{tikzpicture}
\end{document}

Uma quarta abordagemestá com o gnuplot 5.4 e o comando set pm3d clip z(isso não é suportado por versões anteriores do gnuplot)

insira a descrição da imagem aqui

MWE (gnuplot 5.4):

set border 4095;
set bmargin 6;
set style fill transparent solid 0.50 border;
unset colorbox;
set view 56, 15, .75, 1.75;
set samples 40, 40;
set isosamples 40, 40;
set xyplane 0;
set grid x y z vertical;
set pm3d depthorder border linewidth 0.100;
set pm3d clip z;
set pm3d lighting primary 0.8 specular 0.3 spec2 0.3;
set xrange [-1:1];
set yrange [-1:1];
set zrange [0:1000];
set xtics 0.5 offset 0,-0.5;
set ytics 0.5 offset 0,-0.5;
set ztics 100;
f(x,y) = 1/(x*y)**2;
splot f(x,y) with pm3d fillcolor "red";

Infelizmente, o TikZ não pode ler arquivos de tabela 3D GNUPLOT (gerados com splot), consulteManual de pacotes TikZ PGF 3.1.5, página 342, aquilo é,

\documentclass[]{article}
\usepackage{pgfplots}
\begin{document}
\pgfplotsset{compat=1.8}
\begin{tikzpicture}
    \begin{axis}
    \addplot3[raw gnuplot,surf] gnuplot[id=surf] { %
        set border 4095;
        set bmargin 6;
        set style fill transparent solid 0.50 border;
        unset colorbox;
        set view 56, 15, .75, 1.75;
        set samples 40, 40;
        set isosamples 40, 40;
        set xyplane 0;
        set grid x y z vertical;
        set pm3d depthorder border linewidth 0.100;
        set pm3d clip z;
        set pm3d lighting primary 0.8 specular 0.3 spec2 0.3;
        set xrange [-1:1];
        set yrange [-1:1];
        set zrange [0:1000];
        set xtics 0.5 offset 0,-0.5;
        set ytics 0.5 offset 0,-0.5;
        set ztics 100;
        f(x,y) = 1/(x*y)**2;
        splot f(x,y) with pm3d fillcolor "red";
    };
\end{axis}
\end{tikzpicture}
\end{document}

dá:Tabular output of this 3D plot style not implemented

Uma solução alternativa é usar o gnuplottexpacote com o terminal de saída TikZ.

MWE (ainda não testado, pois trabalho com TeX Live)

\documentclass{article}
\usepackage{graphicx}
\usepackage{latexsym}
\usepackage{ifthen}
\usepackage{moreverb}
\usepackage{tikz}
\usepackage{gnuplot-lua-tikz}
\usepackage[miktex]{gnuplottex}
\begin{document}
    \begin{figure}%
            \centering%
            \begin{gnuplot}[terminal=tikz]
              set out "tex-gnuplottex-fig1.tex"
              set term lua tikz latex createstyle
              set border 4095;
              set bmargin 6;
              set style fill transparent solid 0.50 border;
              unset colorbox;
              set view 56, 15, .75, 1.75;
              set samples 40, 40;
              set isosamples 40, 40;
              set xyplane 0;
              set grid x y z vertical;
              set pm3d depthorder border linewidth 0.100;
              set pm3d clip z;
              set pm3d lighting primary 0.8 specular 0.3 spec2 0.3;
              set xrange [-1:1];
              set yrange [-1:1];
              set zrange [0:1000];
              set xtics 0.5 offset 0,-0.5;
              set ytics 0.5 offset 0,-0.5;
              set ztics 100;
              f(x,y) = 1/(x*y)**2;
              splot f(x,y) with pm3d fillcolor "red";
            \end{gnuplot}
        \caption{This is using the \texttt{tikz}-terminal}%
        \label{pic:tikz}%
    \end{figure}%
\end{document}

Uma quinta abordagemcom PSTricks e\psplotThreeD

insira a descrição da imagem aqui

MWE:

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-3dplot}
\begin{document}

\centering
\begin{pspicture}(-10,-4)(15,20)
    \psset{Beta=15}
    \psplotThreeD[plotstyle=line,linecolor=blue,drawStyle=yLines,
    yPlotpoints=100,xPlotpoints=100,linewidth=1pt](-5,5)(-5,5){%
    x y mul 2 neg exp
    dup 5 gt { pop 5 } if % truncation
    }
    \psplotThreeD[plotstyle=line,linecolor=cyan,drawStyle=xLines,
    yPlotpoints=100,xPlotpoints=100,linewidth=1pt](-5,5)(-5,5){%
    x y mul 2 neg exp
    dup 5 gt { pop 5 } if % truncation
    }
    \pstThreeDCoor[xMin=-1,xMax=5,yMin=-1,yMax=5,zMin=-1,zMax=6]
\end{pspicture}

\end{document}

Responder2

Aqui está a Assíntotacódigopara produzir um 3D interativotramada função Gama.

Responder3

SeguindoA resposta de John Bowman, mergulhei na Assíntota. Ao aprender a usá-lo, fiquei bastante impressionado com suas possibilidades. Minha resposta segueesta postagem, que apresenta um hack Asymptote chamado crop3Dque resolve meu problema. Apesar de ser bastante 'cara' (computacionalmente), gosto do facto desta técnica não necessitar de muita instalação adicional, e de poder ser aplicada de uma forma quase cega (portanto, também poderia ser usada para obter um belo truncamento da função Gamma, por exemplo). Aqui está meu código

\documentclass{article}
\usepackage{asymptote}

\begin{document}
    \begin{figure}[h!]
        \begin{asy}
            import crop3D;
            import graph3;
            unitsize(1cm);
            size3(5cm,5cm,3cm,IgnoreAspect);
            
            real f(pair z) {
                if ((z.x*z.y)^2 > 0.001)
                    return 1/(z.x*z.y)^2;
                else
                    return 1000;
            }
            
            currentprojection = orthographic(10,5,5000);
            currentlight = (1,-1,2);
            
            surface s = surface(f,(-1,-1),(1,1),nx=100,Spline);
            s = crop(s,(-1,-1,0),(1,1,500));
            
            draw(s,lightyellow,render(merge=true));
            
            xaxis3("$x$",Bounds,OutTicks(Step=1));
            yaxis3("$y$",Bounds,OutTicks(Step=1));
            zaxis3("$z$",Bounds,OutTicks(Step=500));
        \end{asy}
    \end{figure}
\end{document}

e a saída correspondente:

saída

Muito obrigado a todos vocês pelo seu esforço e apoio.

Responder4

Aqui está uma implementação do sagetexmétodo que comentei acima para a complexa função Gamma

\documentclass[11pt,border={10pt 10pt 10pt 10pt}]{standalone}
\usepackage{pgfplots}
\usepackage{sagetex}
\pgfplotsset{compat=1.16}
\begin{document}
\begin{sagesilent}
var('x','y')
step = .10
x1 = -4.
x2 = 4.
y1 = -1.5
y2 = 1.5
MAX = 6
output = ""
output += r"\begin{tikzpicture}[scale=1.0]"
output += r"\begin{axis}[view={-15}{45},xmin=%s, xmax=%s, ymin=%s, ymax=%s]"%(x1,x2,y1,y2-step)
output += r"\addplot3[surf,mesh/rows=%d] coordinates {"%(((y2-step-y1)/step+1).round())
# rows is the number of y values
for y in srange(y1,y2,step):
    for x in srange(x1,x2,step):
        if (abs(CDF(x+I*y).gamma()))< MAX:
            output += r"(%f, %f, %f) "%(x,y,abs(CDF(x+I*y).gamma()))
        else:
            output += r"(%f, %f, %f) "%(x,y,MAX)
output += r"};"
output += r"\end{axis}"
output += r"\end{tikzpicture}"
\end{sagesilent}
\sagestr{output}
\end{document}

A saída no Cocalc é mostrada abaixo: insira a descrição da imagem aqui

Diminuir o tamanho do passo para obter um diagrama mais preciso enfrenta problemas. O padrão bufsize=200000é texmf.cnfmuito pequeno. Você teria que modificar isso. No momento não sei como fazer a alteração bufsizeno Cocalc.

O site Cocalc é gratuito, mas o desempenho está sofrendo um pouco tarde para as contas gratuitas, como mostra a mensagem na imagem. Se você copiar/colar o código e executá-lo, obterá ?? no lugar da foto. Mude step = .10para step = .1e ele será compilado corretamente. Por algum motivo, a primeira compilação não funciona corretamente.

informação relacionada