# pgfplots: plot line between two coordinates from file

I basically have a tab separate file with about 100 rows. In each row, there are three values: A, B, and C.

I want to loop through each row in the data file, and plot a line between the coordinates: (A,B) and (A,C). The examples in the pgfplots documentation are unclear on how to do this.

So for example, lets say I have the following data in a separate file:

## A, B, C

1, 2, 3
2, 2.5, 4

I want to take that file and loop through its rows, plotting separate lines in the process. In the first row, I want to plot a line from (1,2) to (1,3). In the second, a line from (2, 2.5) to (2, 4), and so on.

-
The question is unclear. Enhance it by adding a self-contained and minimal example. –  Thorsten Donig Feb 9 at 8:55

## 2 Answers

You can use the error bars functionality for this:

\documentclass[border=5mm]{standalone}
\usepackage{pgfplots}
\usepackage{filecontents}

\begin{filecontents}{data.csv}
A,B,C
1,2,3
2,2.5,4
\end{filecontents}

\begin{document}

\begin{tikzpicture}
\begin{axis}[axis equal image, enlargelimits=0.5]
\addplot [
no markers, draw=none,
error bars/y dir=plus,
error bars/y explicit,
error bars/error mark=none,
error bars/error bar style=very thick
] table [
col sep=comma,
y error expr=\thisrow{C}-\thisrow{B}] {data.csv};
\end{axis}
\end{tikzpicture}
\end{document}

-

I may get downvoted for this, but what I would do is write a program in your favourite scripting language that generates the TikZ code that you want. Here's one in Python:

from contextlib import contextmanager
from textwrap import dedent
import re
import sys

def formatter(string_to_be_printed, **kwargs):
"""
Perform recursive string formatting on a string.
Any keywords enclosed in curly quotation marks are expanded using the
keyword arguments passed into the function with a few details:

The formatter is applied recursively to the expanded string.

If a keyword is a comma-separated list like so “a, b, c”, then each of
the keywords "a", "b", and "c" are expanded and the results of joined with
intervening commas.  If any expansion results in the None object, the
formatter acts as if that term were not there.

Any keyword can contain a ':' in which case the Python string formatting
applies, e.g., “a:.6f” would look for 'a' in the keyword arguments and
expanded the floating point number to six decimal places.

Finally, the returned string is unindented and stripped of whitespace
at either end.
"""
def repl(m):
keyword = m.group(1)
retval = []
for x in keyword.split(','):
x = x.strip()
if x == '':
assert not retval
retval.append('')
continue
if kwargs[x.split(':')[0]] is not None:
y = ('{' + x + '}').format(**kwargs)
retval.append(str(y))
retval = ", ".join(retval)
return retval

retval = re.sub(r"“(.+?)”", repl, dedent(string_to_be_printed)).strip()
if '“' in retval:
return formatter(retval, **kwargs)
return retval

def pf(string_to_be_printed, file=sys.stdout, end='\n', **kwargs):
"""
Format the string using formatter and print it to file with the given
ending character.  File defaults to stdout and end to '\n'.
"""
print(formatter(string_to_be_printed, **kwargs), end=end, file=file)

@contextmanager
def tex_pic(f, filename, pic_type, options={}):
"""
A context manager that creates a tikzpicture environment in the given
file.  filename is the name of the generated pdf for the tikz code.
"""
pf(r"""
\tikzsetnextfilename{“filename”}
\begin{tikzpicture}[“pic_type”]
""",
pic_type=pic_type,
filename=filename,
file=f,
**options)
yield
pf(r"""
\end{tikzpicture}
""",
end='\n\n',
file=f)

with open('a.tex', 'wt') as f:
pf(r"""
\documentclass{minimal}
\usepackage{pgfcore}
\usepackage{pgfkeys}
\usepackage{pgfplots}
\usetikzlibrary{
external,
}
\tikzexternalize[prefix=figures/]
\begin{document}
""",
file=f)

with tex_pic(f, 'diagram', ''):
with open('coords.txt') as g:
for line in g:
x, y, z = [float(x) for x in line.split()]
pf(r"\draw (“x”, “y”) -- (“x”, “z”);", x=x, y=y, z=z,
file=f)
pf(r"""
\end{document}
""",
file=f)


The .tex file that it generated looks like:

\documentclass{minimal}
\usepackage{pgfcore}
\usepackage{pgfkeys}
\usepackage{pgfplots}
\usetikzlibrary{
external,
}
\tikzexternalize[prefix=figures/]
\begin{document}
\tikzsetnextfilename{diagram}
\begin{tikzpicture}[]
\draw (1.0, 2.0) -- (1.0, 3.0);
\draw (2.0, 2.5) -- (2.0, 4.0);
\end{tikzpicture}

\end{document}


The real magic is the pf function that does string formatting. Since tex uses {}()[] extensively, I ended up using the curly quotes “”, which are option-[ and option-shift-[ on the mac keyboard. The formatting is done recursively (unlike regular Python formatting), which can be useful sometimes.

Note that the code to actually read the file and generate the image is only the with tex_pic block (6 lines). Additional images are typically easy to add.

-
Why should this get downvoted? It is a nice solution. Maybe the python code could benefit from some comments to explain the approach taken. –  Alexander Feb 9 at 9:51
@Alexander: Thank you. I added some comments. Please let me know if you'd like me to clarify any other lines of code. –  Neil G Feb 9 at 10:09