> ## Documentation Index
> Fetch the complete documentation index at: https://resources.latex-cloud-studio.com/llms.txt
> Use this file to discover all available pages before exploring further.

# LaTeX Figure Positioning: [h], [t], [b], [p], [H], and Float Placement

> Learn LaTeX figure positioning and float placement. Understand [h], [t], [b], [p], [H], why figures move, and how to place images cleanly.

export const RenderedOutput = ({title = "Rendered output", ctaHref, ctaLabel = "Open LaTeX Cloud Studio", children}) => {
  const [isExpanded, setIsExpanded] = useState(false);
  const trackEditorCta = () => {
    const target = new URL(ctaHref, window.location.href);
    globalThis.posthog?.capture?.("docs_app_cta_clicked", {
      source_page: window.location.pathname,
      source_section: "rendered_output",
      cta_variant: "first_compiled_example",
      target_url: target.toString(),
      target_utm_source: target.searchParams.get("utm_source"),
      target_utm_medium: target.searchParams.get("utm_medium"),
      target_utm_campaign: target.searchParams.get("utm_campaign"),
      target_utm_content: target.searchParams.get("utm_content")
    }, {
      transport: "sendBeacon",
      send_instantly: true
    });
  };
  return <details className="rendered-output" onToggle={event => setIsExpanded(event.currentTarget.open)}>
      <summary className="rendered-output__summary">
        <span className="rendered-output__title">{title}</span>
        <span className="rendered-output__hint" aria-hidden="true">View compiled result</span>
      </summary>
      {isExpanded && <div className="rendered-output__content">
          {children}
          {ctaHref && <aside className="rendered-output__cta" aria-label="Continue in the LaTeX editor">
              <span>
                <strong>Ready to use this syntax?</strong>
                Continue in the browser editor when you want to adapt the example in a real project.
              </span>
              <a href={ctaHref} onClick={trackEditorCta}>{ctaLabel}<span aria-hidden="true"> →</span></a>
            </aside>}
        </div>}
    </details>;
};

export const LatexSource = ({filename, source}) => {
  const [copyStatus, setCopyStatus] = useState("Copy");
  const copySource = async () => {
    try {
      await navigator.clipboard.writeText(source);
      setCopyStatus("Copied");
    } catch {
      setCopyStatus("Select and copy");
    }
  };
  return <figure className="latex-source">
      <figcaption className="latex-source__header">
        <span className="latex-source__filename">{filename}</span>
        <button type="button" className="latex-source__copy" onClick={copySource} aria-live="polite">
          {copyStatus}
        </button>
      </figcaption>
      <pre className="latex-source__pre" aria-label={`LaTeX source: ${filename}`} tabIndex="0">
        <code className="language-latex">{source}</code>
      </pre>
    </figure>;
};

export const LatexPreview = ({src, alt, caption, width, height}) => {
  const minZoom = 1;
  const maxZoom = 3;
  const zoomStep = 0.5;
  const measureSvgContent = async (assetSrc, pageWidth, pageHeight) => {
    const cacheKey = "__latexCloudSvgContentBoxCache";
    const contentBoxCache = globalThis[cacheKey] ?? new Map();
    globalThis[cacheKey] = contentBoxCache;
    if (contentBoxCache.has(assetSrc)) return contentBoxCache.get(assetSrc);
    const measurement = (async () => {
      const assetUrl = new URL(assetSrc, window.location.href);
      if (assetUrl.origin !== window.location.origin) {
        throw new Error("Rendered output must use a same-origin SVG asset.");
      }
      const response = await fetch(assetUrl, {
        credentials: "same-origin"
      });
      if (!response.ok) throw new Error(`Rendered output request failed with ${response.status}.`);
      const source = await response.text();
      const documentNode = new DOMParser().parseFromString(source, "image/svg+xml");
      if (documentNode.querySelector("parsererror")) throw new Error("Rendered output is not valid SVG.");
      const sourceSvg = documentNode.documentElement;
      sourceSvg.querySelectorAll("script, foreignObject").forEach(node => node.remove());
      [sourceSvg, ...sourceSvg.querySelectorAll("*")].forEach(node => {
        [...node.attributes].forEach(attribute => {
          if ((/^on/i).test(attribute.name)) node.removeAttribute(attribute.name);
          if ((attribute.name === "href" || attribute.name === "xlink:href") && !attribute.value.startsWith("#")) {
            node.removeAttribute(attribute.name);
          }
        });
      });
      const measurementHost = document.createElement("div");
      measurementHost.className = "latex-preview__measurement-host";
      const measuredSvg = document.importNode(sourceSvg, true);
      measuredSvg.setAttribute("aria-hidden", "true");
      measurementHost.appendChild(measuredSvg);
      document.body.appendChild(measurementHost);
      try {
        const measuredElements = [...measuredSvg.children].filter(node => !["defs", "desc", "metadata", "style", "title"].includes(node.tagName.toLowerCase()));
        const elementBounds = measuredElements.map(node => node.getBBox()).filter(box => [box.x, box.y, box.width, box.height].every(Number.isFinite) && box.width > 0 && box.height > 0);
        if (elementBounds.length === 0) {
          throw new Error("Rendered output has no measurable visible content.");
        }
        const sortedBounds = [...elementBounds].sort((left, right) => left.y - right.y);
        const clusterGap = pageHeight * 0.045;
        const clusters = [];
        sortedBounds.forEach(box => {
          const current = clusters[clusters.length - 1];
          if (!current || box.y - current.bottom > clusterGap) {
            clusters.push({
              boxes: [box],
              bottom: box.y + box.height
            });
            return;
          }
          current.boxes.push(box);
          current.bottom = Math.max(current.bottom, box.y + box.height);
        });
        const contentClusters = clusters.filter(cluster => {
          const clusterBox = cluster.boxes.reduce((combined, box) => {
            const right = Math.max(combined.x + combined.width, box.x + box.width);
            const bottom = Math.max(combined.y + combined.height, box.y + box.height);
            const x = Math.min(combined.x, box.x);
            const y = Math.min(combined.y, box.y);
            return {
              x,
              y,
              width: right - x,
              height: bottom - y
            };
          });
          const centerY = clusterBox.y + clusterBox.height / 2;
          const isMarginFurniture = cluster.boxes.length <= 2 && clusterBox.width < pageWidth * 0.2 && clusterBox.height < pageHeight * 0.04 && (centerY < pageHeight * 0.08 || centerY > pageHeight * 0.8);
          return !isMarginFurniture;
        });
        const visibleBounds = (contentClusters.length > 0 ? contentClusters : clusters).flatMap(cluster => cluster.boxes);
        const bounds = visibleBounds.reduce((combined, box) => {
          const right = Math.max(combined.x + combined.width, box.x + box.width);
          const bottom = Math.max(combined.y + combined.height, box.y + box.height);
          const x = Math.min(combined.x, box.x);
          const y = Math.min(combined.y, box.y);
          return {
            x,
            y,
            width: right - x,
            height: bottom - y
          };
        });
        const clampValue = (value, minimum, maximum) => Math.min(maximum, Math.max(minimum, value));
        const padding = Math.max(8, Math.min(pageWidth, pageHeight) * 0.025);
        const x = clampValue(bounds.x - padding, 0, pageWidth);
        const y = clampValue(bounds.y - padding, 0, pageHeight);
        const right = clampValue(bounds.x + bounds.width + padding, 0, pageWidth);
        const bottom = clampValue(bounds.y + bounds.height + padding, 0, pageHeight);
        return {
          x,
          y,
          width: right - x,
          height: bottom - y
        };
      } finally {
        measurementHost.remove();
      }
    })();
    contentBoxCache.set(assetSrc, measurement);
    measurement.catch(() => contentBoxCache.delete(assetSrc));
    return measurement;
  };
  const renderPreviewAsset = ({contentBox: assetContentBox, loading}) => {
    if (!assetContentBox) {
      return <img className="latex-preview__asset" src={src} alt={alt} width={width} height={height} loading={loading} draggable="false" />;
    }
    return <svg className="latex-preview__asset" viewBox={`${assetContentBox.x} ${assetContentBox.y} ${assetContentBox.width} ${assetContentBox.height}`} preserveAspectRatio="xMidYMid meet" role="img" aria-label={alt}>
        <image href={src} x="0" y="0" width={width} height={height} />
      </svg>;
  };
  const [isOpen, setIsOpen] = useState(false);
  const [frameMode, setFrameMode] = useState("content");
  const [viewMode, setViewMode] = useState("fit");
  const [zoom, setZoom] = useState(minZoom);
  const [contentBox, setContentBox] = useState(null);
  const [measurementStatus, setMeasurementStatus] = useState("loading");
  const dialogRef = useRef(null);
  const closeButtonRef = useRef(null);
  const viewportRef = useRef(null);
  const previousFocusRef = useRef(null);
  const dragRef = useRef(null);
  useEffect(() => {
    let isCurrent = true;
    setMeasurementStatus("loading");
    measureSvgContent(src, width, height).then(box => {
      if (!isCurrent) return;
      setContentBox(box);
      setMeasurementStatus("ready");
    }).catch(() => {
      if (!isCurrent) return;
      setContentBox(null);
      setFrameMode("page");
      setMeasurementStatus("error");
    });
    return () => {
      isCurrent = false;
    };
  }, [height, src, width]);
  const closeViewer = useCallback(() => {
    setIsOpen(false);
  }, []);
  const openViewer = () => {
    previousFocusRef.current = document.activeElement;
    setFrameMode(contentBox ? "content" : "page");
    setViewMode("fit");
    setZoom(minZoom);
    setIsOpen(true);
  };
  const applyZoom = useCallback(nextZoom => {
    const boundedZoom = Math.min(maxZoom, Math.max(minZoom, nextZoom));
    setViewMode("custom");
    setZoom(boundedZoom);
  }, []);
  const zoomIn = useCallback(() => {
    applyZoom(viewMode === "fit" ? minZoom + zoomStep : zoom + zoomStep);
  }, [applyZoom, viewMode, zoom]);
  const zoomOut = useCallback(() => {
    applyZoom(viewMode === "fit" ? minZoom : zoom - zoomStep);
  }, [applyZoom, viewMode, zoom]);
  useEffect(() => {
    if (!isOpen) return undefined;
    const previousOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    closeButtonRef.current?.focus();
    return () => {
      document.body.style.overflow = previousOverflow;
      previousFocusRef.current?.focus?.();
    };
  }, [isOpen]);
  useEffect(() => {
    if (!isOpen) return undefined;
    const handleKeyDown = event => {
      if (event.key === "Escape") {
        event.preventDefault();
        closeViewer();
        return;
      }
      if ((event.key === "+" || event.key === "=") && !event.metaKey && !event.ctrlKey) {
        event.preventDefault();
        zoomIn();
        return;
      }
      if (event.key === "-" && !event.metaKey && !event.ctrlKey) {
        event.preventDefault();
        zoomOut();
        return;
      }
      if (event.key !== "Tab" || !dialogRef.current) return;
      const focusable = [...dialogRef.current.querySelectorAll('button:not([disabled]), a[href], [tabindex]:not([tabindex="-1"])')];
      if (focusable.length === 0) return;
      const first = focusable[0];
      const last = focusable[focusable.length - 1];
      if (event.shiftKey && document.activeElement === first) {
        event.preventDefault();
        last.focus();
      } else if (!event.shiftKey && document.activeElement === last) {
        event.preventDefault();
        first.focus();
      }
    };
    window.addEventListener("keydown", handleKeyDown);
    return () => {
      window.removeEventListener("keydown", handleKeyDown);
    };
  }, [closeViewer, isOpen, zoomIn, zoomOut]);
  const startDrag = event => {
    if (event.button !== 0 || !viewportRef.current) return;
    const viewport = viewportRef.current;
    dragRef.current = {
      pointerId: event.pointerId,
      x: event.clientX,
      y: event.clientY,
      scrollLeft: viewport.scrollLeft,
      scrollTop: viewport.scrollTop
    };
    viewport.setPointerCapture(event.pointerId);
    viewport.dataset.dragging = "true";
  };
  const continueDrag = event => {
    const drag = dragRef.current;
    const viewport = viewportRef.current;
    if (!drag || !viewport || drag.pointerId !== event.pointerId) return;
    viewport.scrollLeft = drag.scrollLeft - (event.clientX - drag.x);
    viewport.scrollTop = drag.scrollTop - (event.clientY - drag.y);
  };
  const stopDrag = event => {
    const viewport = viewportRef.current;
    if (viewport?.hasPointerCapture(event.pointerId)) viewport.releasePointerCapture(event.pointerId);
    if (viewport) delete viewport.dataset.dragging;
    dragRef.current = null;
  };
  const activeContentBox = frameMode === "content" ? contentBox : null;
  const activeWidth = activeContentBox?.width ?? width;
  const activeHeight = activeContentBox?.height ?? height;
  const activeRatio = activeWidth / activeHeight;
  const inlineContentBox = measurementStatus === "ready" ? contentBox : null;
  const inlineWidth = inlineContentBox?.width ?? width;
  const inlineHeight = inlineContentBox?.height ?? height;
  const inlineGeometry = {
    aspectRatio: `${inlineWidth} / ${inlineHeight}`,
    maxWidth: `${30 * inlineWidth / inlineHeight}rem`
  };
  const imageStyle = viewMode === "fit" ? {
    aspectRatio: `${activeWidth} / ${activeHeight}`,
    width: "100%",
    maxWidth: `${Math.max(16, activeRatio * 78)}dvh`
  } : {
    aspectRatio: `${activeWidth} / ${activeHeight}`,
    width: `${zoom * 100}%`,
    maxWidth: "none"
  };
  const zoomLabel = viewMode === "fit" ? frameMode === "content" ? "Fit content" : "Full page" : `${Math.round(zoom * 100)}%`;
  return <figure className="latex-preview">
      <button type="button" className="latex-preview__trigger" onClick={openViewer} aria-haspopup="dialog" aria-label={`Open zoomable preview: ${alt}`}>
        <span className="latex-preview__page" style={inlineGeometry}>
          {measurementStatus === "loading" ? <span className="latex-preview__loading" role="status">Preparing compiled output…</span> : renderPreviewAsset({
    src,
    alt,
    width,
    height,
    contentBox: inlineContentBox,
    loading: "lazy"
  })}
        </span>
        <span className="latex-preview__trigger-label" aria-hidden="true">
          <span className="latex-preview__trigger-icon">⌕</span>
          Open viewer
        </span>
      </button>
      <figcaption className="latex-preview__caption">
        <span>
          {caption}
          {measurementStatus === "error" && <span className="latex-preview__status" role="status"> Content fit is unavailable; the complete vector page is shown.</span>}
        </span>
        <a href={src} target="_blank" rel="noreferrer" className="latex-preview__source-link">Open SVG</a>
      </figcaption>

      {isOpen && <div className="latex-preview__backdrop" onMouseDown={event => {
    if (event.target === event.currentTarget) closeViewer();
  }}>
          <section ref={dialogRef} className="latex-preview__dialog" role="dialog" aria-modal="true" aria-label={`Rendered LaTeX viewer: ${alt}`}>
            <header className="latex-preview__toolbar">
              <div className="latex-preview__identity">
                <span className="latex-preview__eyebrow">Compiled LaTeX</span>
                <span className="latex-preview__filename">{alt}</span>
              </div>
              <div className="latex-preview__controls" aria-label="Preview controls">
                <button type="button" className={frameMode === "content" && viewMode === "fit" ? "is-active" : undefined} disabled={!contentBox} onClick={() => {
    setFrameMode("content");
    setViewMode("fit");
    setZoom(minZoom);
  }}>
                  Fit content
                </button>
                <button type="button" className={frameMode === "page" && viewMode === "fit" ? "is-active" : undefined} onClick={() => {
    setFrameMode("page");
    setViewMode("fit");
    setZoom(minZoom);
  }}>
                  Full page
                </button>
                <span className="latex-preview__zoom-group">
                  <button type="button" onClick={zoomOut} disabled={viewMode === "fit" || zoom <= minZoom} aria-label="Zoom out">−</button>
                  <output aria-live="polite" aria-label="Current zoom">{zoomLabel}</output>
                  <button type="button" onClick={zoomIn} disabled={viewMode !== "fit" && zoom >= maxZoom} aria-label="Zoom in">+</button>
                </span>
                <a href={src} target="_blank" rel="noreferrer">Open SVG</a>
                <button ref={closeButtonRef} type="button" className="latex-preview__close" onClick={closeViewer} aria-label="Close rendered LaTeX viewer">
                  Close
                </button>
              </div>
            </header>
            <div ref={viewportRef} className="latex-preview__viewport" data-view-mode={viewMode} onPointerDown={startDrag} onPointerMove={continueDrag} onPointerUp={stopDrag} onPointerCancel={stopDrag}>
              <span className="latex-preview__dialog-page" style={imageStyle}>
                {renderPreviewAsset({
    src,
    alt,
    width,
    height,
    contentBox: activeContentBox
  })}
              </span>
            </div>
            <footer className="latex-preview__viewer-note">
              Compiler-generated vector output · Use +/− to zoom · Drag to pan · Esc to close
            </footer>
          </section>
        </div>}
    </figure>;
};

If you need to control LaTeX figure positioning, you need to understand floats first. The placement options `[h]`, `[t]`, `[b]`, `[p]`, and `[H]` do not mean "put the image exactly here" in the way many beginners expect. This guide explains what each option actually does, why figures move, and how to get cleaner layouts without fighting the compiler.

<Info>
  **Key concept**: Figures are "floats" in LaTeX - they can move to optimize page layout. Understanding this behavior is essential for controlling positioning.
</Info>

## Understanding Floats

### What Are Floats?

Floats are elements (figures, tables) that LaTeX can move to avoid awkward page breaks and maintain good typography. LaTeX uses sophisticated algorithms to determine optimal placement.

<LatexSource filename="float-basics.tex" source={"\\documentclass{article}\n\\usepackage{graphicx}\n\\begin{document}\n\nText before the figure.\n\n\\begin{figure}[h]  % 'h' suggests \"here\"\n  \\centering\n  \\includegraphics[width=0.5\\textwidth]{example-image}\n  \\caption{LaTeX may move this figure}\n  \\label{fig:float}\n\\end{figure}\n\nText after the figure definition continues here, but the\nfigure might appear elsewhere in the final document.\n\n\\end{document}"} />

<RenderedOutput title="Rendered output" ctaHref="https://app.latex-cloud-studio.com/?utm_source=resources&utm_medium=rendered_output&utm_campaign=docs_open_app&utm_content=learn_latex_figures_positioning">
  <LatexPreview src="/images/rendered/learn-latex-figures-positioning-01/page-1.svg" alt="Compiled PDF page 1 from float-basics.tex" caption="Generated from the shown source with pdfLaTeX in the pinned LaTeXCloud TeX Live 2026 environment." width={612} height={792} />
</RenderedOutput>

### Why Floats Move

LaTeX moves floats to:

* Avoid large white spaces
* Prevent awkward page breaks
* Keep related content together
* Maintain consistent page density

## Positioning Options

### Basic Float Specifiers

<LatexSource filename="positioning-options.tex" source={"% Single option\n\\begin{figure}[h]   % Here\n\\begin{figure}[t]   % Top of page\n\\begin{figure}[b]   % Bottom of page\n\\begin{figure}[p]   % Page of floats\n\n% Multiple options (order matters)\n\\begin{figure}[ht]  % Try here, then top\n\\begin{figure}[hb]  % Try here, then bottom\n\\begin{figure}[tb]  % Try top, then bottom\n\\begin{figure}[htbp] % Try all positions\n\n% With override\n\\begin{figure}[!h]  % Try harder to place here\n\\begin{figure}[!t]  % Override constraints for top"} />

<RenderedOutput title="Expected effect">
  <Info>
    This code is a contextual or intentionally partial LaTeX excerpt, not a self-contained compilable document. Its visible result depends on the surrounding document, so the documentation shows the expected role without inventing a standalone preview.
  </Info>
</RenderedOutput>

### Positioning Priority

| Specifier | Placement            | Notes                   |
| --------- | -------------------- | ----------------------- |
| `h`       | Here (approximately) | Where defined in source |
| `t`       | Top of page          | Current or next page    |
| `b`       | Bottom of page       | Current or next page    |
| `p`       | Float page           | Page with only floats   |
| `!`       | Override             | Relax LaTeX's rules     |

### Forcing Exact Placement

<LatexSource filename="force-placement.tex" source={"\\documentclass{article}\n\\usepackage{graphicx}\n\\usepackage{float}  % Required for H\n\\begin{document}\n\n% Force exact placement\n\\begin{figure}[H]\n  \\centering\n  \\includegraphics[width=0.5\\textwidth]{image}\n  \\caption{This appears exactly here}\n\\end{figure}\n\n% Alternative: suppress floating\n\\begin{center}\n  \\includegraphics[width=0.5\\textwidth]{image}\n  \\captionof{figure}{Non-floating figure}\n  \\label{fig:nonfloat}\n\\end{center}\n\n\\end{document}"} />

<RenderedOutput title="Expected effect">
  <Info>
    This excerpt depends on project files such as images, bibliography data, or included TeX sources that are not part of this standalone code box. Its exact output is project-specific, so no fabricated preview is shown.
  </Info>
</RenderedOutput>

<Warning>
  **Caution**: Using `[H]` can create large white spaces and poor page breaks. Use sparingly.
</Warning>

## Advanced Positioning Control

### Float Parameters

<LatexSource filename="float-parameters.tex" source={"% Control float placement rules\n\\setcounter{topnumber}{2}        % Max floats at top of page\n\\setcounter{bottomnumber}{1}     % Max floats at bottom\n\\setcounter{totalnumber}{3}      % Max floats per page\n\n% Fraction of page for floats\n\\renewcommand{\\topfraction}{0.8}    % Max 80% of page for top floats\n\\renewcommand{\\bottomfraction}{0.5} % Max 50% for bottom floats\n\\renewcommand{\\textfraction}{0.2}   % Min 20% must be text\n\\renewcommand{\\floatpagefraction}{0.7} % Min 70% of float page\n\n% Vertical spacing\n\\setlength{\\floatsep}{12pt}      % Between floats\n\\setlength{\\textfloatsep}{20pt}  % Between text and float\n\\setlength{\\intextsep}{12pt}     % For wrapfig"} />

<RenderedOutput title="Expected effect">
  <Info>
    This is setup or structural LaTeX code. It changes available commands or document behavior, but it does not produce meaningful standalone page content by itself.
  </Info>
</RenderedOutput>

### Clearing Floats

<LatexSource filename="clearing-floats.tex" source={"% Force all pending floats\n\\clearpage  % Start new page after floats\n\n% Clear without page break\n\\usepackage{afterpage}\n\\afterpage{\\clearpage}  % Clear after current page\n\n% Clear specific float type\n\\usepackage{placeins}\n\\FloatBarrier  % Prevent floats from passing\n\n% Section-wise float barriers\n\\usepackage[section]{placeins}  % Floats don't cross sections"} />

<RenderedOutput title="Expected effect">
  <Info>
    This code is a contextual or intentionally partial LaTeX excerpt, not a self-contained compilable document. Its visible result depends on the surrounding document, so the documentation shows the expected role without inventing a standalone preview.
  </Info>
</RenderedOutput>

## Multiple Figures Layout

### Side-by-Side Positioning

<LatexSource filename="side-by-side-advanced.tex" source={"\\documentclass{article}\n\\usepackage{graphicx}\n\\usepackage{subcaption}\n\\begin{document}\n\n% Method 1: Minipage\n\\begin{figure}[htbp]\n  \\centering\n  \\begin{minipage}{0.45\\textwidth}\n    \\centering\n    \\includegraphics[width=\\textwidth]{image1}\n    \\caption{First figure}\n  \\end{minipage}\n  \\hfill\n  \\begin{minipage}{0.45\\textwidth}\n    \\centering\n    \\includegraphics[width=\\textwidth]{image2}\n    \\caption{Second figure}\n  \\end{minipage}\n\\end{figure}\n\n% Method 2: Subfigures with references\n\\begin{figure}[htbp]\n  \\centering\n  \\begin{subfigure}[t]{0.45\\textwidth}\n    \\centering\n    \\includegraphics[width=\\textwidth]{imageA}\n    \\caption{Subfigure A}\n    \\label{fig:subA}\n  \\end{subfigure}\n  \\hfill\n  \\begin{subfigure}[t]{0.45\\textwidth}\n    \\centering\n    \\includegraphics[width=\\textwidth]{imageB}\n    \\caption{Subfigure B}\n    \\label{fig:subB}\n  \\end{subfigure}\n  \\caption{Main caption for both figures}\n  \\label{fig:both}\n\\end{figure}\n\nReference: Figure \\ref{fig:subA} shows X, while Figure \\ref{fig:subB} shows Y.\n\n\\end{document}"} />

<RenderedOutput title="Expected effect">
  <Info>
    This excerpt depends on project files such as images, bibliography data, or included TeX sources that are not part of this standalone code box. Its exact output is project-specific, so no fabricated preview is shown.
  </Info>
</RenderedOutput>

### Custom Arrangements

<LatexSource filename="custom-arrangements.tex" source={"% Three figures with different sizes\n\\begin{figure}[htbp]\n  \\centering\n  % Large figure on left\n  \\begin{minipage}{0.5\\textwidth}\n    \\includegraphics[width=\\textwidth]{large}\n  \\end{minipage}\n  \\hfill\n  % Two small figures on right\n  \\begin{minipage}{0.45\\textwidth}\n    \\includegraphics[width=\\textwidth]{small1}\\\\[0.5cm]\n    \\includegraphics[width=\\textwidth]{small2}\n  \\end{minipage}\n  \\caption{Custom arrangement}\n\\end{figure}\n\n% L-shaped arrangement\n\\begin{figure}[htbp]\n  \\centering\n  \\begin{tabular}{cc}\n    \\includegraphics[width=0.3\\textwidth]{img1} &\n    \\includegraphics[width=0.3\\textwidth]{img2} \\\\\n    \\multicolumn{2}{c}{\n      \\includegraphics[width=0.6\\textwidth]{img3}\n    }\n  \\end{tabular}\n  \\caption{L-shaped layout}\n\\end{figure}"} />

<RenderedOutput title="Expected effect">
  <Info>
    This excerpt depends on project files such as images, bibliography data, or included TeX sources that are not part of this standalone code box. Its exact output is project-specific, so no fabricated preview is shown.
  </Info>
</RenderedOutput>

## Page-Wide Figures

### Full Width in Two-Column

<LatexSource filename="full-width.tex" source={"\\documentclass[twocolumn]{article}\n\\usepackage{graphicx}\n\\begin{document}\n\n% Regular figure (one column)\n\\begin{figure}[htbp]\n  \\centering\n  \\includegraphics[width=\\columnwidth]{small-image}\n  \\caption{Column-width figure}\n\\end{figure}\n\n% Full page width\n\\begin{figure*}[htbp]\n  \\centering\n  \\includegraphics[width=\\textwidth]{wide-image}\n  \\caption{Full page-width figure}\n\\end{figure*}\n\n\\end{document}"} />

<RenderedOutput title="Expected effect">
  <Info>
    This excerpt depends on project files such as images, bibliography data, or included TeX sources that are not part of this standalone code box. Its exact output is project-specific, so no fabricated preview is shown.
  </Info>
</RenderedOutput>

### Landscape Figures

<LatexSource filename="landscape-figures.tex" source={"\\usepackage{rotating}\n\\usepackage{pdflscape}  % Rotates PDF page\n\n% Rotated figure\n\\begin{sidewaysfigure}\n  \\centering\n  \\includegraphics[width=\\textwidth]{wide-diagram}\n  \\caption{Rotated to fit}\n\\end{sidewaysfigure}\n\n% Landscape page\n\\begin{landscape}\n\\begin{figure}\n  \\centering\n  \\includegraphics[width=\\linewidth]{very-wide-image}\n  \\caption{On landscape page}\n\\end{figure}\n\\end{landscape}"} />

<RenderedOutput title="Expected effect">
  <Info>
    This excerpt depends on project files such as images, bibliography data, or included TeX sources that are not part of this standalone code box. Its exact output is project-specific, so no fabricated preview is shown.
  </Info>
</RenderedOutput>

## Precise Positioning

### Absolute Positioning

<LatexSource filename="absolute-positioning.tex" source={"\\usepackage{tikz}\n\\usepackage{eso-pic}\n\n% Place at specific coordinates\n\\AddToShipoutPictureBG{%\n  \\AtPageUpperLeft{%\n    \\put(2cm,-5cm){%\n      \\includegraphics[width=3cm]{logo}\n    }%\n  }%\n}\n\n% Using TikZ\n\\begin{tikzpicture}[remember picture,overlay]\n  \\node at (current page.center) {\n    \\includegraphics[width=5cm]{watermark}\n  };\n\\end{tikzpicture}"} />

<RenderedOutput title="Expected effect">
  <Info>
    This excerpt depends on project files such as images, bibliography data, or included TeX sources that are not part of this standalone code box. Its exact output is project-specific, so no fabricated preview is shown.
  </Info>
</RenderedOutput>

### Margin Figures

<LatexSource filename="margin-figures.tex" source={"% For books/reports with wide margins\n\\marginpar{\n  \\centering\n  \\includegraphics[width=\\marginparwidth]{small-image}\n  \\captionof{figure}{Margin figure}\n}\n\n% Using marginfigure (tufte-latex)\n\\begin{marginfigure}\n  \\includegraphics[width=\\textwidth]{image}\n  \\caption{In the margin}\n\\end{marginfigure}"} />

<RenderedOutput title="Expected effect">
  <Info>
    This excerpt depends on project files such as images, bibliography data, or included TeX sources that are not part of this standalone code box. Its exact output is project-specific, so no fabricated preview is shown.
  </Info>
</RenderedOutput>

## Float Management Strategies

### Document-Wide Settings

<LatexSource filename="global-settings.tex" source={"% Preamble settings for better float handling\n\n% Allow more floats\n\\setcounter{totalnumber}{6}\n\\setcounter{topnumber}{4}\n\\setcounter{bottomnumber}{4}\n\n% Relax float constraints\n\\renewcommand{\\topfraction}{0.9}\n\\renewcommand{\\bottomfraction}{0.8}\n\\renewcommand{\\textfraction}{0.1}\n\\renewcommand{\\floatpagefraction}{0.8}\n\n% Penalties for float placement\n\\setlength{\\floatsep}{10pt plus 3pt minus 2pt}\n\\setlength{\\textfloatsep}{15pt plus 3pt minus 3pt}\n\\setlength{\\intextsep}{10pt plus 3pt minus 2pt}\n\n% Stricter float placement\n\\usepackage[section]{placeins}  % Floats within sections"} />

<RenderedOutput title="Expected effect">
  <Info>
    This is setup or structural LaTeX code. It changes available commands or document behavior, but it does not produce meaningful standalone page content by itself.
  </Info>
</RenderedOutput>

### Managing Many Figures

<LatexSource filename="many-figures.tex" source={"% Strategy 1: Group related figures\n\\begin{figure}[p]  % Float page\n  \\centering\n  \\includegraphics[width=0.45\\textwidth]{fig1}\n  \\includegraphics[width=0.45\\textwidth]{fig2}\\\\[1em]\n  \\includegraphics[width=0.45\\textwidth]{fig3}\n  \\includegraphics[width=0.45\\textwidth]{fig4}\n  \\caption{Related figures grouped}\n\\end{figure}\n\n% Strategy 2: Process floats periodically\nText and figures...\n\\clearpage  % Force processing\n\n% Strategy 3: Use non-floating alternatives\n\\begin{center}\n  \\includegraphics[width=0.8\\textwidth]{image}\n  \\captionof{figure}{Non-floating alternative}\n\\end{center}"} />

<RenderedOutput title="Expected effect">
  <Info>
    This excerpt depends on project files such as images, bibliography data, or included TeX sources that are not part of this standalone code box. Its exact output is project-specific, so no fabricated preview is shown.
  </Info>
</RenderedOutput>

## Debugging Float Issues

### Common Problems and Solutions

<LatexSource filename="float-debugging.tex" source={"% Problem: Figure appears too late\n% Solution 1: Add more placement options\n\\begin{figure}[!htbp]  % Try harder\n\n% Solution 2: Clear floats\n\\clearpage  % Before problematic section\n\n% Problem: \"Too many unprocessed floats\"\n% Solution: Process pending floats\n\\clearpage\n% Or increase counter\n\\usepackage{morefloats}  % Allows more floats\n\n% Problem: Large gaps\n% Solution: Adjust parameters\n\\setlength{\\textfloatsep}{10pt plus 2pt minus 2pt}\n\n% Check float queue\n\\usepackage{showframe}  % Shows page layout\n\\usepackage{layout}     % \\layout command"} />

<RenderedOutput title="Expected effect">
  <Info>
    This code is a contextual or intentionally partial LaTeX excerpt, not a self-contained compilable document. Its visible result depends on the surrounding document, so the documentation shows the expected role without inventing a standalone preview.
  </Info>
</RenderedOutput>

## How to Force a Figure to Stay in Its Own Section

A float can drift several pages past the point where it was declared, which often
means it appears under the wrong heading. This is normal float behaviour, not a bug:
LaTeX moves floats to wherever they fit.

The reliable fix is a float barrier. `\usepackage{placeins}` provides
`\FloatBarrier`, which forces every pending float to be placed before the document
continues. Put it at the end of a section, and no figure can escape into the next
one.

`\usepackage[section]{placeins}` does this automatically at every `\section`, which
is usually what people want when they ask this question.

`\clearpage` also flushes floats, but it starts a new page, so it is a heavier tool.
Reach for `\FloatBarrier` first.

Forcing exact placement with `[H]` from `float` is a different thing and a worse
default — it disables floating entirely and tends to leave large gaps.

## Best Practices

<Tip>
  **Float positioning guidelines:**

  1. **Default first**: Start with `[htbp]` for most figures
  2. **Avoid `[h]` only**: Too restrictive, add alternatives
  3. **Group related**: Put related figures together
  4. **Clear periodically**: Use `\clearpage` at chapter/section ends
  5. **Size appropriately**: Oversized figures cause problems
  6. **Think document-wide**: Consider overall flow, not just local placement
  7. **Use packages wisely**: `float`, `placeins`, `afterpage` for control
</Tip>

## Quick Reference

### Placement Options

<LatexSource filename="example.tex" source={"[h]     % Here\n[t]     % Top\n[b]     % Bottom\n[p]     % Page of floats\n[!]     % Override constraints\n[H]     % HERE (requires float package)\n[htbp]  % Recommended default"} />

<RenderedOutput title="Rendered output">
  <LatexPreview src="/images/rendered/learn-latex-figures-positioning-15/page-1.svg" alt="Compiled PDF page 1 from example.tex" caption="Generated from the shown source with pdfLaTeX in the pinned LaTeXCloud TeX Live 2026 environment. The visible fragment is compiled inside the documented minimal article wrapper." width={595.276} height={841.89} />
</RenderedOutput>

### Key Commands

| Command                | Purpose                  |
| ---------------------- | ------------------------ |
| `\clearpage`           | Process all floats       |
| `\FloatBarrier`        | Boundary for floats      |
| `\captionof{figure}{}` | Caption without float    |
| `figure*`              | Full width in two-column |

***

<Info>
  **Next**: Learn about [Creating tables](/learn/latex/tables/creating-tables) to present structured data effectively. Tables use similar positioning concepts to figures. You might also be interested in [Cross-referencing](/learn/latex/cross-referencing) to link to your figures and tables.
</Info>
