ODF Chart Extraction#
ODF files (ODT, ODS, ODP) embed charts as sub-documents inside the ODF ZIP archive. Docling resolves the draw:object reference on a Frame element, reads the embedded content.xml, classifies the chart type, reconstructs the underlying data from the chart's internal local-table, and emits a PictureItem with structured tabular metadata — without any rendering step or VLM inference.
All chart extraction logic lives in docling/backend/opendocument_backend.py, introduced in PR #3480.
Entry Points#
Chart extraction is triggered at two points during ODF traversal:
- Inside
_add_odf_paragraph()— called when aParagraphelement contains frames with embedded objects (common in ODT). - Inside
_add_odf_child()— called for top-levelFrameelements during document walk. - Inside
OdpDocumentBackend._walk_slide_frame()— called per slide frame during ODP presentation conversion.
In all cases the call is _add_odf_charts(doc, element, parent, content_layer, odf_obj).
Extraction Pipeline#
1. Frame Discovery — _add_odf_charts() #
Collects Frame objects from the element (either the element itself, or via get_frames() / child iteration), then calls _chart_data_from_frame() for each.
2. draw:object Resolution — _chart_data_from_frame() #
Iterates the frame's children looking for a child whose tag is "draw:object" and reads its xlink:href attribute . The href is an internal archive path such as ./Object 1.
The embedded content path is constructed by _embedded_odf_content_path():
{href stripped of './' and trailing '/'}/content.xml
→ e.g. "Object 1/content.xml"
odf_obj.get_part() is then called to read the embedded XML from the ODF archive . If any exception occurs (missing or malformed embedded object), the function returns None silently — no exception propagates to the caller.
3. Chart Classification — _odf_chart_classification() #
Searches the content XML for chart:chart elements first, then falls back to chart:series elements, reading the chart:class attribute. The mapping table _ODF_CHART_CLASS_TO_PICTURE_CLASSIFICATION covers:
chart:class | PictureClassificationLabel |
|---|---|
chart:bar | BAR_CHART |
chart:line | LINE_CHART |
chart:circle / chart:pie | PIE_CHART |
chart:scatter | SCATTER_PLOT |
| (anything else) | OTHER_CHART |
4. Data Reconstruction — _table_data_from_odf() via local-table #
_chart_data_from_frame() scans the embedded content XML for table:table elements, filtering for the one named "local-table" — ODF's internal chart data table. The matching table is passed to _table_data_from_odf(), which:
- Calls
_find_true_data_bounds()to find the non-empty cell rectangle . - Iterates rows and cells within those bounds, skipping covered (merged) cells.
- Reads each cell's text value via
_odf_cell_text(). - Sets
column_header=Truefor row index 0. - Returns a
TableDatawith the full grid.
5. PictureItem Emission — _add_odf_charts() #
For each frame that yields a (TableData, PictureClassificationLabel) pair, a PictureItem is added to the document with:
PictureMeta(
classification=PictureClassificationMetaField(
predictions=[PictureClassificationPrediction(class_name=chart_classification)]
),
tabular_chart=TabularChartMetaField(chart_data=chart_data),
)
This is the same PictureMeta shape produced by the Excel and VLM-based chart extraction paths, giving downstream consumers a uniform interface regardless of document format.
ObjectReplacements Skipping#
When _add_odf_charts() finds charts in a frame, it signals that count back to the paragraph/frame handler. The image extraction step then skips any images whose href starts with ObjectReplacements/ — these are low-fidelity preview bitmaps that ODF embeds alongside each chart object and should not be double-emitted.
Exception Handling#
All calls to odf_obj.get_part() in _chart_data_from_frame() are wrapped in a bare except Exception: return None block . A missing or corrupted embedded chart object is silently dropped; the rest of document conversion continues unaffected.
Key Source Files#
| File | Role |
|---|---|
docling/backend/opendocument_backend.py | All ODF chart extraction logic |
_chart_data_from_frame() | Core: resolves draw:object, reads embedded XML, returns (TableData, label) |
_odf_chart_classification() | Maps chart:class → PictureClassificationLabel |
_add_odf_charts() | Collects frames, drives extraction, emits PictureItems |
_table_data_from_odf() | Converts local-table ODF table → TableData |
_embedded_odf_content_path() | Constructs archive path for embedded content.xml |