A comprehensive Python package for creating, reading, modifying, and writing DXF (Drawing Exchange Format) documents with support for multiple DXF versions.
—
Layout management system for organizing drawing content in Model Space (3D geometry) and Paper Space (plotting layouts). Layouts provide the structure for placing entities and managing drawing hierarchy.
Core layout functionality for managing drawing organization and entity placement.
class Layout:
"""Base layout class with entity management"""
@property
def name(self) -> str:
"""Layout name"""
@property
def dxf_layout(self):
"""Associated DXF layout table entry"""
def __len__(self) -> int:
"""Number of entities in layout"""
def __iter__(self):
"""Iterate over entities in layout"""
def query(self, query: str = '*'):
"""
Query entities by criteria.
Parameters:
- query: entity selection query string ('*', 'LINE', 'CIRCLE[layer=="0"]', etc.)
Returns:
EntityQuery: Collection of matching entities
"""
def groupby(self, dxfattrib: str = '', key = None):
"""Group entities by DXF attribute or custom key function"""
def delete_entity(self, entity): ...
def delete_all_entities(self): ...
def unlink_entity(self, entity): ...
class Modelspace(Layout):
"""Model space layout for 3D geometry and main drawing content"""
def add_foreign_entity(self, entity, copy: bool = True):
"""Add entity from another document"""
class Paperspace(Layout):
"""Paper space layout for plotting and annotation"""
@property
def page_setup(self):
"""Page setup configuration"""
class BlockLayout(Layout):
"""Block definition layout containing block entities"""
@property
def block(self):
"""Associated block definition entity"""
@property
def endblk(self):
"""Block end marker entity"""
@property
def attdefs(self):
"""Attribute definitions in block"""Usage examples:
import ezdxf
doc = ezdxf.new()
# Access model space
msp = doc.modelspace()
print(f"Entities in model space: {len(msp)}")
# Create paper space layout
psp = doc.new_layout('Plot Layout')
# Query entities
lines = msp.query('LINE') # All lines
red_circles = msp.query('CIRCLE[color==1]') # Red circles
layer0_entities = msp.query('*[layer=="0"]') # All entities on layer 0
# Group entities
by_layer = msp.groupby('layer')
for layer_name, entities in by_layer.items():
print(f"Layer {layer_name}: {len(entities)} entities")Factory methods for creating and adding entities to layouts.
# Basic geometry
def add_point(self, location, dxfattribs: dict = None) -> Point: ...
def add_line(self, start, end, dxfattribs: dict = None) -> Line: ...
def add_circle(self, center, radius: float, dxfattribs: dict = None) -> Circle: ...
def add_arc(self, center, radius: float, start_angle: float, end_angle: float,
dxfattribs: dict = None) -> Arc: ...
def add_ellipse(self, center, major_axis, ratio: float = 1,
start_param: float = 0, end_param: float = 2*pi,
dxfattribs: dict = None) -> Ellipse: ...
# Text entities
def add_text(self, text: str, dxfattribs: dict = None) -> Text: ...
def add_mtext(self, text: str, dxfattribs: dict = None) -> MText: ...
# Polylines
def add_lwpolyline(self, points, format: str = 'xy', dxfattribs: dict = None) -> LWPolyline: ...
def add_polyline2d(self, points, dxfattribs: dict = None) -> Polyline: ...
def add_polyline3d(self, points, dxfattribs: dict = None) -> Polyline: ...
# Curves
def add_spline(self, control_points, degree: int = 3, dxfattribs: dict = None) -> Spline: ...
def add_spline_with_a_fit_points(self, fit_points, degree: int = 3,
dxfattribs: dict = None) -> Spline: ...
# Complex entities
def add_hatch(self, color: int = 256, dxfattribs: dict = None) -> Hatch: ...
def add_mpolygon(self, dxfattribs: dict = None) -> MPolygon: ...
def add_mesh(self, dxfattribs: dict = None) -> Mesh: ...
# Block insertions
def add_insert(self, name: str, insert = (0, 0), dxfattribs: dict = None) -> Insert: ...
def add_auto_blockref(self, name: str, insert = (0, 0), values: dict = None,
dxfattribs: dict = None) -> Insert: ...
# Images and underlays
def add_image(self, image_def, insert = (0, 0), size_in_units = (1, 1),
rotation: float = 0, dxfattribs: dict = None) -> Image: ...
def add_underlay(self, underlay_def, insert = (0, 0), scale = (1, 1, 1),
rotation: float = 0, dxfattribs: dict = None) -> Underlay: ...
# Dimensions
def add_linear_dim(self, base, p1, p2, dimstyle: str = 'EZDXF',
override: dict = None, dxfattribs: dict = None): ...
def add_aligned_dim(self, p1, p2, distance: float, dimstyle: str = 'EZDXF',
override: dict = None, dxfattribs: dict = None): ...
def add_angular_dim_2l(self, base, line1, line2, dimstyle: str = 'EZDXF',
override: dict = None, dxfattribs: dict = None): ...
def add_diameter_dim(self, center, radius: float, angle: float = 0,
dimstyle: str = 'EZDXF', override: dict = None,
dxfattribs: dict = None): ...Usage examples:
from ezdxf.math import Vec3
import math
# Basic entities
line = msp.add_line((0, 0), (10, 10))
circle = msp.add_circle((5, 5), 3)
arc = msp.add_arc((0, 0), 5, 0, 90)
# Text with attributes
text = msp.add_text("Hello World", dxfattribs={
'height': 2.5,
'color': 1, # Red
'layer': 'TEXT'
})
# Polyline with multiple points
points = [(0, 0), (10, 0), (10, 10), (0, 10)]
lwpoly = msp.add_lwpolyline(points, dxfattribs={'layer': 'POLYLINES'})
lwpoly.close() # Close the polyline
# Spline curve
control_points = [Vec3(0, 0), Vec3(2, 4), Vec3(4, 0), Vec3(6, -2)]
spline = msp.add_spline(control_points, degree=3)
# Block insertion with scaling and rotation
insert = msp.add_insert('MY_BLOCK', insert=(20, 20), dxfattribs={
'xscale': 2.0,
'yscale': 2.0,
'rotation': 45
})Management of multiple layouts in a document.
class Layouts:
"""Collection of all layouts in a document"""
def __len__(self) -> int:
"""Number of layouts"""
def __iter__(self):
"""Iterate over all layouts"""
def __contains__(self, name: str) -> bool:
"""Check if layout exists"""
def __getitem__(self, name: str) -> Layout:
"""Get layout by name"""
def names(self) -> List[str]:
"""List of all layout names"""
def names_in_taborder(self) -> List[str]:
"""Layout names in tab display order"""
def get(self, name: str) -> Layout:
"""Get layout by name, returns None if not found"""
def new(self, name: str, dxfattribs: dict = None) -> Paperspace:
"""Create new paper space layout"""
def rename(self, old_name: str, new_name: str): ...
def delete(self, name: str): ...
def set_active_layout(self, name: str): ...
@property
def active_layout(self) -> Layout:
"""Currently active layout"""
@property
def modelspace(self) -> Modelspace:
"""Model space layout"""Usage examples:
# Access layouts collection
layouts = doc.layouts
# List all layouts
print(f"Available layouts: {layouts.names()}")
# Create new layout
plot_layout = layouts.new('Plot Sheet 1', dxfattribs={
'taborder': 1
})
# Switch active layout
layouts.set_active_layout('Plot Sheet 1')
current = layouts.active_layout
# Rename layout
layouts.rename('Plot Sheet 1', 'Main Plot')
# Check if layout exists
if 'Detail View' in layouts:
detail = layouts['Detail View']Creating and managing reusable block definitions.
class BlocksSection:
"""Collection of block definitions"""
def __len__(self) -> int: ...
def __iter__(self): ...
def __contains__(self, name: str) -> bool: ...
def __getitem__(self, name: str) -> BlockLayout: ...
def new(self, name: str, base_point = (0, 0), dxfattribs: dict = None) -> BlockLayout:
"""Create new block definition"""
def get(self, name: str) -> BlockLayout:
"""Get block by name, returns None if not found"""
def rename_block(self, old_name: str, new_name: str): ...
def delete_block(self, name: str, safe: bool = True): ...
def delete_all_blocks(self): ...
@property
def names(self) -> List[str]:
"""List of all block names"""Usage examples:
# Access blocks collection
blocks = doc.blocks
# Create new block definition
symbol_block = blocks.new('SYMBOL_1', base_point=(0, 0))
# Add entities to block
symbol_block.add_circle((0, 0), 1)
symbol_block.add_line((-1, 0), (1, 0))
symbol_block.add_line((0, -1), (0, 1))
# Use block in layout
msp.add_insert('SYMBOL_1', insert=(10, 10))
# List all blocks
print(f"Available blocks: {blocks.names}")
# Check block usage before deletion
if 'OLD_SYMBOL' in blocks:
try:
blocks.delete_block('OLD_SYMBOL', safe=True)
except ezdxf.DXFBlockInUseError:
print("Block is still referenced")Advanced entity selection and filtering capabilities.
class EntityQuery:
"""Result of layout.query() operations"""
def __len__(self) -> int: ...
def __iter__(self): ...
def __getitem__(self, index): ...
def extend(self, entities): ...
def filter(self, predicate) -> 'EntityQuery': ...
def query(self, query: str) -> 'EntityQuery': ...
@property
def first(self):
"""First entity or None"""
@property
def last(self):
"""Last entity or None"""Query syntax examples:
# Basic entity type queries
lines = msp.query('LINE')
circles = msp.query('CIRCLE')
all_entities = msp.query('*')
# Attribute-based queries
red_entities = msp.query('*[color==1]')
layer0_lines = msp.query('LINE[layer=="0"]')
thick_lines = msp.query('LINE[lineweight>50]')
# Complex queries with multiple conditions
complex_query = msp.query('CIRCLE[color==1][layer=="SYMBOLS"][radius>=5.0]')
# Combine queries
lines_and_arcs = msp.query('LINE ARC')
geometric_entities = msp.query('LINE CIRCLE ARC ELLIPSE')
# Use query results
for entity in msp.query('TEXT'):
if entity.dxf.height < 2.0:
entity.dxf.height = 2.0
# Filter query results further
large_circles = msp.query('CIRCLE').filter(lambda e: e.dxf.radius > 10)Layout organization and relationships:
class Drawing:
"""Main document class"""
def modelspace(self) -> Modelspace:
"""Get model space layout"""
def layout(self, name: str = None) -> Layout:
"""Get layout by name (active layout if name is None)"""
def new_layout(self, name: str, dxfattribs: dict = None) -> Paperspace:
"""Create new paper space layout"""
@property
def layouts(self) -> Layouts:
"""Layouts collection"""
@property
def blocks(self) -> BlocksSection:
"""Block definitions collection"""Usage examples:
import ezdxf
# Document with layouts
doc = ezdxf.new('R2018', setup=True)
# Model space for 3D geometry
msp = doc.modelspace()
msp.add_line((0, 0, 0), (100, 100, 50))
# Paper space for plotting
psp1 = doc.new_layout('Sheet 1')
psp1.add_text('Title: My Drawing', dxfattribs={'height': 5})
# Block for reusable content
title_block = doc.blocks.new('TITLE_BLOCK')
title_block.add_rectangle((0, 0), 100, 20)
title_block.add_text('Company Name', dxfattribs={'height': 3})
# Use block in paper space
psp1.add_insert('TITLE_BLOCK', insert=(0, 0))
# Save document
doc.saveas('drawing_with_layouts.dxf')Install with Tessl CLI
npx tessl i tessl/pypi-ezdxf