Intermediate 35 min read

Plots and Graphs in LaTeX with PGFPlots

Master creating publication-quality plots, charts, and data visualizations directly in LaTeX using PGFPlots. This comprehensive guide covers 2D line plots, scatter plots, bar charts, 3D surfaces, contour plots, and advanced customization techniques with 50+ practical examples for scientific and technical documentation.

Introduction to PGFPlots

PGFPlots is a powerful LaTeX package built on TikZ/PGF for creating high-quality, publication-ready plots and charts. It's the standard tool for scientific data visualization in LaTeX documents, offering precise control, professional styling, and seamless integration with mathematical typesetting.

Why Use PGFPlots for Data Visualization?

PGFPlots produces vector graphics that scale perfectly, integrates mathematical notation seamlessly, maintains consistent styling with your document, works with external data files, and is the standard for IEEE publications, academic journals, and scientific papers worldwide.

What You Can Create with PGFPlots

Setup and Installation

PGFPlots requires TikZ and comes with most modern LaTeX distributions. Load it in your preamble:

Basic PGFPlots Setup
\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}  % Use latest version

\begin{document}

\begin{tikzpicture}
  \begin{axis}
    % Your plot code here
  \end{axis}
\end{tikzpicture}

\end{document}
💡 Compatibility Tip: Always set \pgfplotsset{compat=1.18} (or latest version) to enable new features and ensure consistent behavior across LaTeX installations.

Common Package Options

PGFPlots with Options
% Load additional libraries
\usepackage{pgfplots}
\usepgfplotslibrary{
  fillbetween,    % Fill areas between curves
  statistics,     % Box plots, histograms
  polar,          % Polar coordinate plots
  smithchart,     % Smith chart plots
  groupplots,     % Multiple subplot arrangements
  dateplot,       % Date/time axis
  colorbrewer     % ColorBrewer color schemes
}

% Set global defaults
\pgfplotsset{
  compat=1.18,
  width=10cm,
  height=7cm,
  grid=major
}

Basic 2D Plots

The foundation of PGFPlots is the axis environment, which creates a coordinate system for plotting data.

Line Plots

Simple Line Plot
\begin{tikzpicture}
  \begin{axis}[
    title={Simple Line Plot},
    xlabel={$x$},
    ylabel={$y$},
    grid=major
  ]
  
  % Add plot with coordinates
  \addplot coordinates {
    (0,0) (1,1) (2,4) (3,9) (4,16) (5,25)
  };
  
  \end{axis}
\end{tikzpicture}

Multiple Lines

Multiple Line Plots
\begin{tikzpicture}
  \begin{axis}[
    title={Multiple Functions},
    xlabel={$x$},
    ylabel={$f(x)$},
    legend pos=north west,
    grid=major
  ]
  
  % Linear function
  \addplot[blue, thick] coordinates {
    (0,0) (1,1) (2,2) (3,3) (4,4) (5,5)
  };
  \addlegendentry{$y = x$}
  
  % Quadratic function
  \addplot[red, thick] coordinates {
    (0,0) (1,1) (2,4) (3,9) (4,16) (5,25)
  };
  \addlegendentry{$y = x^2$}
  
  % Cubic function
  \addplot[green, thick] coordinates {
    (0,0) (1,1) (2,8) (3,27) (4,64) (5,125)
  };
  \addlegendentry{$y = x^3$}
  
  \end{axis}
\end{tikzpicture}

Scatter Plots

Scatter Plot with Markers
\begin{tikzpicture}
  \begin{axis}[
    title={Scatter Plot Example},
    xlabel={Variable $X$},
    ylabel={Variable $Y$},
    grid=major,
    only marks,  % Show only markers, no lines
  ]
  
  \addplot[
    color=blue,
    mark=*,
    mark size=2pt
  ] coordinates {
    (1,2.3) (2,4.1) (3,5.8) (4,7.2) 
    (5,9.5) (6,11.1) (7,12.8) (8,14.3)
  };
  
  \end{axis}
\end{tikzpicture}

Scatter with Different Markers

Various Marker Styles
\begin{tikzpicture}
  \begin{axis}[
    title={Marker Styles},
    legend pos=outer north east,
    grid=major
  ]
  
  % Circles
  \addplot[only marks, mark=*, color=red] 
    coordinates {(1,1) (2,2) (3,3)};
  \addlegendentry{Circle}
  
  % Squares
  \addplot[only marks, mark=square*, color=blue] 
    coordinates {(1,2) (2,3) (3,4)};
  \addlegendentry{Square}
  
  % Triangles
  \addplot[only marks, mark=triangle*, color=green] 
    coordinates {(1,3) (2,4) (3,5)};
  \addlegendentry{Triangle}
  
  % Diamonds
  \addplot[only marks, mark=diamond*, color=orange] 
    coordinates {(1,4) (2,5) (3,6)};
  \addlegendentry{Diamond}
  
  \end{axis}
\end{tikzpicture}

Function Plots

Plotting Mathematical Functions
\begin{tikzpicture}
  \begin{axis}[
    title={Trigonometric Functions},
    xlabel={$x$},
    ylabel={$f(x)$},
    domain=0:2*pi,
    samples=100,
    grid=major,
    legend pos=south east
  ]
  
  % Sine function
  \addplot[blue, thick] {sin(deg(x))};
  \addlegendentry{$\sin(x)$}
  
  % Cosine function
  \addplot[red, thick] {cos(deg(x))};
  \addlegendentry{$\cos(x)$}
  
  % Tangent function (limited range)
  \addplot[green, thick, domain=0.1:1.4] {tan(deg(x))};
  \addlegendentry{$\tan(x)$}
  
  \end{axis}
\end{tikzpicture}

Exponential and Logarithmic Functions

Exp and Log Functions
\begin{tikzpicture}
  \begin{axis}[
    title={Exponential and Logarithmic},
    xlabel={$x$},
    ylabel={$y$},
    domain=0.1:3,
    samples=50,
    grid=major,
    legend pos=north west,
    ymin=-2, ymax=20
  ]
  
  % Exponential
  \addplot[blue, thick] {exp(x)};
  \addlegendentry{$e^x$}
  
  % Natural logarithm
  \addplot[red, thick] {ln(x)};
  \addlegendentry{$\ln(x)$}
  
  % Power function
  \addplot[green, thick] {x^2};
  \addlegendentry{$x^2$}
  
  \end{axis}
\end{tikzpicture}

Axis and Grid Customization

Axis Range and Ticks

Customizing Axes
\begin{tikzpicture}
  \begin{axis}[
    title={Custom Axis Settings},
    xlabel={Time (s)},
    ylabel={Voltage (V)},
    % Set axis ranges
    xmin=0, xmax=10,
    ymin=-5, ymax=5,
    % Custom tick positions
    xtick={0,2,4,6,8,10},
    ytick={-5,-2.5,0,2.5,5},
    % Grid styling
    grid=both,
    minor tick num=1,
    grid style={line width=.1pt, draw=gray!30},
    major grid style={line width=.2pt, draw=gray!50}
  ]
  
  \addplot[blue, thick, domain=0:10] {3*sin(deg(x))};
  
  \end{axis}
\end{tikzpicture}

Logarithmic Scales

Log Scale Plots
% Semi-log plot (y-axis logarithmic)
\begin{tikzpicture}
  \begin{semilogyaxis}[
    title={Exponential Growth (Semi-log)},
    xlabel={Time},
    ylabel={Population},
    grid=major
  ]
  
  \addplot[blue, thick] coordinates {
    (0,1) (1,10) (2,100) (3,1000) (4,10000)
  };
  
  \end{semilogyaxis}
\end{tikzpicture}

% Log-log plot (both axes logarithmic)
\begin{tikzpicture}
  \begin{loglogaxis}[
    title={Power Law (Log-log)},
    xlabel={$x$},
    ylabel={$y$},
    grid=major
  ]
  
  \addplot[red, thick, domain=1:100] {x^2};
  \addlegendentry{$y = x^2$}
  
  \end{loglogaxis}
\end{tikzpicture}

Styling Options

Line and Marker Styles
\begin{tikzpicture}
  \begin{axis}[
    title={Line Style Examples},
    legend pos=north west
  ]
  
  % Solid line, thick
  \addplot[blue, thick] coordinates {
    (0,1) (1,1.5) (2,2) (3,2.5) (4,3)
  };
  \addlegendentry{Solid thick}
  
  % Dashed line
  \addplot[red, dashed, thick] coordinates {
    (0,2) (1,2.5) (2,3) (3,3.5) (4,4)
  };
  \addlegendentry{Dashed}
  
  % Dotted line
  \addplot[green, dotted, ultra thick] coordinates {
    (0,3) (1,3.5) (2,4) (3,4.5) (4,5)
  };
  \addlegendentry{Dotted}
  
  % Line with markers
  \addplot[black, mark=*, mark options={fill=orange}] 
  coordinates {
    (0,4) (1,4.5) (2,5) (3,5.5) (4,6)
  };
  \addlegendentry{With markers}
  
  \end{axis}
\end{tikzpicture}

Legends and Labels

Legend Positioning

Legend Placement Options
% Inside plot area
\begin{axis}[legend pos=north east]  % or north west, south east, south west
\end{axis}

% Outside plot area
\begin{axis}[
  legend pos=outer north east,
  legend style={
    at={(1.02,1)},
    anchor=north west
  }
]
\end{axis}

% Custom position (relative coordinates)
\begin{axis}[
  legend style={
    at={(0.5,0.97)},
    anchor=north,
    legend columns=3  % Horizontal legend
  }
]
\end{axis}

Annotations and Text

Adding Annotations
\begin{tikzpicture}
  \begin{axis}[
    xlabel={$x$},
    ylabel={$f(x)$}
  ]
  
  \addplot[blue, thick, domain=0:4] {x^2};
  
  % Add text node
  \node[pin=120:{Maximum}] at (axis cs:2,4) {};
  
  % Add arrow with text
  \draw[red, ->] (axis cs:1,3) 
    node[above left] {Interesting point} 
    -- (axis cs:1.5,2.25);
  
  % Add coordinate label
  \node[circle, fill=red, inner sep=2pt] 
    at (axis cs:3,9) {};
  \node[above] at (axis cs:3,9) {$(3,9)$};
  
  \end{axis}
\end{tikzpicture}

Bar Charts and Histograms

Vertical Bar Chart

Simple Bar Chart
\begin{tikzpicture}
  \begin{axis}[
    ybar,
    title={Sales by Quarter},
    ylabel={Revenue (\$1000)},
    xlabel={Quarter},
    symbolic x coords={Q1, Q2, Q3, Q4},
    xtick=data,
    nodes near coords,
    nodes near coords align={vertical},
    ymin=0
  ]
  
  \addplot coordinates {
    (Q1,45) (Q2,52) (Q3,48) (Q4,63)
  };
  
  \end{axis}
\end{tikzpicture}

Grouped Bar Chart

Multiple Bar Series
\begin{tikzpicture}
  \begin{axis}[
    ybar,
    bar width=8pt,
    title={Product Comparison},
    ylabel={Sales},
    xlabel={Month},
    symbolic x coords={Jan, Feb, Mar, Apr},
    xtick=data,
    legend pos=north west,
    ymin=0
  ]
  
  \addplot[fill=blue!60] coordinates {
    (Jan,20) (Feb,25) (Mar,22) (Apr,30)
  };
  \addlegendentry{Product A}
  
  \addplot[fill=red!60] coordinates {
    (Jan,18) (Feb,28) (Mar,24) (Apr,26)
  };
  \addlegendentry{Product B}
  
  \addplot[fill=green!60] coordinates {
    (Jan,22) (Feb,23) (Mar,26) (Apr,28)
  };
  \addlegendentry{Product C}
  
  \end{axis}
\end{tikzpicture}

Stacked Bar Chart

Stacked Bars
\begin{tikzpicture}
  \begin{axis}[
    ybar stacked,
    title={Resource Allocation},
    ylabel={Hours},
    xlabel={Week},
    symbolic x coords={W1, W2, W3, W4},
    xtick=data,
    legend pos=north west,
    ymin=0
  ]
  
  \addplot[fill=blue!60] coordinates {
    (W1,15) (W2,18) (W3,16) (W4,20)
  };
  \addlegendentry{Development}
  
  \addplot[fill=red!60] coordinates {
    (W1,10) (W2,12) (W3,14) (W4,11)
  };
  \addlegendentry{Testing}
  
  \addplot[fill=green!60] coordinates {
    (W1,5) (W2,7) (W3,8) (W4,9)
  };
  \addlegendentry{Documentation}
  
  \end{axis}
\end{tikzpicture}

Horizontal Bar Chart

Horizontal Bars
\begin{tikzpicture}
  \begin{axis}[
    xbar,
    title={Survey Results},
    xlabel={Percentage (\%)},
    ylabel={Category},
    symbolic y coords={Excellent, Good, Fair, Poor},
    ytick=data,
    nodes near coords,
    nodes near coords align={horizontal},
    xmin=0, xmax=100
  ]
  
  \addplot[fill=blue!60] coordinates {
    (45,Excellent) (35,Good) (15,Fair) (5,Poor)
  };
  
  \end{axis}
\end{tikzpicture}

Multiple Plots

Subplots with Groupplots

2x2 Subplot Grid
\usepgfplotslibrary{groupplots}

\begin{tikzpicture}
  \begin{groupplot}[
    group style={
      group size=2 by 2,
      horizontal sep=2cm,
      vertical sep=2cm
    },
    width=6cm,
    height=5cm,
    grid=major
  ]
  
  % Plot 1 (top left)
  \nextgroupplot[title={Linear}, ylabel={$y$}]
  \addplot[blue] {x};
  
  % Plot 2 (top right)
  \nextgroupplot[title={Quadratic}]
  \addplot[red] {x^2};
  
  % Plot 3 (bottom left)
  \nextgroupplot[title={Exponential}, xlabel={$x$}, ylabel={$y$}]
  \addplot[green, domain=0:2] {exp(x)};
  
  % Plot 4 (bottom right)
  \nextgroupplot[title={Sine}, xlabel={$x$}]
  \addplot[purple, domain=0:6.28] {sin(deg(x))};
  
  \end{groupplot}
\end{tikzpicture}

Secondary Y-Axis

Dual Y-Axes
\begin{tikzpicture}
  \begin{axis}[
    scale only axis,
    width=10cm, height=6cm,
    xlabel={Time (s)},
    ylabel={Temperature ($^\circ$C)},
    ylabel style={blue},
    ymin=0, ymax=100,
    legend pos=north west
  ]
  
  \addplot[blue, thick] coordinates {
    (0,20) (1,35) (2,50) (3,70) (4,85)
  };
  \addlegendentry{Temperature}
  
  \end{axis}
  
  % Second y-axis
  \begin{axis}[
    scale only axis,
    width=10cm, height=6cm,
    xlabel={Time (s)},
    ylabel={Pressure (kPa)},
    ylabel style={red},
    ymin=0, ymax=200,
    axis y line*=right,
    legend pos=south east
  ]
  
  \addplot[red, thick, dashed] coordinates {
    (0,50) (1,75) (2,110) (3,150) (4,180)
  };
  \addlegendentry{Pressure}
  
  \end{axis}
\end{tikzpicture}

3D Plots and Surfaces

3D Surface Plot

3D Surface
\begin{tikzpicture}
  \begin{axis}[
    title={3D Surface: $z = \sin(x) \cdot \cos(y)$},
    xlabel={$x$},
    ylabel={$y$},
    zlabel={$z$},
    colormap/viridis,
    view={60}{30}
  ]
  
  \addplot3[
    surf,
    domain=-3:3,
    domain y=-3:3,
    samples=30
  ] {sin(deg(x)) * cos(deg(y))};
  
  \end{axis}
\end{tikzpicture}

3D Mesh Plot

Mesh Surface
\begin{tikzpicture}
  \begin{axis}[
    title={Paraboloid: $z = x^2 + y^2$},
    xlabel={$x$},
    ylabel={$y$},
    zlabel={$z$},
    colormap/hot,
    view={45}{30}
  ]
  
  \addplot3[
    mesh,
    domain=-2:2,
    domain y=-2:2,
    samples=20
  ] {x^2 + y^2};
  
  \end{axis}
\end{tikzpicture}

Contour Plot

2D Contour Lines
\begin{tikzpicture}
  \begin{axis}[
    title={Contour Plot},
    xlabel={$x$},
    ylabel={$y$},
    view={0}{90},
    colorbar,
    colormap/jet
  ]
  
  \addplot3[
    contour gnuplot={levels={-2,-1,0,1,2}},
    domain=-2:2,
    domain y=-2:2,
    samples=40
  ] {x^2 - y^2};
  
  \end{axis}
\end{tikzpicture}

Parametric 3D Curve

3D Parametric Helix
\begin{tikzpicture}
  \begin{axis}[
    title={Helix},
    xlabel={$x$},
    ylabel={$y$},
    zlabel={$z$},
    view={60}{30}
  ]
  
  \addplot3[
    blue,
    thick,
    domain=0:6*pi,
    samples=200,
    samples y=0
  ] ({cos(deg(x))}, {sin(deg(x))}, {x/(2*pi)});
  
  \end{axis}
\end{tikzpicture}

Plotting from Data Files

Reading CSV Files

Plot from External Data
% Create data file: data.csv
% x, y1, y2
% 0, 1.2, 2.1
% 1, 2.5, 3.4
% 2, 3.8, 4.2
% 3, 5.1, 5.8

\begin{tikzpicture}
  \begin{axis}[
    title={Data from CSV},
    xlabel={$x$},
    ylabel={$y$},
    legend pos=north west
  ]
  
  % Read and plot column 1 vs column 2
  \addplot[blue, mark=*] table[
    x=x,
    y=y1,
    col sep=comma
  ] {data.csv};
  \addlegendentry{Series 1}
  
  % Read and plot column 1 vs column 3
  \addplot[red, mark=square*] table[
    x=x,
    y=y2,
    col sep=comma
  ] {data.csv};
  \addlegendentry{Series 2}
  
  \end{axis}
\end{tikzpicture}

Inline Data Tables

Data Table in LaTeX
\begin{tikzpicture}
  \begin{axis}[
    title={Inline Table Data},
    xlabel={Month},
    ylabel={Revenue},
    symbolic x coords={Jan, Feb, Mar, Apr},
    xtick=data
  ]
  
  \addplot table {
    Jan 150
    Feb 180
    Mar 165
    Apr 210
  };
  
  \end{axis}
\end{tikzpicture}

Advanced Techniques

Fill Between Curves

Shaded Area Between Curves
\usepgfplotslibrary{fillbetween}

\begin{tikzpicture}
  \begin{axis}[
    domain=0:2*pi,
    samples=100
  ]
  
  % Plot curves with names
  \addplot[blue, name path=A] {sin(deg(x))};
  \addplot[red, name path=B] {cos(deg(x))};
  
  % Fill area between curves
  \addplot[green!30] fill between[
    of=A and B,
    soft clip={domain=0:1.57}
  ];
  
  \end{axis}
\end{tikzpicture}

Error Bars

Plot with Error Bars
\begin{tikzpicture}
  \begin{axis}[
    title={Experimental Data},
    xlabel={Trial},
    ylabel={Measurement},
    error bars/y dir=both,
    error bars/y explicit
  ]
  
  \addplot[
    blue,
    mark=*,
    error bars/.cd,
    y dir=both,
    y explicit
  ] coordinates {
    (1,10) +- (0,0.5)
    (2,15) +- (0,0.8)
    (3,20) +- (0,1.2)
    (4,22) +- (0,0.9)
    (5,25) +- (0,1.5)
  };
  
  \end{axis}
\end{tikzpicture}

Box Plots

Statistical Box Plot
\usepgfplotslibrary{statistics}

\begin{tikzpicture}
  \begin{axis}[
    title={Box Plot Example},
    ylabel={Distribution},
    boxplot/draw direction=y
  ]
  
  \addplot+[
    boxplot prepared={
      median=5,
      upper quartile=6,
      lower quartile=4,
      upper whisker=8,
      lower whisker=2
    },
  ] coordinates {};
  
  \end{axis}
\end{tikzpicture}

Frequently Asked Questions

How do I install PGFPlots?

PGFPlots comes with most LaTeX distributions. Add \usepackage{pgfplots} and \pgfplotsset{compat=1.18} to your preamble. For manual installation, use tlmgr install pgfplots (TeX Live) or the MiKTeX Package Manager.

Why is my plot compilation slow?

Complex plots (especially 3D surfaces with many samples) can be slow. Solutions: (1) Reduce sample count, (2) Use the externalize library: \usepgfplotslibrary{external} and \tikzexternalize, (3) Compile plots separately and include as images.

Can I plot data from external files?

Yes! PGFPlots supports CSV, DAT, and custom delimited files. Use \addplot table[options] {filename.csv}; with options like x=column1, y=column2, col sep=comma.

How do I change colors in my plots?

Use predefined colors (red, blue, green), color mixing (blue!50), or define custom colors with \definecolor{mycolor}{RGB}{255,100,50}. For color schemes, use colormap/viridis or other built-in colormaps.

Can I create polar plots?

Yes! Load the polar library with \usepgfplotslibrary{polar} and use the polaraxis environment instead of axis.

How do I export plots as standalone images?

Use the standalone document class:

\documentclass[tikz,border=5pt]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}
\begin{document}
\begin{tikzpicture}
  \begin{axis}
    % Your plot here
  \end{axis}
\end{tikzpicture}
\end{document}

What's the difference between samples and domain?

domain sets the x-range (e.g., domain=0:10), while samples sets how many points to calculate (e.g., samples=100). More samples = smoother curves but slower compilation.