A comprehensive Python library for programmatically creating and compiling LaTeX documents and snippets.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Advanced layout control with positioning, spacing, alignment, and minipage environments for precise document formatting. PyLaTeX provides comprehensive tools for managing document layout, from simple spacing commands to complex multi-column layouts and precise element positioning.
Control horizontal and vertical spacing between document elements with precise measurements.
class HorizontalSpace(CommandBase):
def __init__(self, size, *, star=True):
"""
Add horizontal space between elements.
Parameters:
- size: str, amount of space to add (e.g., '1cm', '10pt', '0.5in')
- star: bool, use starred version (hspace*) that doesn't disappear at line breaks
"""
class VerticalSpace(CommandBase):
def __init__(self, size, *, star=True):
"""
Add vertical space between elements.
Parameters:
- size: str, amount of space to add (e.g., '1cm', '10pt', '0.5em')
- star: bool, use starred version (vspace*) that doesn't disappear at page breaks
"""Usage example:
from pylatex import Document, Section, NoEscape
from pylatex.position import HorizontalSpace, VerticalSpace
doc = Document()
with doc.create(Section('Spacing Examples')):
doc.append('Text before horizontal space')
doc.append(HorizontalSpace('2cm'))
doc.append('Text after 2cm space')
doc.append(VerticalSpace('1cm'))
doc.append('Text after 1cm vertical space')
# Negative spacing (overlap)
doc.append('Overlapping')
doc.append(HorizontalSpace('-0.5cm'))
doc.append('Text')
# Various units
doc.append(VerticalSpace('2em')) # Relative to font size
doc.append('Text after 2em space')
doc.append(VerticalSpace('12pt')) # Points
doc.append('Text after 12pt space')
doc.append(VerticalSpace('0.2in')) # Inches
doc.append('Text after 0.2 inch space')Control text and content alignment within specific regions of the document.
class Center(Environment):
"""
Center-aligned environment.
Requires:
- ragged2e package (automatically added)
"""
class FlushLeft(Environment):
"""
Left-aligned environment.
Requires:
- ragged2e package (automatically added)
"""
class FlushRight(Environment):
"""
Right-aligned environment.
Requires:
- ragged2e package (automatically added)
"""Usage example:
from pylatex import Document, Section
from pylatex.position import Center, FlushLeft, FlushRight
doc = Document()
with doc.create(Section('Text Alignment')):
with doc.create(Center()):
doc.append('This text is centered on the page.')
doc.append('Multiple lines are all centered.')
with doc.create(FlushLeft()):
doc.append('This text is left-aligned.')
doc.append('Even in a document with different default alignment.')
with doc.create(FlushRight()):
doc.append('This text is right-aligned.')
doc.append('Useful for signatures or dates.')
# Centering specific elements
with doc.create(Section('Centered Elements')):
doc.append('Normal paragraph text flows naturally.')
with doc.create(Center()):
doc.append('--- Important Notice ---')
doc.append('Back to normal text flow after the centered element.')Create flexible sub-documents within the main document with independent formatting and layout control.
class MiniPage(Environment):
def __init__(self, *, width=NoEscape(r"\textwidth"), pos=None,
height=None, content_pos=None, align=None,
fontsize=None, data=None):
"""
Create a minipage environment for complex layouts.
Parameters:
- width: str or NoEscape, width of minipage (default: full text width)
- pos: str, vertical alignment relative to baseline ('c', 't', 'b')
- 'c': center (default)
- 't': top
- 'b': bottom
- height: str, fixed height of minipage
- content_pos: str, content position within minipage ('c', 't', 'b', 's')
- 'c': center
- 't': top
- 'b': bottom
- 's': stretch (spread content)
- align: str, text alignment within minipage
- fontsize: str, font size for minipage content
- data: initial content
Requires:
- ragged2e package (automatically added)
"""Usage example:
from pylatex import Document, Section, NoEscape
from pylatex.position import MiniPage
from pylatex.figure import StandAloneGraphic
doc = Document()
with doc.create(Section('Complex Layouts')):
# Side-by-side content
with doc.create(MiniPage(width=NoEscape(r'0.45\textwidth'))) as left:
left.append('This is the left column content. ')
left.append('It can contain multiple paragraphs and will wrap ')
left.append('within the specified width.')
doc.append(NoEscape(r'\hfill')) # Push to opposite sides
with doc.create(MiniPage(width=NoEscape(r'0.45\textwidth'))) as right:
right.append('This is the right column content. ')
right.append('Both minipages will appear side by side ')
right.append('on the same horizontal line.')
# Text and image layout
with doc.create(Section('Mixed Content Layout')):
with doc.create(MiniPage(width=NoEscape(r'0.6\textwidth'),
pos='t')) as text_box:
text_box.append('Detailed explanation of the concept. ')
text_box.append('This text appears alongside the diagram. ')
text_box.append('The minipage allows precise control over ')
text_box.append('the text width and positioning.')
doc.append(NoEscape(r'\hfill'))
with doc.create(MiniPage(width=NoEscape(r'0.35\textwidth'),
pos='t')) as image_box:
image_box.append(StandAloneGraphic('diagram.png',
image_options=NoEscape(r'width=\textwidth')))
# Vertical alignment examples
with doc.create(Section('Vertical Alignment')):
with doc.create(MiniPage(width=NoEscape(r'0.3\textwidth'),
height='4cm', pos='t', content_pos='t')) as top:
top.append('Content aligned to top of minipage.')
doc.append(NoEscape(r'\hfill'))
with doc.create(MiniPage(width=NoEscape(r'0.3\textwidth'),
height='4cm', pos='t', content_pos='c')) as center:
center.append('Content centered in minipage.')
doc.append(NoEscape(r'\hfill'))
with doc.create(MiniPage(width=NoEscape(r'0.3\textwidth'),
height='4cm', pos='t', content_pos='b')) as bottom:
bottom.append('Content aligned to bottom.')from pylatex import Document, Section, NoEscape
from pylatex.position import MiniPage
doc = Document()
with doc.create(Section('Three-Column Layout')):
# Three equal columns
column_width = NoEscape(r'0.32\textwidth')
with doc.create(MiniPage(width=column_width, pos='t')) as col1:
col1.append('First Column')
col1.append('Content for the first column goes here. ')
col1.append('This could be text, lists, or other elements.')
doc.append(NoEscape(r'\hfill'))
with doc.create(MiniPage(width=column_width, pos='t')) as col2:
col2.append('Second Column')
col2.append('Content for the second column. ')
col2.append('Each column is independent.')
doc.append(NoEscape(r'\hfill'))
with doc.create(MiniPage(width=column_width, pos='t')) as col3:
col3.append('Third Column')
col3.append('Final column content. ')
col3.append('Columns align at the top.')
# Asymmetric layout
with doc.create(Section('Asymmetric Layout')):
# Wide left, narrow right
with doc.create(MiniPage(width=NoEscape(r'0.7\textwidth'))) as main:
main.append('Main Content Area')
main.append('This wider area contains the primary content. ')
main.append('It takes up most of the page width.')
doc.append(NoEscape(r'\hfill'))
with doc.create(MiniPage(width=NoEscape(r'0.25\textwidth'))) as sidebar:
sidebar.append('Sidebar')
sidebar.append('Notes, references, or supplementary information.')from pylatex import Document, Section, Command, NoEscape
from pylatex.position import MiniPage, Center
doc = Document()
with doc.create(Section('Boxed Content')):
# Framed minipage
with doc.create(Center()):
doc.append(Command('fbox',
MiniPage(width=NoEscape(r'0.8\textwidth'), data=[
'Important Information',
NoEscape(r'\\[0.5em]'),
'This content is highlighted in a box for emphasis. ',
'The minipage provides the content structure, while ',
'fbox adds the border.'
])
))
# Custom spacing and padding
with doc.create(Section('Padded Boxes')):
with doc.create(Center()):
# Custom padding using fboxsep
doc.append(Command('setlength', arguments=[NoEscape(r'\fboxsep'), '10pt']))
doc.append(Command('fbox',
MiniPage(width=NoEscape(r'0.6\textwidth'), data=[
'Padded Content',
NoEscape(r'\\[0.5em]'),
'Extra padding makes this more readable.'
])
))from pylatex import Document, Section, NoEscape
from pylatex.position import MiniPage, FlushLeft, FlushRight, Center
doc = Document()
# Custom header layout
def create_header(title, author, date):
with doc.create(MiniPage(width=NoEscape(r'\textwidth'))) as header:
with header.create(FlushLeft()):
header.append(f'Title: {title}')
with header.create(Center()):
header.append(f'Author: {author}')
with header.create(FlushRight()):
header.append(f'Date: {date}')
doc.append(NoEscape(r'\hrule'))
doc.append(NoEscape(r'\vspace{1em}'))
create_header('Research Report', 'Dr. Jane Smith', '2024-01-15')
with doc.create(Section('Document Content')):
doc.append('Main document content follows the custom header.')class TextBlock(Environment):
def __init__(self, width, horizontal_pos, vertical_pos, *,
indent=False, data=None):
"""
Create positioned text block using textpos package.
Parameters:
- width: float, width of text block in TPHorizModule units
- horizontal_pos: float, horizontal position in TPHorizModule units
- vertical_pos: float, vertical position in TPVertModule units
- indent: bool, enable paragraph indentation (default False)
- data: initial content for the text block
Requires:
- textpos package (automatically added)
"""Usage example:
from pylatex import Document, Package
from pylatex.position import TextBlock
doc = Document()
doc.packages.append(Package('textpos'))
# Absolute positioning
with doc.create(TextBlock(width='5cm', horizontal_pos=2, vertical_pos=3)):
doc.append('This text block is positioned at specific coordinates.')
doc.append('Useful for overlays, annotations, or precise layouts.')from pylatex import Document, NoEscape
from pylatex.position import HorizontalSpace, VerticalSpace
doc = Document()
# Responsive spacing
doc.append('Text')
doc.append(HorizontalSpace(NoEscape(r'0.1\textwidth'))) # 10% of text width
doc.append('More text')
# Fill remaining space
doc.append('Left')
doc.append(NoEscape(r'\hfill')) # Fills all available space
doc.append('Right')
# Stretchable space
doc.append('Item 1')
doc.append(NoEscape(r'\hspace{\stretch{1}}'))
doc.append('Item 2')
doc.append(NoEscape(r'\hspace{\stretch{2}}')) # Twice as much space
doc.append('Item 3')from pylatex import Document, Command, Package, NoEscape
from pylatex.position import VerticalSpace
doc = Document()
doc.packages.append(Package('geometry', options=['margin=1in']))
# Page-level spacing adjustments
doc.preamble.append(Command('setlength', arguments=[NoEscape(r'\parskip'), '1em']))
doc.preamble.append(Command('setlength', arguments=[NoEscape(r'\parindent'), '0pt']))
# Dynamic page breaks
doc.append('Content before page break')
doc.append(VerticalSpace(NoEscape(r'\fill'))) # Push to bottom
doc.append('Content at bottom of page')
doc.append(Command('newpage'))
doc.append('Content on next page')from pylatex import Document, Package, NoEscape, Command
from pylatex.position import MiniPage
doc = Document()
doc.packages.append(Package('tikz'))
# TikZ overlay on minipage
with doc.create(MiniPage(width=NoEscape(r'0.8\textwidth'))) as container:
container.append('Base content that will have overlays.')
container.append(NoEscape(r'\\[2em]'))
container.append('More base content here.')
# Add TikZ overlay
container.append(NoEscape(r'''
\begin{tikzpicture}[remember picture, overlay]
\node[red, font=\Large] at (2, 0) {Overlay Text};
\draw[blue, thick] (0, -1) rectangle (4, 1);
\end{tikzpicture}
'''))from pylatex import Document, Command, NoEscape
from pylatex.position import MiniPage
doc = Document()
# Conditional layout based on text width
doc.preamble.append(Command('newlength', arguments=NoEscape(r'\columnwidth')))
doc.preamble.append(Command('setlength', arguments=[
NoEscape(r'\columnwidth'), NoEscape(r'0.45\textwidth')
]))
# Use calculated width
with doc.create(MiniPage(width=NoEscape(r'\columnwidth'))) as responsive:
responsive.append('This minipage uses a calculated width.')
responsive.append('It adapts to different document settings.')Layout functionality requires specific LaTeX packages:
ragged2e package (automatically added)ragged2e package (automatically added)textpos package (must be added manually)tikz package for overlaysfrom pylatex import Document, Package
doc = Document()
# Layout packages
doc.packages.append(Package('ragged2e'))
doc.packages.append(Package('textpos'))
doc.packages.append(Package('tikz'))
doc.packages.append(Package('geometry', options=['margin=1in']))from pylatex import Document, Command, NoEscape
from pylatex.position import VerticalSpace
doc = Document()
# Define standard spacing units
doc.preamble.append(Command('newlength', arguments=NoEscape(r'\standardspace')))
doc.preamble.append(Command('setlength', arguments=[
NoEscape(r'\standardspace'), '1em'
]))
# Use consistent spacing throughout
doc.append('Section 1')
doc.append(VerticalSpace(NoEscape(r'\standardspace')))
doc.append('Section 2')
doc.append(VerticalSpace(NoEscape(r'\standardspace')))
doc.append('Section 3')from pylatex import Document, NoEscape
from pylatex.position import MiniPage, Center
def create_info_box(title, content, width=NoEscape(r'0.8\textwidth')):
"""Create a standardized information box."""
with doc.create(Center()):
with doc.create(MiniPage(width=width)) as box:
with box.create(Center()):
box.append(Command('textbf', title))
box.append(NoEscape(r'\\[0.5em]'))
box.append(content)
return box
doc = Document()
# Reusable layout components
create_info_box('Important Note', 'This is highlighted information.')
create_info_box('Warning', 'Please review this carefully.')The layout system in PyLaTeX provides powerful tools for creating professional, precisely controlled document layouts while maintaining the flexibility to adapt to different content requirements.
Install with Tessl CLI
npx tessl i tessl/pypi-pylatex