* [MRG] Create a new figure and test each plot type #127 - move `plot()` to `plotting.py` as `plot_pdf()` - modify plotting functions to return matplotlib figures - add `test_plotting.py` and baseline images - import `plot_pdf()` in `__init__` - update `cli.py` to use `plot_pdf()` - update advanced usage docs to reflect changes * Change matplotlib backend for image comparison tests * Update plotting and tests - use matplotlib rectangle instead of `cv2.rectangle` in `plot_contour()` - set matplotlib backend in `tests/__init__` - update contour plot baseline image - update `test_plotting` with more checks * Update plot tests and config - remove unnecessary asserts - update setup.cfg and makefile with `--mpl` * Add to * Add tolerance * remove text from baseline plots update plot tests with `remove_text` * Change method name, update docs and add pep8 * Update docs
This commit is contained in:
committed by
Vinayak Mehta
parent
79db6e3d1b
commit
c0e9235164
@@ -6,6 +6,7 @@ from click import HelpFormatter
|
||||
|
||||
from .__version__ import __version__
|
||||
from .io import read_pdf
|
||||
from .plotting import plot
|
||||
|
||||
|
||||
def _write_usage(self, prog, args='', prefix='Usage: '):
|
||||
|
||||
+8
-4
@@ -3,9 +3,11 @@
|
||||
import logging
|
||||
|
||||
import click
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from . import __version__
|
||||
from .io import read_pdf
|
||||
from .plotting import plot
|
||||
|
||||
|
||||
logger = logging.getLogger('camelot')
|
||||
@@ -81,7 +83,7 @@ def cli(ctx, *args, **kwargs):
|
||||
help='Number of times for erosion/dilation will be applied.')
|
||||
@click.option('-plot', '--plot_type',
|
||||
type=click.Choice(['text', 'table', 'contour', 'joint', 'line']),
|
||||
help='Plot geometry found on PDF page, for debugging.')
|
||||
help='Plot elements found on PDF page for visual debugging.')
|
||||
@click.argument('filepath', type=click.Path(exists=True))
|
||||
@pass_config
|
||||
def lattice(c, *args, **kwargs):
|
||||
@@ -107,7 +109,8 @@ def lattice(c, *args, **kwargs):
|
||||
click.echo('Found {} tables'.format(tables.n))
|
||||
if plot_type is not None:
|
||||
for table in tables:
|
||||
table.plot(plot_type)
|
||||
plot(table, plot_type=plot_type)
|
||||
plt.show()
|
||||
else:
|
||||
if output is None:
|
||||
raise click.UsageError('Please specify output file path using --output')
|
||||
@@ -128,7 +131,7 @@ def lattice(c, *args, **kwargs):
|
||||
' used to combine text horizontally, to generate columns.')
|
||||
@click.option('-plot', '--plot_type',
|
||||
type=click.Choice(['text', 'table']),
|
||||
help='Plot geometry found on PDF page for debugging.')
|
||||
help='Plot elements found on PDF page for visual debugging.')
|
||||
@click.argument('filepath', type=click.Path(exists=True))
|
||||
@pass_config
|
||||
def stream(c, *args, **kwargs):
|
||||
@@ -153,7 +156,8 @@ def stream(c, *args, **kwargs):
|
||||
click.echo('Found {} tables'.format(tables.n))
|
||||
if plot_type is not None:
|
||||
for table in tables:
|
||||
table.plot(plot_type)
|
||||
plot(table, plot_type=plot_type)
|
||||
plt.show()
|
||||
else:
|
||||
if output is None:
|
||||
raise click.UsageError('Please specify output file path using --output')
|
||||
|
||||
@@ -7,8 +7,6 @@ import tempfile
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
from .plotting import *
|
||||
|
||||
|
||||
class Cell(object):
|
||||
"""Defines a cell in a table with coordinates relative to a
|
||||
@@ -321,33 +319,6 @@ class Table(object):
|
||||
cell.hspan = True
|
||||
return self
|
||||
|
||||
def plot(self, geometry_type):
|
||||
"""Plot geometry found on PDF page based on geometry_type
|
||||
specified, useful for debugging and playing with different
|
||||
parameters to get the best output.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
geometry_type : str
|
||||
The geometry type for which a plot should be generated.
|
||||
Can be 'text', 'table', 'contour', 'joint', 'line'
|
||||
|
||||
"""
|
||||
if self.flavor == 'stream' and geometry_type in ['contour', 'joint', 'line']:
|
||||
raise NotImplementedError("{} cannot be plotted with flavor='stream'".format(
|
||||
geometry_type))
|
||||
|
||||
if geometry_type == 'text':
|
||||
plot_text(self._text)
|
||||
elif geometry_type == 'table':
|
||||
plot_table(self)
|
||||
elif geometry_type == 'contour':
|
||||
plot_contour(self._image)
|
||||
elif geometry_type == 'joint':
|
||||
plot_joint(self._image)
|
||||
elif geometry_type == 'line':
|
||||
plot_line(self._segments)
|
||||
|
||||
def to_csv(self, path, **kwargs):
|
||||
"""Writes Table to a comma-separated values (csv) file.
|
||||
|
||||
|
||||
@@ -141,9 +141,6 @@ class PDFHandler(object):
|
||||
-------
|
||||
tables : camelot.core.TableList
|
||||
List of tables found in PDF.
|
||||
geometry : camelot.core.GeometryList
|
||||
List of geometry objects (contours, lines, joints) found
|
||||
in PDF.
|
||||
|
||||
"""
|
||||
tables = []
|
||||
|
||||
+101
-24
@@ -1,15 +1,59 @@
|
||||
import cv2
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.patches as patches
|
||||
|
||||
|
||||
def plot(table, plot_type='text', filepath=None):
|
||||
"""Plot elements found on PDF page based on plot_type
|
||||
specified, useful for debugging and playing with different
|
||||
parameters to get the best output.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
table: Table
|
||||
A Camelot Table.
|
||||
plot_type : str, optional (default: 'text')
|
||||
{'text', 'table', 'contour', 'joint', 'line'}
|
||||
The element type for which a plot should be generated.
|
||||
filepath: str, optional (default: None)
|
||||
Absolute path for saving the generated plot.
|
||||
|
||||
Returns
|
||||
-------
|
||||
fig : matplotlib.fig.Figure
|
||||
|
||||
"""
|
||||
if table.flavor == 'stream' and plot_type in ['contour', 'joint', 'line']:
|
||||
raise NotImplementedError("{} cannot be plotted with flavor='stream'".format(
|
||||
plot_type))
|
||||
if plot_type == 'text':
|
||||
fig = plot_text(table._text)
|
||||
elif plot_type == 'table':
|
||||
fig = plot_table(table)
|
||||
elif plot_type == 'contour':
|
||||
fig = plot_contour(table._image)
|
||||
elif plot_type == 'joint':
|
||||
fig = plot_joint(table._image)
|
||||
elif plot_type == 'line':
|
||||
fig = plot_line(table._segments)
|
||||
if filepath:
|
||||
plt.savefig(filepath)
|
||||
return fig
|
||||
|
||||
|
||||
def plot_text(text):
|
||||
"""Generates a plot for all text present on the PDF page.
|
||||
"""Generates a plot for all text elements present
|
||||
on the PDF page.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
text : list
|
||||
|
||||
Returns
|
||||
-------
|
||||
fig : matplotlib.fig.Figure
|
||||
|
||||
"""
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot(111, aspect='equal')
|
||||
@@ -26,83 +70,116 @@ def plot_text(text):
|
||||
)
|
||||
ax.set_xlim(min(xs) - 10, max(xs) + 10)
|
||||
ax.set_ylim(min(ys) - 10, max(ys) + 10)
|
||||
plt.show()
|
||||
return fig
|
||||
|
||||
|
||||
def plot_table(table):
|
||||
"""Generates a plot for the table.
|
||||
"""Generates a plot for the detected tables
|
||||
on the PDF page.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
table : camelot.core.Table
|
||||
|
||||
Returns
|
||||
-------
|
||||
fig : matplotlib.fig.Figure
|
||||
|
||||
"""
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot(111, aspect='equal')
|
||||
for row in table.cells:
|
||||
for cell in row:
|
||||
if cell.left:
|
||||
plt.plot([cell.lb[0], cell.lt[0]],
|
||||
ax.plot([cell.lb[0], cell.lt[0]],
|
||||
[cell.lb[1], cell.lt[1]])
|
||||
if cell.right:
|
||||
plt.plot([cell.rb[0], cell.rt[0]],
|
||||
ax.plot([cell.rb[0], cell.rt[0]],
|
||||
[cell.rb[1], cell.rt[1]])
|
||||
if cell.top:
|
||||
plt.plot([cell.lt[0], cell.rt[0]],
|
||||
ax.plot([cell.lt[0], cell.rt[0]],
|
||||
[cell.lt[1], cell.rt[1]])
|
||||
if cell.bottom:
|
||||
plt.plot([cell.lb[0], cell.rb[0]],
|
||||
ax.plot([cell.lb[0], cell.rb[0]],
|
||||
[cell.lb[1], cell.rb[1]])
|
||||
plt.show()
|
||||
return fig
|
||||
|
||||
|
||||
def plot_contour(image):
|
||||
"""Generates a plot for all table boundaries present on the
|
||||
PDF page.
|
||||
"""Generates a plot for all table boundaries present
|
||||
on the PDF page.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : tuple
|
||||
|
||||
Returns
|
||||
-------
|
||||
fig : matplotlib.fig.Figure
|
||||
|
||||
"""
|
||||
img, table_bbox = image
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot(111, aspect='equal')
|
||||
for t in table_bbox.keys():
|
||||
cv2.rectangle(img, (t[0], t[1]),
|
||||
(t[2], t[3]), (255, 0, 0), 20)
|
||||
plt.imshow(img)
|
||||
plt.show()
|
||||
ax.add_patch(
|
||||
patches.Rectangle(
|
||||
(t[0], t[1]),
|
||||
t[2] - t[0],
|
||||
t[3] - t[1],
|
||||
fill=None,
|
||||
edgecolor='red'
|
||||
)
|
||||
)
|
||||
ax.imshow(img)
|
||||
return fig
|
||||
|
||||
|
||||
def plot_joint(image):
|
||||
"""Generates a plot for all line intersections present on the
|
||||
PDF page.
|
||||
"""Generates a plot for all line intersections present
|
||||
on the PDF page.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : tuple
|
||||
|
||||
Returns
|
||||
-------
|
||||
fig : matplotlib.fig.Figure
|
||||
|
||||
"""
|
||||
img, table_bbox = image
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot(111, aspect='equal')
|
||||
x_coord = []
|
||||
y_coord = []
|
||||
for k in table_bbox.keys():
|
||||
for coord in table_bbox[k]:
|
||||
x_coord.append(coord[0])
|
||||
y_coord.append(coord[1])
|
||||
plt.plot(x_coord, y_coord, 'ro')
|
||||
plt.imshow(img)
|
||||
plt.show()
|
||||
ax.plot(x_coord, y_coord, 'ro')
|
||||
ax.imshow(img)
|
||||
return fig
|
||||
|
||||
|
||||
def plot_line(segments):
|
||||
"""Generates a plot for all line segments present on the PDF page.
|
||||
"""Generates a plot for all line segments present
|
||||
on the PDF page.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
segments : tuple
|
||||
|
||||
Returns
|
||||
-------
|
||||
fig : matplotlib.fig.Figure
|
||||
|
||||
"""
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot(111, aspect='equal')
|
||||
vertical, horizontal = segments
|
||||
for v in vertical:
|
||||
plt.plot([v[0], v[2]], [v[1], v[3]])
|
||||
ax.plot([v[0], v[2]], [v[1], v[3]])
|
||||
for h in horizontal:
|
||||
plt.plot([h[0], h[2]], [h[1], h[3]])
|
||||
plt.show()
|
||||
ax.plot([h[0], h[2]], [h[1], h[3]])
|
||||
return fig
|
||||
|
||||
Reference in New Issue
Block a user