Quiero usar TikZ/pgf para producir el siguiente gráfico 3D, que consta de:
- una gráfica de la función f(x, y) = xy/(x^2 + y^2) cuando (x, y) != (0,0) y f(0,0)=0;
- la intersección del plano y = x con la superficie, es decir, la recta con ecuación y = x, z = 1/2 pero con el punto (0, 0, 1/2) omitido;
- el origen; y
- al menos la porción positiva de los ejes x, y y z.
Ese gráfico fue creado con Mathematica y usa un punto de vista (2.85216, 1.62152, 0.828166) en coordenadas espaciales (r,θ, φ) (donde los ángulos están en radianes, no en grados).
Mi pgfplots
intento utiliza el siguiente código y produce el gráfico que se muestra a continuación.
Pregunta: ¿Cómo puedo modificar el pgfplots
código para que se parezca mucho al gráfico de Mathematica para que:
utiliza esencialmente el mismo punto de vista (y por tanto la misma orientación de los ejes);
omite reglas de contorno en la superficie;
tiene la ruptura en el eje z de la recta y = x, z = 1/2;
utiliza un punto más convincente en el origen; y
Evita las "dentaduras" en la superficie cerca del eje z.
Con respecto a 5., intenté aumentar el samples
valor, ¡pero al hacerlo se produce un TeX capacity exceeded
error!
Mi pgfplot
salida:
Mi código:
\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
% Define a grayscale colormap
\pgfplotsset{
colormap={grayscale}{[1pt] rgb255(0pt)=(0,0,0); rgb255(1000pt)=(255,255,255)}
}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
view={75.833}{35.3489},
axis lines=center,
xlabel={$x$}, ylabel={$y$}, zlabel={$z$},
ticks=none,
domain=-1:1, y domain=-1:1,
samples=50, % need to avoid "jaggies"
z buffer=sort,
clip=false,
xmin=-1, xmax=1, ymin=-1, ymax=1, zmin=-1, zmax=1.5,
colormap name=grayscale,
xlabel style={anchor=north west}, ylabel style={anchor=north west},
zlabel style={anchor=south},
]
% Surface plot
\addplot3[surf, shader=faceted interp, opacity=0.7]
{x != 0 || y != 0 ? (x*y)/(x^2 + y^2) : 0};
% Point at the origin
\addplot3[mark=*, mark size=1,mark options={color=black}] coordinates {(0, 0, 0)};
% Curve of intersection of plane and surface
\addplot3[samples=20, samples y=0, thick, color=black]
({x}, {x}, {1/2});
\end{axis}
\end{tikzpicture}
\end{document}
Respuesta1
Actualizar
Modifiqué el código según los numerosos comentarios de @murray. Hay dos formas de representar la superficie: utilizando coordenadas polares para el dominio de definición o utilizando coordenadas normales. El primero trata idealmente la singularidad en el origen ya que la respeta. Este último se atiene a la definición inicial de la función pero tiene problemas con su comportamiento en torno a (0, 0).
Para esto último, las principales modificaciones respecto a la respuesta inicial son las siguientes:
- la superficie se divide en dos (y<0yy>0respectivamente)
- Se añaden bordes para una mejor comprensión de la superficie.
- Los ejes se dibujan por separado (como segmentos TikZ).
El orden de los distintos elementos gráficos cuenta.
Observación
A continuación se muestra una imagen obtenida utilizando matplotlib
cálculos basados en una cuadrícula de 10000x10000. La superficie nunca puede alisarse alrededor del origen desde este último punto de vista.
Nuevo código para el dibujo usando coordenadas polares para el dominio.
\documentclass[11pt, margin=10pt]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{math}
\pgfplotsset{compat=1.17}
\begin{document}
\pgfplotsset{
colormap={cmpgray}{rgb255=(221,221,221) rgb255=(54,54,54)}
}
\xdefinecolor{axisRGB}{RGB}{128, 30, 0} % {128, 128, 145}
\begin{tikzpicture}
\begin{axis}[
data cs=polar,
axis lines=none, % grid=major,
view={110}{22},
z buffer=sort,
clip=false]
% negative Ox axis
\draw[axisRGB, thin] (0, 0, 0) -- (-1.8, 0, 0);
\draw[axisRGB, thin, ->] (0, 0, .02) -- (0, 0, .8)
node[right, text=black, scale=.7] {$z$};
\addplot3[
surf,
shader=interp,
domain=0:360, domain y=.02:1.4,
samples=50, samples y=20,
opacity=0.95]
{.5*sin(2*x)};
% negative Oy axis
\draw[axisRGB, thin] (0, 0, 0) -- (0, -1.8, 0);
% negative Oz axis
\draw[axisRGB, thin] (0, 0, -.025) -- (0, 0, -.8);
% point at the origin
\fill[opacity=.7] (0, 0, 0) circle (1.2pt);
\draw[axisRGB, thin, ->] (0, .02, 0, 0) -- (0, 1.8, 0)
node[below, text=black, scale=.7] {$y$};
\draw[axisRGB, thin, ->] (.02, 0, 0) -- (1.8, 0, 0)
node[below, text=black, scale=.7] {$x$};
% Intersection curve of surface and plane z=1/2
\draw[thin] (-1, -1, 1/2) -- (1, 1, 1/2);
\end{axis}
\end{tikzpicture}
\end{document}
Nuevo código para el segundo sorteo.
\documentclass[11pt, margin=10pt]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.17}
\begin{document}
\pgfplotsset{
colormap={cmpgray}{rgb255=(221,221,221) rgb255=(54,54,54)}
}
\xdefinecolor{axisRGB}{RGB}{128, 128, 145}
\begin{tikzpicture}
\begin{axis}[
view={115}{19},
axis lines=none, % center,
xlabel={$x$}, ylabel={$y$}, zlabel={$z$},
ticks=none,
z buffer=sort,
clip=false,
xmin=-1.3, xmax=1.3,
ymin=-1.3, ymax=1.3,
zmin=-1, zmax=1.3,
xlabel style={anchor=north west, scale=.8},
ylabel style={anchor=north west, scale=.8},
zlabel style={anchor=south, scale=.8},
]
% Surface y<0
\addplot3[
surf,
domain=-1:1,
y domain=-1:-.005,
samples=55,
colormap name=cmpgray,
shader=interp, % flat, faceted interp,
opacity=0.75]
{x*y/(x^2 + y^2)};
% Surface y<0 's border
\addplot3[%
draw=black, ultra thin,
domain=-1:1,
samples y=0]
(x, -1, {-x/(x*x +1)});
\addplot3[%
draw=black, ultra thin,
domain=-1:1,
samples y=0]
(-1, x, {-x/(x*x +1)});
% negative Ox and Oy axes
\draw[axisRGB, thin] (0, 0, 0) -- (0, -1.4, 0);
\draw[axisRGB, thin] (0, 0, 0) -- (-1.4, 0, 0);
% Point at the origin
\fill (0, 0, 0) circle (1.2pt);
% positive Oz axis
\draw[axisRGB, thin, ->] (0, 0, .02) -- (0, 0, 1.3)
node[right, text=black, scale=.7] {$z$};
% Surface y>0
\addplot3[
surf,
domain=-1:1,
y domain=.005:1,
samples=55,
colormap name=cmpgray,
shader=interp, % flat, faceted interp,
opacity=0.75]
{x*y/(x*x + y*y)};
% positive Oy axis
\draw[axisRGB, thin, ->] (0, .02, 0, 0) -- (0, 1.4, 0)
node[below, text=black, scale=.7] {$y$};
% negative Oz axis
\draw[axisRGB, thin] (0, 0, -.025) -- (0, 0, -1.3);
% Intersection curve of surface and plane z=1/2
\draw[thin] (-1, -1, 1/2) -- (1, 1, 1/2);
% Surface y>0 's border
\addplot3[%
draw=black, very thin,
domain=-1:1,
samples y=0]
(x, 1, {x/(x*x +1)});
\addplot3[%
draw=black, very thin,
domain=-1:1,
samples y=0]
(1, x, {x/(x*x +1)});
% positive Ox axis
\draw[axisRGB, thin, ->] (.02, 0, 0) -- (1.5, 0, 0)
node[below, text=black, scale=.7] {$x$};
\end{axis}
\end{tikzpicture}
\end{document}
Antigua respuesta
Algo como esto; Solo cambié el punto de vista, la longitud de los ejes de coordenadas y el sombreador.
El código
\documentclass[11pt, margin=10pt]{standalone}
\usepackage{pgfplots}
\usepgfplotslibrary{colorbrewer}
\pgfplotsset{compat=1.17}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
view={115}{15},
axis lines=center,
xlabel={$x$}, ylabel={$y$}, zlabel={$z$},
ticks=none,
domain=-1:1, y domain=-1:1,
samples=50, % need to avoid "jaggies"
z buffer=sort,
clip=false,
xmin=-1.3, xmax=1.3,
ymin=-1.3, ymax=1.3,
zmin=-1, zmax=1.3,
xlabel style={anchor=north west, scale=.8},
ylabel style={anchor=north west, scale=.8},
zlabel style={anchor=south, scale=.8},
]
% Surface plot
\addplot3[
surf,
colormap/Blues, % cool,
% shader=faceted interp,
opacity=0.3]
{x != 0 || y != 0 ? (x*y)/(x^2 + y^2) : 0};
% Point at the origin
\addplot3[mark=*, mark size=1,mark options={color=black}]
coordinates {(0, 0, 0)};
% Curve of intersection of plane and surface
\addplot3[samples=20, samples y=0, thick, color=black]
({x}, {x}, {1/2});
\end{axis}
\end{tikzpicture}
\end{document}