pgfplots in LaTeX: Plot Data and Functions

Quick answer

  • Preamble: \usepackage{pgfplots} and \pgfplotsset{compat=1.18}. pgfplots loads TikZ itself.
  • A plot is an axis inside a tikzpicture; each \addplot draws one series.
  • Data: \addplot coordinates {(0,0) (1,1)}; or \addplot table[col sep=comma] {data.csv};. Function: \addplot[domain=-2:2] {x^2};
  • Trig functions use degrees: write sin(deg(x)) or set trig format plots=rad.
\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}

\begin{document}
\begin{tikzpicture}
  \begin{axis}[xlabel={$x$}, ylabel={$y$}]
    \addplot coordinates {(0,0) (1,1) (2,4) (3,9)};
  \end{axis}
\end{tikzpicture}
\end{document}

pgfplots is the LaTeX package for plots: line plots, scatter plots, bar charts, function graphs and 3D surfaces, drawn in the same fonts as your document and stored as code next to the text. This guide starts from a complete document, then covers plotting coordinates, reading a CSV or table file, plotting a formula, bar charts, legends and axis labels, and the errors (the compat warning, “Dimension too large”, “Environment axis undefined”) everyone runs into. Every snippet compiles with a current TeX Live.

What is pgfplots?

pgfplots is built on top of TikZ. TikZ draws shapes from coordinates you give it; pgfplots adds axes, ticks, scaling, legends and data input, so you describe what to plot and it works out where everything goes. Because the plot is typeset by LaTeX, axis labels can contain math such as $\sigma^2$, the font matches the body text, and the output is vector graphics that stays sharp at any zoom. Journals and theses use it for exactly that reason.

Your First Plot: A Complete Document

Every pgfplots figure has the same three layers: a tikzpicture, an axis with options in square brackets, and one or more \addplot commands, each ending in a semicolon.

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}  % always set this; see Common Errors

\begin{document}

\begin{figure}[htbp]
  \centering
  \begin{tikzpicture}
    \begin{axis}[
        title={Simple Function Plot},
        xlabel={$x$},
        ylabel={$y$},
    ]
      \addplot[blue, thick, domain=-2:2, samples=100] {x^2};
    \end{axis}
  \end{tikzpicture}
  \caption{The parabola $y = x^2$.}
  \label{fig:parabola}
\end{figure}

\end{document}

Wrapping the tikzpicture in a figure gives it a caption and a number you can \ref, exactly like an image.

Line Plot from Coordinates

For a handful of points, type them straight into the document with \addplot coordinates. Each \addplot is one series; \addlegendentry right after it names that series in the legend.

\begin{tikzpicture}
  \begin{axis}[
      xlabel={Epoch},
      ylabel={Loss},
      legend pos=north east,
      grid=major,
  ]
    \addplot[blue, mark=*] coordinates {
      (1, 0.92) (2, 0.61) (3, 0.45) (4, 0.38) (5, 0.34)
    };
    \addlegendentry{Training}

    \addplot[red, dashed, mark=square*] coordinates {
      (1, 0.95) (2, 0.70) (3, 0.58) (4, 0.55) (5, 0.54)
    };
    \addlegendentry{Validation}
  \end{axis}
\end{tikzpicture}

Write \addplot with options in brackets to set the style completely, as above. Write \addplot+[...] to keep the automatic colour and marker from the cycle list and only add to it, and \addplot with no options to use the cycle list as is. Add only marks to the options for a scatter plot, or no marks for a clean line.

Plot from a CSV or Table File

For real data, keep the numbers in a file and let pgfplots read it. Columns are named by the header row, so you pick them with x= and y=. Use col sep=comma for CSV; without it pgfplots expects columns separated by spaces or tabs.

% data.csv, in the same folder as main.tex:
% time,temp,pressure
% 0,20.1,101.3
% 1,22.4,101.1
% 2,25.0,100.8
% 3,27.3,100.6
% 4,29.9,100.2

\begin{tikzpicture}
  \begin{axis}[xlabel={Time (min)}, ylabel={Temperature ($^\circ$C)}]
    \addplot table[x=time, y=temp, col sep=comma] {data.csv};
  \end{axis}
\end{tikzpicture}

To keep a self-contained example in one file, write the CSV from the preamble with filecontents*, which is built into LaTeX:

\begin{filecontents*}[overwrite]{data.csv}
time,temp,pressure
0,20.1,101.3
1,22.4,101.1
2,25.0,100.8
3,27.3,100.6
4,29.9,100.2
\end{filecontents*}

When several plots use the same file, read it once into a macro with \pgfplotstableread. To plot a computed column, use y expr with \thisrow on the file itself:

\pgfplotstableread[col sep=comma]{data.csv}\mydata

\begin{tikzpicture}
  \begin{axis}[legend pos=outer north east]
    \addplot table[x=time, y=temp] {\mydata};
    \addplot table[x=time, y=pressure] {\mydata};
    \legend{Temperature, Pressure}
  \end{axis}
\end{tikzpicture}

% A computed column (Celsius to Fahrenheit), inside an axis:
\addplot table[x=time, y expr=\thisrow{temp}*9/5+32, col sep=comma] {data.csv};

Short tables can also live inline. Give row sep=\\ so each row ends with \\:

\addplot table[row sep=\\] {
  x  y  \\
  0  1  \\
  1  3  \\
  2  2  \\
  3  5  \\
};

Data in a spreadsheet? The Excel to LaTeX converter turns it into rows you can paste, or export the sheet as CSV and read it as above.

Plot a Function

Put a formula in braces instead of coordinates. domain sets the x range and samples the number of points; raise it for curves with tight bends. pgfplots understands + - * / ^, sqrt, exp, ln, abs, pi and the trig functions.

\begin{tikzpicture}
  \begin{axis}[
      axis lines=middle,
      xlabel={$x$}, ylabel={$y$},
      domain=-2*pi:2*pi, samples=200,
      trig format plots=rad,   % sin(x) in radians
      legend pos=outer north east,
  ]
    \addplot[blue, thick] {sin(x)};
    \addplot[red, thick] {cos(x)};
    \addplot[green!50!black, thick, domain=-2:2] {x^3 - x};
    \legend{$\sin x$, $\cos x$, $x^3 - x$}
  \end{axis}
\end{tikzpicture}

Trig functions take degrees by default, which is the most common surprise in pgfplots. Either set trig format plots=rad as above or convert in the formula: \addplot {sin(deg(x))};. Parametric curves take a pair of formulas in parentheses:

\begin{tikzpicture}
  \begin{axis}[axis equal, trig format plots=rad]
    \addplot[domain=0:2*pi, samples=100, variable=t] ({cos(t)}, {sin(t)});
  \end{axis}
\end{tikzpicture}

Bar Chart

Add ybar to the axis for vertical bars or xbar for horizontal ones. symbolic x coords lets you use category names as x values, xtick=data puts one tick under each bar, and nodes near coords prints the value on top. Two \addplot commands give a grouped bar chart.

\begin{tikzpicture}
  \begin{axis}[
      ybar,
      bar width=18pt,
      ymin=0,
      enlarge x limits=0.2,
      symbolic x coords={Q1, Q2, Q3, Q4},
      xtick=data,
      nodes near coords,
      ylabel={Revenue (\$k)},
      legend style={at={(0.5,-0.15)}, anchor=north, legend columns=-1},
  ]
    \addplot coordinates {(Q1, 45) (Q2, 62) (Q3, 78) (Q4, 91)};
    \addplot coordinates {(Q1, 38) (Q2, 55) (Q3, 60) (Q4, 84)};
    \legend{2026, 2025}
  \end{axis}
\end{tikzpicture}

ymin=0 makes the bars start at zero rather than at the smallest value, and enlarge x limits stops the outer bars from touching the frame. For horizontal bars swap the roles of the axes:

\begin{tikzpicture}
  \begin{axis}[
      xbar,
      xmin=0,
      symbolic y coords={Python, C++, Rust},
      ytick=data,
      nodes near coords,
      xlabel={Runtime (s)},
  ]
    \addplot coordinates {(12.4,Python) (1.8,C++) (1.6,Rust)};
  \end{axis}
\end{tikzpicture}

Legends, Axis Labels and Titles

Labels, limits, ticks and the legend are all axis options. Name each series with \addlegendentry after its \addplot, or list every name at once with \legend.

\begin{tikzpicture}
  \begin{axis}[
      title={Damped oscillation},
      xlabel={Time $t$ (s)},
      ylabel={Displacement $x(t)$ (cm)},
      xmin=0, xmax=10,
      ymin=-1.2, ymax=1.2,
      xtick={0,2,...,10},
      grid=both,
      legend pos=north east,
      legend cell align=left,
      width=0.9\textwidth, height=6cm,
  ]
    \addplot[blue, thick, domain=0:10, samples=200] {exp(-0.3*x)*cos(deg(2*x))};
    \addlegendentry{$e^{-0.3t}\cos 2t$}
    \addplot[gray, dashed, domain=0:10] {exp(-0.3*x)};
    \addlegendentry{envelope}
  \end{axis}
\end{tikzpicture}
OptionWhat it does
title, xlabel, ylabelPlot title and axis labels; math allowed
xmin, xmax, ymin, ymaxAxis limits
xtick={0,2,...,10}Tick positions; xticklabels sets their text
legend posnorth east, north west, south east, south west, outer north east
legend style={at={(0.5,-0.15)}, anchor=north}Legend anywhere, here centred below the plot
legend columns=-1Legend in one row
axis lines=middleAxes through the origin instead of a box (left for an open L-shape)
grid=major / bothGrid lines at major (and minor) ticks
width, heightSize of the whole plot, e.g. width=0.9\textwidth
domain=a:b, samples=nx range and resolution for function plots

Scatter Plots

\begin{tikzpicture}
  \begin{axis}[
      title={Data Points},
      xlabel={Time (s)},
      ylabel={Value},
      only marks,
  ]
    \addplot coordinates {
      (0, 0.5) (1, 2.1) (2, 3.8) (3, 6.2) (4, 7.9) (5, 10.1)
    };
  \end{axis}
\end{tikzpicture}

Error Bars

\begin{tikzpicture}
  \begin{axis}[
      title={Measurement with Errors},
      xlabel={Sample},
      ylabel={Value},
  ]
    \addplot+[
        only marks,
        error bars/.cd,
        y dir=both,
        y explicit,
    ] coordinates {
        (1, 2.5) +- (0, 0.3)
        (2, 3.1) +- (0, 0.4)
        (3, 4.2) +- (0, 0.2)
        (4, 3.8) +- (0, 0.5)
    };
  \end{axis}
\end{tikzpicture}

Logarithmic Axes

Replace axis with semilogyaxis, semilogxaxis or loglogaxis. A log axis is also the cure for data spanning many orders of magnitude.

\begin{tikzpicture}
  \begin{semilogyaxis}[xlabel={$n$}, ylabel={$2^n$}, grid=major]
    \addplot[blue, thick, domain=0:60, samples=61] {2^x};
  \end{semilogyaxis}
\end{tikzpicture}

3D Plots

\begin{tikzpicture}
  \begin{axis}[
      title={3D Surface},
      view={60}{30},
      colormap/viridis,
  ]
    \addplot3[
        surf,
        domain=-2:2,
        domain y=-2:2,
        samples=30,
    ] {exp(-x^2-y^2)};
  \end{axis}
\end{tikzpicture}

Customizing Appearance

\begin{tikzpicture}
  \begin{axis}[
      title style={font=\bfseries\large},
      xlabel style={font=\itshape},
      ylabel style={font=\itshape},
      tick label style={font=\small},
      legend style={font=\footnotesize},
      grid=both,
      grid style={line width=.1pt, draw=gray!20},
      major grid style={line width=.2pt, draw=gray!50},
      width=10cm,
      height=7cm,
  ]
    \addplot[blue, thick] {x^2};
  \end{axis}
\end{tikzpicture}

To give every plot in the document the same look, put the shared options in the preamble with \pgfplotsset{every axis/.append style={...}}, and colours from xcolor work in any plot style.

Common Errors and Fixes

MessageCauseFix
Package pgfplots Warning: running in backwards compatibility modeNo compat setting in the preambleAdd \pgfplotsset{compat=1.18} after \usepackage{pgfplots}
LaTeX Error: Environment axis undefinedOnly tikz is loaded, not pgfplotsLoad \usepackage{pgfplots}; it loads TikZ too
Undefined control sequence on \pgfplotsset\pgfplotsset comes before \usepackage{pgfplots}, or the package is missingLoad the package first, then set compat
Dimension too largeA \draw or \node far outside the axis limits, or a huge spike such as 1/x at 0Keep annotations inside the limits, add restrict y to domain, rescale, or use a log axis
I do not know the key '/tikz/legend pos'An axis option given to tikzpicture instead of the axis, or a misspelled key such as legend positionMove it to the options of \begin{axis}[...]
Could not read table file 'data.csv'Wrong path, or the file was not uploaded with the projectPath is relative to the main .tex file; check the name and folder
Sine or cosine curve is almost flatTrig functions take degreessin(deg(x)) or trig format plots=rad

The compat warning in full reads: running in backwards compatibility mode (unsuitable tick labels; missing features). Consider writing \pgfplotsset{compat=1.18} into your preamble. Older answers online suggest compat=newest; that works but lets a pgfplots update change your figures silently, so a fixed version is safer for a paper or thesis.

For an asymptote, cut the spikes off rather than plotting them, and let pgfplots break the line where values are dropped:

\begin{tikzpicture}
  \begin{axis}[
      domain=-3:3, samples=201,
      restrict y to domain=-10:10,
      unbounded coords=jump,
  ]
    \addplot {1/x};
  \end{axis}
\end{tikzpicture}

Frequently Asked Questions

How do I use pgfplots in LaTeX?

Put \usepackage{pgfplots} and \pgfplotsset{compat=1.18} in the preamble. pgfplots loads TikZ for you. Each plot is an axis environment inside a tikzpicture, and each \addplot command inside the axis draws one series, from coordinates, a table file or a formula.

What does \pgfplotsset{compat=1.18} do?

It tells pgfplots which version's behaviour to use. Without it pgfplots runs in backwards compatibility mode, which places axis labels differently and turns off newer features, and it prints the warning “running in backwards compatibility mode”. 1.18 is the current version in TeX Live; use compat=newest only if you accept plots changing when pgfplots is updated.

How do I plot data from a CSV file with pgfplots?

Use \addplot table[x=time, y=temp, col sep=comma] {data.csv}; where time and temp are column names from the header row. Without col sep=comma pgfplots expects whitespace-separated columns. The file path is relative to the main .tex file.

Why does my sine plot look wrong in pgfplots?

pgfplots trig functions take degrees, so sin(x) over a domain of 0 to 6 barely moves. Write sin(deg(x)) or add trig format plots=rad to the axis options so that sin(x) uses radians.

How do I fix “Dimension too large” in pgfplots?

TeX lengths cannot exceed about 16384pt, and the error usually comes from a \draw or \node inside the axis whose coordinates lie far outside the axis limits, or from a formula with a huge spike such as 1/x near zero. Keep annotations within the limits (or use rel axis cs), add restrict y to domain=-10:10 for asymptotes, rescale the data, or switch to a logarithmic axis.

Next Steps

Free pgfplots Tools

Generate plots with AI

Describe your data visualization and let Octree's AI write the pgfplots code, compile it and fix the errors for you.

Try Octree Free →