18

I have plotted a 3D line using this following data:

p p1t p2t
-65.79  -210.81 137.73
-124.76 -182.7  189.67
-170.78 -141.97 233.17
-206.39 -96.42  257.48
-226.99 -40.212 268.45
-231.57 20.337  255.59
-226.75 78.518  223.62
-210.81 137.73  175.85
-182.7  189.67  113.02
-141.97 233.17  46.467
-96.42  257.48  -21.029
-40.212 268.45  -88.289
20.337  255.59  -145.29
78.518  223.62  -187.76
137.73  175.85  -219.49
189.67  113.02  -236.46
233.17  46.467  -239.94
257.48  -21.029 -232.83
268.45  -88.289 -215.23
255.59  -145.29 -188.55
223.62  -187.76 -150.57
175.85  -219.49 -105.58
113.02  -236.46 -53.317
46.467  -239.94 8.5742
-21.029 -232.83 69.439
-88.289 -215.23 133.3
-145.29 -188.55 189.99
-187.76 -150.57 237.67
-219.49 -105.58 270.35
-236.46 -53.317 280.53
-239.94 8.5742  273.67
-232.83 69.439  242.25
-215.23 133.3   192.67
-188.55 189.99  124.54
-150.57 237.67  54.914
-105.58 270.35  -17.003
-53.317 280.53  -84.499
8.5742  273.67  -144.65
69.439  242.25  -186.34
133.3   192.67  -215.7
189.99  124.54  -232.52
237.67  54.914  -232.44
270.35  -17.003 -224.46
280.53  -84.499 -207.1
273.67  -144.65 -179.78
242.25  -186.34 -143
192.67  -215.7  -100.92
124.54  -232.52 -51.028
54.914  -232.44 5.9691
-17.003 -224.46 64.545
-84.499 -207.1  124.38
-144.65 -179.78 178.78
-186.34 -143    225.43
-215.7  -100.92 259.53
-232.52 -51.028 273.98
-232.44 5.9691  271.22
-224.46 64.545  241.22
-207.1  124.38  191.33
-179.78 178.78  128.33
-143    225.43  57.519
-100.92 259.53  -12.74
-51.028 273.98  -82.841
5.9691  271.22  -138.81
64.545  241.22  -184.6
124.38  191.33  -216.97
178.78  128.33  -231.49
225.43  57.519  -232.67

The plot will look like this. enter image description here Now,

  1. I would like to plot a cross-section of this 3D plot (i.e a 2D plot - a plane that for instance passes through p1=0)

  2. I want a dotted rectangle in the 3D plot to represent which cross-section I'm plotting.

  3. How do I make the x, y, and z labels parallel to their respective axes?

Here is a MWE:

\documentclass{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{graphicx}
\usepackage{tikz}
\usepackage{pgf}
\usepackage{mathtools}
\pgfplotsset{compat=newest}
\begin{document}
\begin{tikzpicture}
\begin{axis}[xlabel=p1, ylabel=p1t, zlabel=p2t, tick style={draw=none}]

\addplot3[smooth, mark=none, color=black] table [x=p, y=p1t, z=p2t]{dummy.txt};

\end{axis}
\end{tikzpicture}
\end{document}

Progress Update: Although there is a method to do this for surface plots, the same doesn't work for line plots.

6
  • 2
    For the second question, you can add a \draw command inside the axis environment, something like \draw[dotted] (0,-200,-200) -- (0,200,-200) -- (0,200,200) -- (0,-200,200) -- cycle; Jun 14, 2016 at 23:57
  • @cfr: It is a line which exist in 3 dimensions (has x, y, z values) as opposed to most of the plots, which are restricted to a 2D plane (generally, a 2D plot is also a 3D plot with a constant 3rd dimension coordinate or the one lying in a single plane ) Jun 16, 2016 at 7:41
  • 2
    To see this clearly: a cross section on a plane will be just a set of points, correct? the intersections of the line when it "punch through" it.
    – Rmano
    Jun 16, 2016 at 17:45
  • @Rmano: Exactly Jun 16, 2016 at 18:02
  • Do you want only pgf-plots and tikz, or can we use Lua or Metapost?
    – JPG
    Jun 17, 2016 at 16:56

2 Answers 2

7
+50

I would use a split approach, really -- I am posting this here because I am sure that someone with Lua skills will integrate it in a standalone LaTeX source. It happens I know python... and I will learn from the other answer :-)

So I created this quick and dirty python script to find the intercepts, by linear interpolation:

#! /usr/bin/env python3
#
# use as ./process.py filename x-coordinate-to-cut
# 
import sys
xcut = float(sys.argv[2])
with open(sys.argv[1]) as f:
    i=-1
    for line in f:
        i += 1
        if i==0:
            print ("p1t p2t")
            continue # skip first line
        data = [float(f) for f in line.split()]
        if i==1:
            old_data = data 
            continue
        if (old_data[0] <= xcut and data[0] > xcut) or (old_data[0] >= xcut and data[0] < xcut):
            # crossing the plane
            y = old_data[1] + (data[1]-old_data[1])/(data[0]-old_data[0])*(xcut - old_data[0])
            z = old_data[2] + (data[2]-old_data[2])/(data[0]-old_data[0])*(xcut - old_data[0])
            print("%g %g" % (y,z))
        old_data = data

And use it to create data points for the cut at p=0:

./process.py dummy.txt 0.0 > cross0.txt
./process.py dummy.txt 100.0 > cross100.txt
./process.py dummy.txt 200.0 > cross200.txt

and now with the source:

\documentclass[border=10pt]{standalone}
\usepackage{pgfplots}\pgfplotsset{compat=1.13}
\usepackage{pgfplotstable}
\usepackage{graphicx}
\usepackage{tikz}
\usepackage{pgf}
\usepackage{mathtools}
\pgfplotsset{compat=newest}
\begin{document}
\begin{tikzpicture}
\begin{axis}[xlabel=p1, ylabel=p1t, zlabel=p2t, tick style={draw=none},
    xmin=-300, xmax=300, ymin=-300, ymax=300, zmin=-300, zmax=300]
    \addplot3[smooth, mark=none, color=black] table [x=p, y=p1t, z=p2t]{dummy.txt};
    \draw [dashed, red] (0,-300,-300) -- (0,300,-300) -- (0,300,300) -- (0,-300,300) -- cycle; 
    \draw [dashed, blue] (100,-300,-300) -- (100,300,-300) -- (100,300,300) -- (100,-300,300) -- cycle; 
    \draw [dashed, green] (200,-300,-300) -- (200,300,-300) -- (200,300,300) -- (200,-300,300) -- cycle; 
\end{axis}
\end{tikzpicture}
\begin{tikzpicture}
    \begin{axis}[xlabel=p1t, ylabel=p2t, tick style={draw=none},
        xmin=-300, xmax=300, ymin=-300, ymax=300]
        \addplot [red, only marks] table [x=p1t, y=p2t]{cross0.txt};
        \addplot [blue, only marks] table [x=p1t, y=p2t]{cross100.txt};
        \addplot [green, only marks] table [x=p1t, y=p2t]{cross200.txt};
        \legend{$p=0$, $p=100$, $p=200$}
    \end{axis}
\end{tikzpicture}

\end{document}

I have the result:

Ok, now it's the correct one

which obviously needs a bit of love to massage a bit, but I think it's more or less what the OP wanted.

2

Here is the same answer as Rmano's one, but in Lualatex with everything in the same file:

\documentclass[border=10pt]{standalone}
\usepackage{pgfplots}
\usepackage{tikz}
\usepackage{pgf}
\usepackage{luacode}
\pgfplotsset{compat=newest}
\begin{document}
\begin{tikzpicture}
\begin{axis}[xlabel=p1, ylabel=p1t, zlabel=p2t, tick style={draw=none},
    xmin=-300, xmax=300, ymin=-300, ymax=300, zmin=-300, zmax=300]
    \addplot3[smooth, mark=none, color=black] table [x=p, y=p1t, z=p2t]{dummy.txt};
    \draw [dashed, red] (0,-300,-300) -- (0,300,-300) -- (0,300,300) -- (0,-300,300) -- cycle; 
    \draw [dashed, blue] (100,-300,-300) -- (100,300,-300) -- (100,300,300) -- (100,-300,300) -- cycle; 
    \draw [dashed, green] (200,-300,-300) -- (200,300,-300) -- (200,300,300) -- (200,-300,300) -- cycle; 
\end{axis}
\end{tikzpicture}

\begin{luacode*}
function split(str)
    return {str:match("([^ ]*) +([^ ]*) +([^ ]*)")}
end
function plot_crosssection(filename,p1val)
    local i=0
    local data,olddata
    for line in io.lines(filename) do
        print (i,data)
        i=i+1
        if i==2 then data=split(line)
        elseif i>2 then
            olddata={data[1],data[2],data[3]}
            data=split(line)
            if (olddata[1]-p1val)*(data[1]-p1val)<=0 then
                local y = olddata[2] + (data[2]-olddata[2])/(data[1]-olddata[1])*(p1val - olddata[1])
                local z = olddata[3] + (data[3]-olddata[3])/(data[1]-olddata[1])*(p1val - olddata[1])
                tex.sprint("("..y..","..z..")")
            end
        end
    end
end
\end{luacode*}
\begin{tikzpicture}
    \begin{axis}[xlabel=p1t, ylabel=p2t, tick style={draw=none},
        xmin=-300, xmax=300, ymin=-300, ymax=300]
        \addplot [red, only marks] coordinates {\directlua{plot_crosssection("dummy.txt",0);}};
        \addplot [blue, only marks] coordinates {\directlua{plot_crosssection("dummy.txt",100);}};
        \addplot [green, only marks] coordinates {\directlua{plot_crosssection("dummy.txt",200);}};
        \legend{$p=0$, $p=100$, $p=200$}
    \end{axis}
\end{tikzpicture}

\end{document}

Compile it with lualatex. I have used a very simple way to read this .txt file, but you can also use the csv.lua library for this.

2
  • Can you please explain the methodology you used to plot the cross section? Jun 24, 2016 at 14:21
  • 1
    The same as Rmano: I read the file line by line. olddata contains one line of data and data the following. If olddata[1]-p1val and data[1]-p1val are of opposite sign (supposing a cross-section p1=p1val) then we interpolate to find the real coordinates of the crossing point. Then it is printed to TeX with the tex.sprint(...) command. Pgfplots plots then the coordinates of the points furnished by Lua. If you want more complicated cross-sections (not p1=...) then it is possible but more complicated.
    – JPG
    Jun 24, 2016 at 15:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .