Skip to main content

crop-parsed-elements

Use when cropping figures, charts, tables, or other elements out of PDFs parsed with ai_parse_document (bbox coord), when extracting chart data from parsed documents or sending chart images to a vision model, or when crops come out misaligned or chart insights have wrong titles, units, or series names.

Source facts

Repository
databricks-solutions/advance-document-processing
Last source activity
November 3, 2026 at 05:14
Detected SKILL.md language
English
Stars
2
Forks
5

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
2 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
crop-parsed-elements
description
Use when cropping figures, charts, tables, or other elements out of PDFs parsed with ai_parse_document (bbox coord), when extracting chart data from parsed documents or sending chart images to a vision model, or when crops come out misaligned or chart insights have wrong titles, units, or series names.
# Cropping ai_parse_document Elements (and Getting Chart Data) ## Overview Two facts decide everything: **bbox coords are pixels of the page rendered at 200 DPI**, and **a crop alone loses the chart's title, units, and often its legend** — those are separate elements on the page. Without them a vision model invents the metric and drops the scale (observed: "Quarterly Revenue, $" for "Advertising Revenue by User Geography, In Millions"). For function syntax, use the `databricks-ai-functions` skill. ## First: do you need to crop at all? | Parse option `descriptionElementTypes` | Chart figure `content` | |---|---| | default `'*'` or includes `'figure'` | **Structured chart JSON** (series × categories, values exact on tested decks) + a prose `description` | | `''` | Raw label text only (`"$50,082\n$46,783…"`) | - Need chart data and can (re)parse with figures on → read figure `content` JSON (`builtin_chart_data`), add page context, done. No crop, no vision call. - Crop + vision model when: the corpus was parsed with `''` and re-parsing costs more than vision calls on figures only; you need your own schema or domain prompt; you need the image itself (review UI, OCR, audit); or built-in JSON is missing for a chart. - Either way, built-in JSON has `"title": "None"`, no units, and may name series `"Segment 1"` — always attach page context. ## Verified facts | | | |---|---| | `bbox[0].coord` | `[x0, y0, x1, y1]` int pixels, origin top-left, page rendered at **200 DPI** (px = PDF points × 200/72) | | Page image | Only with `imageOutputPath` (`pages[].image_uri`, same 200-DPI size); otherwise `null` | | Without page images | Render with `pypdfium2` at `scale=200/72` — aligns pixel-exact with the parser's image | | Page | `bbox[0].page_id` = 0-based PDF page index = `pages[].id` (not array position in chunked parses) | | Box tightness | Boxes touch content and move 2–3 px between parses — pad ~20 px | | Context | Title/units are `title` + short `text` above the chart; legends may be a `footnote` beside it | ## Implementation `scripts/crop_elements.py` (unit-tested). Install `pypdfium2` (Apache/BSD; PyMuPDF is AGPL), copy the file's contents **unchanged** into one cell, then: ```python %pip install pypdfium2 # own cell, first els = elements_to_crop(spark.table("<cat>.<sch>.<parsed_table>"), parsed_col="parsed", doc_id_col="path") display(els.select("doc_id", "page_id", "builtin_chart_json", "context")) # built-in data + context crops = crop_elements(spark, els, out_dir="/Volumes/<cat>/<sch>/<vol>/crops") # doc_id = source PDF path crops.write.mode("overwrite").saveAsTable("<cat>.<sch>.element_crops") # status: ok | too_small | bad_page | pdf_not_found | bad_pdf insights = vision_insights(spark, spark.table("<cat>.<sch>.element_crops"), "<vision endpoint>") ``` `vision_insights` calls `ai_query(endpoint, prompt + context, files => crop, failOnError => false)` (verified with Claude endpoints). With `failOnError => false` the result is a struct with fields **`result`** and **`errorMessage`** (verified live) — not `response` / `error`. To embed with document text, use `splice_figure_text(elements, {element_id: insight})` so each chart stays in reading order. `elements_to_crop(..., types=("table",))` crops tables too. ## Common mistakes | Mistake | Fix | |---|---| | Treating coords as PDF points, 72-DPI pixels, or 0–1 | 200-DPI pixels; scale by `render_dpi / 200` | | Calibrating coords from PDF text blocks | Fails on scanned pages; the scale is a constant | | Sending only the crop (or only a `caption`) | Pass same-page title, units, and adjacent legend (`figure_context`) | | Ignoring built-in figure `content` / `description` | Check it first; parse with figures on if chart data is the goal | | Parsing with `descriptionElementTypes: ''` then wanting chart data | That setting drops the chart JSON; re-parse or crop + vision | | Mapping page by array position | Use `bbox.page_id` | | No padding / no size floor | Pad ~20 px; skip tiny figures (logos) with `min_side_px` | | PyMuPDF in a customer project | AGPL — use `pypdfium2` | | Embedding vision text *and* running `ai_prep_search` on the original `parsed` | Built-in chart JSON gets embedded too; pick one representation per chart |
View on GitHub