This is an add-on for drawing tables build from DXF primitives.

This add-on was created for porting dxfwrite projects to ezdxf and was not officially documented for ezdxf versions prior the 1.0 release. For the 1.0 version of ezdxf, this class was added as an officially documented add-on because full support for the ACAD_TABLE entity is very unlikely due to the enormous complexity for both the entity itself, and for the required infrastructure and also the lack of a usable documentation to implement all that features.


This add-on is not related to the ACAD_TABLE entity at all and and does not create ACAD_TABLE entities!

The table cells can contain multi-line text or BLOCK references. You can create your own cell types by extending the CustomCell class. The cells are addressed by zero-based row and column indices. A table cell can span over multiple columns and/or rows.

A TextCell can contain multi-line text with an arbitrary rotation angle or letters stacked from top to bottom. The MTextSurrogate add-on is used to create multi-line text compatible to DXF version R12.

A BlockCell contains block references (INSERT entities), if the block definition contains attribute definitions as ATTDEF entities, these attributes can be added automatically to the block reference as ATTRIB entities.


The DXF format does not support clipping boxes ot paths, therefore the render method of any cell can render beyond the borders of the cell!


Set up a new DXF document:

import ezdxf
from ezdxf.enums import MTextEntityAlignment
from ezdxf.addons import TablePainter

doc ="R2000")  # required for lineweight support
doc.header["$LWDISPLAY"] = 1  # show lineweights
doc.styles.add("HEAD", font="OpenSans-ExtraBold.ttf")
doc.styles.add("CELL", font="OpenSans-Regular.ttf")

Create a new TablePainter object with four rows and four columns, the insert location is the default render location but can be overriden in the render() method:

table = TablePainter(
    insert=(0, 0), nrows=4, ncols=4, cell_width=6.0, cell_height=2.0

Create a new CellStyle object for the table-header called “head”:


Redefine the default CellStyle for the content cells:

# reset default cell style
default_style = table.get_cell_style("default")
default_style.text_style = "CELL"
default_style.char_height = 0.5
default_style.align = MTextEntityAlignment.BOTTOM_LEFT

Set the table-header content:

for col in range(4):
    table.text_cell(0, col, f"Head[{col}]", style="head")

Set the cell content:

for row in range(1, 4):
    for col in range(4):
        # cell style is "default"
        table.text_cell(row, col, f"Cell[{row}, {col}]")

Add a red frame around the table-header:

# new cell style is required
red_frame = table.new_cell_style("red-frame")
red_borderline = table.new_border_style(color=ezdxf.colors.RED, lineweight=35)
# set the red borderline style for all cell borders
# create the frame object
table.frame(0, 0, 4, style="red-frame")

Render the table into the modelspace and export the DXF file:

# render the table, shifting the left-bottom of the table to the origin:
table.render(doc.modelspace(), insert=(0, table.table_height))

th = table.table_height
tw = table.table_width
doc.set_modelspace_vport(height=th * 1.5, center=(tw/2, th/2))

See also


class ezdxf.addons.tablepainter.TablePainter(insert: UVec, nrows: int, ncols: int, cell_width=DEFAULT_CELL_WIDTH, cell_height=DEFAULT_CELL_HEIGHT, default_grid=True)

The TablePainter class renders tables build from DXF primitives.

The TablePainter instance contains all the data cells.

  • insert – insert location as or UVec

  • nrows – row count

  • ncols – column count

  • cell_width – default cell width in drawing units

  • cell_height – default cell height in drawing units

  • default_grid – draw a grid of solid lines if True, otherwise draw only explicit defined borders, the default grid has a priority of 50.

bg_layer_name: str

background layer name, layer for the background SOLID entities, default is “TABLEBACKGROUND”

fg_layer_name: str

foreground layer name, layer for the cell content, default is “TABLECONTENT”

grid_layer_name: str

table grid layer name, layer for the cell border lines, default is “TABLEGRID”

property table_width: float

Returns the total table width.

property table_height: float

Returns the total table height.

set_col_width(index: int, value: float)

Set column width in drawing units of the given column index.

  • index – zero based column index

  • value – new column width in drawing units

set_row_height(index: int, value: float)

Set row height in drawing units of the given row index.

  • index – zero based row index

  • value – new row height in drawing units

text_cell(row: int, col: int, text: str, span: tuple[int, int] = (1, 1), style='default') TextCell

Factory method to create a new text cell at location (row, col), with text as content, the text can be a line breaks '\n'. The final cell can spread over several cells defined by the argument span.

block_cell(row: int, col: int, blockdef: BlockLayout, span: tuple[int, int] = (1, 1), attribs=None, style='default') BlockCell

Factory method to Create a new block cell at position (row, col).

Content is a block reference inserted by an INSERT entity, attributes will be added if the block definition contains ATTDEF. Assignments are defined by attribs-key to attdef-tag association.

Example: attribs = {‘num’: 1} if an ATTDEF with tag==’num’ in the block definition exists, an attrib with text=str(1) will be created and added to the insert entity.

The cell spans over ‘span’ cells and has the cell style with the name ‘style’.

set_cell(row: int, col: int, cell: T) T

Insert a cell at position (row, col).

get_cell(row: int, col: int) Cell

Get cell at location (row, col).

new_cell_style(name: str, **kwargs) CellStyle

Factory method to create a new CellStyle object, overwrites an already existing cell style.

  • name – style name as string

  • kwargs – see attributes of class CellStyle

get_cell_style(name: str) CellStyle

Get cell style by name.

static new_border_style(color: int = const.BYLAYER, status=True, priority: int = 100, linetype: str = 'BYLAYER', lineweight: int = const.LINEWEIGHT_BYLAYER) BorderStyle

Factory method to create a new border style.

  • statusTrue for visible, False for invisible

  • colorAutoCAD Color Index (ACI)

  • linetype – linetype name, default is “BYLAYER”

  • lineweight – lineweight as int, default is by layer

  • priority – drawing priority, higher priorities cover lower priorities

frame(row: int, col: int, width: int = 1, height: int = 1, style='default') Frame

Creates a frame around the give cell area, starting at (row, col) and covering width columns and height rows. The style argument is the name of a CellStyle.

render(layout: GenericLayoutType, insert: UVec | None = None)

Render table to layout.


class ezdxf.addons.tablepainter.Cell

Abstract base class for table cells.


class ezdxf.addons.tablepainter.TextCell

Implements a cell type containing a multi-line text. Uses the MTextSurrogate add-on to render the multi-line text, therefore the content of these cells is compatible to DXF R12.


Use the factory method TablePainter.text_cell() to instantiate text cells.


class ezdxf.addons.tablepainter.BlockCell(table: TablePainter, blockdef: BlockLayout, style='default', attribs=None, span: tuple[int, int] = (1, 1))

Implements a cell type containing a block reference.

  • table – table object

  • blockdefezdxf.layouts.BlockLayout instance

  • attribs – BLOCK attributes as (tag, value) dictionary

  • style – cell style name as string

  • span – tuple(rows, cols) area of cells to cover

Implements a cell type containing a block reference.


Use the factory method TablePainter.block_cell() to instantiate block cells.


class ezdxf.addons.tablepainter.CustomCell

Base class to implement custom cells. Overwrite the render() method to render the cell. The custom cell type has to be instantiated by the user and added to the table by the TablePainter.set_cell() method.

render(layout: GenericLayoutType, coords: Sequence[float], layer: str)

Renders the cell content into the given layout.

The render space is defined by the argument coords which is a tuple of 4 float values in the order: left, right, top, bottom. These values are layout coordinates in drawing units. The DXF format does not support clipping boxes, therefore the render method can render beyond these borders!


class ezdxf.addons.tablepainter.CellStyle(data: dict[str, Any] | None = None)

Cell style object.


Always instantiate new styles by the factory method: TablePainter.new_cell_style()

text_style: str

Textstyle name as string, ignored by BlockCell

char_height: float

text height in drawing units, ignored by BlockCell

line_spacing: float

line spacing in percent, distance of line base points = char_height * line_spacing, ignored by BlockCell

scale_x: float

text stretching factor (width factor) or block reference x-scaling factor

scale_y: float

block reference y-scaling factor, ignored by TextCell

text_color: int

AutoCAD Color Index (ACI) for text, ignored by BlockCell

rotation: float

text or block rotation in degrees

stacked: bool

Stacks letters of TextCell instances from top to bottom without rotating the characters if True, ignored by BlockCell

align: MTextEntityAlignment

text and block alignment, see ezdxf.enums.MTextEntityAlignment

margin_x: float

left and right cell margin in drawing units

margin_y: float

top and bottom cell margin in drawing units

bg_color: int

cell background color as AutoCAD Color Index (ACI), ignored by BlockCell

left: BorderStyle

left cell border style

top: BorderStyle

top cell border style

right: BorderStyle

right cell border style

bottom: BorderStyle

bottom cell border style

set_border_status(left=True, right=True, top=True, bottom=True)

Set status of all cell borders at once.

set_border_style(style: BorderStyle, left=True, right=True, top=True, bottom=True)

Set border styles of all cell borders at once.

static get_default_border_style() BorderStyle


class ezdxf.addons.tablepainter.BorderStyle(status: bool = DEFAULT_BORDER_STATUS, color: int = DEFAULT_BORDER_COLOR, linetype: str = DEFAULT_BORDER_LINETYPE, lineweight=const.LINEWEIGHT_BYLAYER, priority: int = DEFAULT_BORDER_PRIORITY)

Border style class.


Always instantiate new border styles by the factory method: TablePainter.new_border_style()

status: bool

border status, True for visible, False for hidden

color: int

AutoCAD Color Index (ACI)

linetype: str

linetype name as string, default is “BYLAYER”

lineweight: int

lineweight as int, default is by layer

priority: int

drawing priority, higher values cover lower values