kartograph.py

#
from options import parse_options
from shapely.geometry import Polygon, LineString, MultiPolygon
from errors import *
from copy import deepcopy
from renderer import SvgRenderer, KmlRenderer
from map import Map
#

Kartograph

verbose = False
#

These renderers are currently available. See renderer/svg.py and renderer/kml.py for more details on those.

_known_renderer = {
    'svg': SvgRenderer,
    'kml': KmlRenderer
}
#
class Kartograph(object):
#
    def __init__(self):
        self.layerCache = {}
        pass
#

Generates a the map and renders it using the specified output format.

    def generate(self, opts, outfile=None, format='svg', preview=None):
#
        if preview is None:
            preview = outfile is not None
#

Create a deep copy of the options dictionary so our changes will not be visible to the calling application.

        opts = deepcopy(opts)
#

Parse the options dictionary. See options.py for more details.

        parse_options(opts)
#

Create the map instance. It will do all the hard work for us, so you definitely should check out map.py for all the fun stuff happending there..

        _map = Map(opts, self.layerCache, format=format)
#

Check if the format is handled by a renderer.

        format = format.lower()
        if format in _known_renderer:
#

Create a renderer instance and render the map.

            renderer = _known_renderer[format](_map)
            renderer.render()
#

If requested, we try to preview the created map now, which means that we open the created SVG file in Firefox or open the KML in Google Earth. Of course, preview modes are highly dependent on the operating system, but we don't care about that now.

            if preview:
                renderer.preview()
#

Write the map to a file or return the renderer instance.

            if outfile is None:
                return renderer
            else:
                renderer.write(outfile)
        else:
            raise KartographError('unknown format: %s' % format)
#

Here are some handy methods for debugging Kartograph. It will plot a given shapely geometry using matplotlib and descartes.

def _plot_geometry(geom, fill='#ffcccc', stroke='#333333', alpha=1, msg=None):
    from matplotlib import pyplot
    from matplotlib.figure import SubplotParams
    from descartes import PolygonPatch

    if isinstance(geom, (Polygon, MultiPolygon)):
        b = geom.bounds
        geoms = hasattr(geom, 'geoms') and geom.geoms or [geom]
        w, h = (b[2] - b[0], b[3] - b[1])
        ratio = w / h
        pad = 0.15
        fig = pyplot.figure(1, figsize=(5, 5 / ratio), dpi=110, subplotpars=SubplotParams(left=pad, bottom=pad, top=1 - pad, right=1 - pad))
        ax = fig.add_subplot(111, aspect='equal')
        for geom in geoms:
            patch1 = PolygonPatch(geom, linewidth=0.5, fc=fill, ec=stroke, alpha=alpha, zorder=0)
            ax.add_patch(patch1)
    p = (b[2] - b[0]) * 0.03  # some padding
    pyplot.axis([b[0] - p, b[2] + p, b[3] + p, b[1] - p])
    pyplot.grid(True)
    if msg:
        fig.suptitle(msg, y=0.04, fontsize=9)
    pyplot.show()
#
def _plot_lines(lines):
    from matplotlib import pyplot
#
    def plot_line(ax, line):
        filtered = []
        for pt in line:
            if not pt.deleted:
                filtered.append(pt)
        if len(filtered) < 2:
            return
        ob = LineString(line)
        x, y = ob.xy
        ax.plot(x, y, '-', color='#333333', linewidth=0.5, solid_capstyle='round', zorder=1)

    fig = pyplot.figure(1, figsize=(4, 5.5), dpi=90, subplotpars=SubplotParams(left=0, bottom=0.065, top=1, right=1))
    ax = fig.add_subplot(111, aspect='equal')
    for line in lines:
        plot_line(ax, line)
    pyplot.grid(False)
    ax.xaxis.set_visible(False)
    ax.yaxis.set_visible(False)
    ax.set_frame_on(False)
    return (ax, fig)
#
def _debug_show_features(features, message=None):
    from descartes import PolygonPatch
    from matplotlib import pyplot
    from matplotlib.figure import SubplotParams

    fig = pyplot.figure(1, figsize=(9, 5.5), dpi=110, subplotpars=SubplotParams(left=0, bottom=0.065, top=1, right=1))
    ax = fig.add_subplot(111, aspect='equal')
    b = (100000, 100000, -100000, -100000)
    for feat in features:
        if feat.geom is None:
            continue
        c = feat.geom.bounds
        b = (min(c[0], b[0]), min(c[1], b[1]), max(c[2], b[2]), max(c[3], b[3]))
        geoms = hasattr(feat.geom, 'geoms') and feat.geom.geoms or [feat.geom]
        for geom in geoms:
            patch1 = PolygonPatch(geom, linewidth=0.25, fc='#ddcccc', ec='#000000', alpha=0.75, zorder=0)
            ax.add_patch(patch1)
    p = (b[2] - b[0]) * 0.05  # some padding
    pyplot.axis([b[0] - p, b[2] + p, b[3], b[1] - p])
    ax.xaxis.set_visible(False)
    ax.yaxis.set_visible(False)
    ax.set_frame_on(True)
    if message:
        fig.suptitle(message, y=0.04, fontsize=9)
    pyplot.show()