PtablePtableThe Graph Digitizer is a web-based tool for extracting performance data from PDF images of aircraft flight manuals and other technical documents. It supports three primary workflows:
Ptable structures compatible with the POH Performance aircraft performance calculation engine.The digitizer runs entirely in the browser with no server-side processing required.
The digitizer is designed to allow you to digitize all the graphs and tables in a single POH PDF. In fact, the output file contains a copy of the entire PDF, making it rather large, so it's counterproductive to do one graph or table per output file.
The output file should be archived after the data is extracted into Ptables, as it documents the sampling accuracy. This allows you to adjust the grid calibration or samples if errors are found later, or add more tables or graphs.
A POH can be digitized in the Digitizer alone, or by an AI agent working in the code base together with the Digitizer. Both end in the same place: a checked project file (.ppdig) in digitized/<appId>/, whose Ptables a developer exports into the model.
The Digitizer alone suits volunteers who don't work in the code base. It needs only the hosted Digitizer, and your own Anthropic API key if you auto-sample.
.ppdig file to a developer, with a note of anything you weren't sure of.Developers, when you receive a volunteer's project:
ppdig check on it and fix what it reports.Ptables, which make <appId>.ptables model=<modelId> lists. The volunteer chooses data paths from the reference model's Ptables, which can differ from those of the model you put the data in, and a path typed by hand may not be one the model reads. Without a reference model, auto-sampling suggests data paths from a short list of common ones. Correct them in the Digitizer.ppdigCompare.js to confirm that the model matches the project, and commit the .ppdig with the model.An agent with the Digitizer suits developers. The agent reads the code base, so it takes the data paths, keys, units and table layouts from a model already in the app, and lists that model's tables the POH has nothing for. It transcribes the tables, builds the project with the graphs calibrated and sampled, and compares the model with the project; you check its graphs and tables in the Digitizer. They show Unreviewed in the Project panel until you open them, and View Ptable warns you while any remain. See Extracting POH Data with an AI Agent.
The digitizer can be found at https://pohperformance.com/developer/digitizer/.
The digitizer user interface is organized into four vertical panels. From left to right:
Ptable constructor object.The Digitizer can find a POH's graphs and tables and sample them for you to check. It offers to when you load a PDF into an empty project, and Auto-sample Graphs in the Project panel starts it at any time. It needs your Anthropic API key, which stays in your browser.
79-81, 85, or click Choose pages… to choose them from the page thumbnails: click a page to choose it, ⌘-click (Ctrl-click on Windows) to add or remove one, and Shift-click to choose every page between. If the PDF has a table of contents, Show TOC lists it, and Select beside an entry chooses that section's pages.Ptable it feeds, and samples it with that Ptable's input and output keys; without one, it suggests data paths from a short list of common ones. The estimate shows what sampling them costs.The graph's status says how it ended:
A table is saved once for each kind of result, such as a cruise table's power, TAS and fuel flow, each with the same inputs. A table printed with a group of columns for each value of an input, such as a group for each altitude, is still one table for each kind of result, with that input taken from the group headings. So is a table printed in two halves side by side, with its input taken from a column of each half, and a table laid out across, with a case in each column. Claude leaves a table whose inputs are printed as ranges, such as 10,000 to 22,000 ft, for you to enter. The separators sit on the table's printed rules, or in the gaps between words where there are none; one Claude places by eye moves to the nearest. A cell the page's OCR leaves empty is read again on its own, which finds most numbers it missed, such as one alone in a large ruled box. Its values are the OCR's except where Claude corrected one, and every correction is listed with the row it's in and what the OCR read. An input printed once for a block of rows, such as RPM, is carried down the block. Before a table is saved, every value must be a number and no two rows may have the same inputs; where a column doesn't run smoothly, as a misread digit usually shows, Claude has to check it on the page first, and what it confirms is listed too. The table opens with the page's OCR, region and separators, so you can move a separator, drag a cell or OCR it again as you would on a table you set up yourself.
A page's graphs and tables are done in one conversation, so a chart's panels agree with each other. A panel of a chosen chart that the survey missed is digitized too, unless you unchecked it. Across panels, a reference scale that carries a value from one panel to the next must count it from the same line in each, and the Digitizer warns when they don't. The guide lines of a tandem adjustment panel take their parameter from their samples, so check those against the printed values.
Claude's work on a page grows with what it has to look at, and each look resends the conversation, so a page costs about $2 with Claude Opus and stops at $6 or 40 requests, keeping what was saved.
Every graph starts out marked Unreviewed in the Project panel. A bar above the graph counts what's left and its Next button opens the next one: the graphs with no samples first, then those with notes, keeping the items of one Ptable together. Opening an item clears its mark, whether you use Next or the Project panel. An item that only came up by itself, such as when a project loads, stays unreviewed.
For the open graph, the bar shows its notes and the worst distance of its samples from the ink when they were placed, in the output's units as well as pixels, because on a nearly flat curve a pixel can be many feet. The notes stay until you dismiss them.
While any item is unreviewed, View Ptable warns you and names them, and a combined Ptable isn't reviewed until all its items are. Save the project to record what you've reviewed.
Ptables suggest each item's data path, input and output keys, as the model in the app names them. Only their shape is used, never their values, which come from another POH. The choice is saved with the project.Fig 5-3, p. 5-9. It's exported, with the name, as a comment at the top of the Ptable.acData Ptable the data feeds, such as tko.obstacleTbl. ppdigCompare.js uses it to compare the project with a model. With a reference model, the field suggests its Ptables and shows the chosen one's inputs and output, with the app's units in brackets, and warns when the reference model has no such Ptable.Digitizing a graph has five major steps:
Grid calibration adjusts the grid points to align with the grid displayed in the graph image. Many older POH documents and maps have been printed and scanned multiple times, adding skew and other non-linearities with each pass. Without calibration, the digitizer cannot convert mouse clicks into accurate performance data. Once calibrated, the digitizer uses each sample's image coordinates to determine the distances to the nearest grid points and, from those, calculates the sample's graph-axis values.
NOTE: Accurately aligning the displayed grid with the image grid is key to accurate sampling.
Each grid point is adjustable by clicking it, then dragging it or using the arrow keys. Once adjusted, the point becomes anchored and cannot be moved by other adjustments. These anchors are highlighted by a yellow ring. If you subsequently want to remove the anchoring, select the point and press the Delete key. The corner points are always treated as anchors, and their positions are initially set by the axis points. However, you may move them as desired to align them accurately with the grid.
The points you move by hand, together with the four corners, are primary anchors: they are fixed in both directions and are highlighted by a yellow ring. When you anchor a point, the digitizer runs a horizontal and a vertical line of secondary anchors through it. Each of these lines extends until it reaches another primary anchor or an edge of the grid — it runs straight through any secondary anchors it crosses along the way, stopping only at a primary or an edge.
Secondary anchors are pinned in a single direction — the one their line holds steady. A vertical line of secondaries is pinned only horizontally, and a horizontal line only vertically. This lets a later anchor still adjust the grid across an existing secondary line: a vertical line of secondaries will hold its horizontal position while sliding vertically to follow a new horizontal anchor, and vice versa. Where a horizontal and a vertical secondary line cross, that crossing point ends up pinned in both directions. The grid's edge points are always pinned in both directions, at their interpolated position between the corners and any anchors on that edge.
The order in which you create anchors matters. A new anchor's lines interpolate between the anchors already in place, so moving a point never disturbs points already tied to an earlier anchor's line. All other grid points adjust linearly to follow the nearest anchors on each side.
Because the order of anchor creation matters, the following technique is suggested:
In some cases, you may want to delete previously defined anchors by selecting and pressing the delete key. You can reset all the anchors by pressing Init Grid again.
When you are finished, the grid points should lie directly over each grid intersection, and the lines between them should bisect the image grid lines. Click Hide next to the Init Grid button to hide the grid. Sampling is disabled while the grid is displayed.
Once the grid is initialized and displayed, click Auto-Adjust Grid to have the digitizer calibrate it for you. In short, it ignores the plotted curves, arrows, and labels, finds the real image grid lines near each point, and snaps the grid onto them — following the same corners-then-edges-then-interior technique described above, while leaving any points you've already adjusted by hand exactly where you put them.
It is conservative and will give up rather than guess when the image is too degraded — too many intersections it can't trust, or too much of the grid would have to move. When it gives up it leaves the grid unchanged so you can calibrate by hand.
On success the anchored points behave exactly like manual edits (yellow rings), so you can fine-tune or delete any of them afterward, or press Init Grid to start over. Always review the result — especially the points nearest the graphed curves, where misalignment matters most.
Tip: very fine grids make this hard — the accuracy target is half a grid-line width, which can be sub-pixel on a heavily scanned chart. If auto-adjust struggles, re-initialize with a coarser axis increment; the alignment is just as accurate for sampling and far more robust.
Each graphed curve is series. If a graph has only one curve, then there is only one series, one input, and one output. The input may be either the X or Y axis, and the output would be the opposite axis value. By default, the X axis is the input and the Y axis is the output. Clicking Use Y as input reverses that.
When the series has more than one curve, set the number of inputs to two. The first input is the parameter value, the second input is the X or Y axis value. When sampling a curve, you'll have to set the parameter value manually in the value panel.
The input and output names are used as Ptable keys. The keys are used to extract particular input values and set output values in the object that is passed to Ptable.interpolate(). The keys and their units can be app-specific, but here's a list of keys used by most POH Performance apps and their typical default units:
densityAltitude (ft)pressureAltitude (ft)distance (for routes: nm)runwayDistance (nm)weight (lb)arm (in)fuel (gal)fuelWeight (lb)fuelFlow (pph)ias, cas, tas (kt)windspeed (kt)headwind (kt)climbRate (fpm)climbGradient (fpnm)oat, ioat, isa (dC)pressure (psi)oxygenPressure (psi)time (min)If input values are in units different from the default, you may set a different unit string so the Ptable performs the conversion automatically. For example, if a graphed input or output airspeed is in mph when the app's default is kt, simply set the input units to mph to set up the conversion.
PtableA POH often splits one Ptable across several graphs or tables: a table per flap setting, or a table continued on the next page. Give them the same Data path in the Source Image card, and they combine into one.
If an item's rows don't carry an input of the Ptable, put its value in Fixed, such as flaps=up, or pressureAltitude=5000 ft with units. Use the model's keys and values. Then View Ptable has a Combined tab with the whole Ptable. It won't show one with items that disagree, and lists the reasons instead.
A Ptable has several ways to handle input range errors. You can adjust then with the input limit selector. Possible values are:
errorclampclampLoclampHimatch'match' interpType on the input, not as a limit.offsetPtable. offset is used for simple tandem adjustment graphs (e.g., weight, headwind, IAS to CAS) where lines may not cover the entire input range. This allows exceedances to parallel the upper or lower line. See Tandem graphs.Once the input(s) and output are set up, you may begin sampling the first curve by clicking Start Digitizing. You may then set samples along the curve by clicking. Sample values will appear in the current row in the value panel. You may add samples out of order, since the digitizer assumes curves are well-behaved and each input value corresponds to a unique output value. Samples are automatically sorted in input value order. You may change the sort direction in the value panel. Lines will appear between points to help you judge interpolation error. Each curve will have a unique color, so you can distinguish them.
You can edit sample values at any time by clicking and then dragging or moving the sample with the arrow keys. To remove a sample, select it and press the Delete key. It may be convenient to click Stop Digitizing before selecting a sample, so you don't inadvertently create a new sample. You may also directly edit or delete values in the value panel (see below).
On 2-input graphs, you will have to manually set the first input value for the curve by editing the value field in the value panel. When a series is complete, click New Series in the value panel to create sample value rows for a new curve. Enter the new value for the first input manually.
Ptable objects can project a spline between samples. The type of spline used ensures that the curve has a continuous first derivative and does not fall outside the rectangle defined by the two points. This restricts the use of splines to well-behaved curves without severe changes in slope. Fortunately, most curves seen in a POH are well-behaved. Clicking Use spline interpolation will cause the lines between samples in each series to be splined using the Ptable algorithm. It will also specify spline interpolation in the final Ptable output.
When you are done sampling a series, look at the captured values in the value panel. Samples on grid lines should have the grid line value. You can click a sample row in the value panel to highlight the sample and adjust it, if required. If the sample appears in the correct position, but the value is off, then check that the grid is properly aligned near the sample by clicking the Show button in the Grid Calibration card. Click Hide when done to show the samples again.
You can readjust the grid at any time. The existing samples will retain their physical position on the image; however, the sample values in the value panel will be adjusted to match any changes in the grid.
The last card in the graph panel lets you add verification constraints on the output value of each sample. Samples that violate the constraints will be highlighted in red in the value panel. There are two types of constraints: value and slope. The value constraint lets you verify that the output value increases or decreases monotonically as the input value increases. Similarly, the slope constraint lets you verify that the slope between each pair of samples increases or decreases monotonically as the input value increases. This lets you verify that concave or convex curves remain concave or convex in the sample output.
POH graphs are designed to be read by humans, who have a limited ability to interpolate and extract values as offset from a grid. This limits their absolute accuracy. The goal is to do as well or better than a human could. Here are some hints:
Over-sampling adds noise to the data. Imagine sampling a straight line with 10 samples instead of two. The slope between each pair of samples can't be constant due to the constraints of accuracy and rounding. Similarly, if you over-sample, gently curving lines, you will probably cause unwanted slope verification failures. Lastly, over-sampling makes it harder to manually verify the output values.
Many POH graphs are arranged in tandem on the same set of grid lines. The output of one graph flows into the next either horizontally or vertically. A typical example is a takeoff graph with a first graph that computes ground roll at the given temperature and altitude, whose output flows into the second graph that adjusts the ground roll for weight, followed by a third graph that adjusts the ground roll for head or tailwind.
In many cases, the user is expected to use the output of the first graph to interpolate between two adjustment lines in the next graph. In this case, the parameter value in each series in the adjustment graph is the input value of the first sample. In graphs that are to the right of the previous graph, that's the leftmost sample. In this case, clicking Use leftmost Y value as parameter in the Input and Output Configuration card will automatically synchronize the series parameter with the leftmost sample in each series.
In graphs that are beneath the previous graph, the X value of the uppermost sample forms the series parameter value. In this case, click Use Y as input, which changes the box to Use uppermost X value as parameter, and check it to synchronize the series parameter with the uppermost sample in each series. The parameters follow whenever the samples, the grid or Use Y as input change.
Always check that the start of the adjustment lines (the leftmost or uppermost samples) covers all valid output values from the previous graph. If they do not, use offset in the error handling for the adjustment input. That will allow the interpolation to parallel the outermost line when the input value exceeds the adjustment range instead of producing an error.
Digitizing a table has four major steps:
The digitizer uses any OCR text embedded in the PDF. If no text is supplied, the digitizer has a built-in OCR engine. The OCR is adequate for many scanned text images, but in some cases it may be useful to prepare the PDF using more professional OCR engines like Adobe Acrobat Pro.
See Setting up inputs and the output above. However, tables often have 2 or more inputs.
If the data you're extracting is not organized into a formal table with data grouped in columns or rows, you can simply drag individual numbers or strings to value panel cells. However, if the data is organized into a table, you can outline groups of columnar data so that they can be dragged as a group into rows of cells in the value panel. To do that:
When finished, the cell boundaries in the data region should surround groups of columnar data that can be dragged as a group into sequential output cells in the value panel.
If you've set up data regions, you can drag groups of output data directly to the output column in the value panel. You'll be able to see the values you're dragging in the drag image. Once dropped on an output cell, the grouped data will create the necessary rows and populate the output values. Similarly, you can drop the values associated with the final input to the rightmost input column to populate those. You'll have to populate the series parameter with the individual series values by dragging them from the image.
PtableWhen you're done digitizing a table or graph, you can export the data by clicking View Ptable in the value panel. This will display a pop-up page with a JavaScript object suitable for passing to a Ptable constructor, headed by a comment with the item's name and source. The object can be copied by clicking Copy to Clipboard and then pasted into a JavaScript file as appropriate.
Click Save Project in the project panel to download the project file. It will normally be placed in your browser downloads directory. The file encapsulates the PDF and the sampled graphs and tables. The file name is derived from the project name.
The project file can hold all the digitized graphs and tables associated PDF. It can be saved with each aircraft app and used to verify how the data in each POH was captured.
PtableYou may verify the samples in an existing Ptable that was digitized using other digitizers by importing them. In the case of a graph, you must first initialize and calibrate the grid in order for this to make sense. After that, click Import Ptable, which will display a pop-up with a text input area where you can paste the text of a Ptable constructor object. Clicking Done will complete the import. For graphs, the series and sample line will appear on the grid according to their value.
| Problem | Solution |
|---|---|
| PDF won't load | Reduce PDF size by extracting relevant pages; check that the file is valid PDF |
| OCR text is garbled | Improve scan quality; OCR the document using better tools like Adobe Acrobat Pro; crop the image to just the table; try manual entry instead |
| Exported Ptable won't import | Check Ptable object structure structure; verify all required fields (title, inputs, output, a); validate syntax |
| Inaccurate sample points | Check grid alignment and adjust grid points; reinitialize the grid and realign |
| App freezes on large PDF | PDFs >50MB may be slow; try cropping to individual pages; use a faster device |