예제 #1
0
def test_render_exceptions():
    for arg in ('fill', 'char'):
        with pytest.raises(ValueError):
            gj2ascii.render([], **{arg: 'too long'})
    for w in (0, -1, -1000):
        with pytest.raises(ValueError):
            gj2ascii.render([], width=w)
예제 #2
0
파일: test_core.py 프로젝트: nerik/gj2ascii
def test_render_exceptions():
    for arg in ('fill', 'char'):
        with pytest.raises(ValueError):
            gj2ascii.render([], **{arg: 'too long'})
    for w in (0, -1, -1000):
        with pytest.raises(ValueError):
            gj2ascii.render([], width=w)
예제 #3
0
 def test_compare_min_max_given_vs_compute_and_as_generator(self):
     # Easiest to compare these 3 things together since they are related
     with fiona.open(POLY_FILE) as src:
         min_max = dict(zip(('x_min', 'y_min', 'x_max', 'y_max'), src.bounds))
         given = gj2ascii.render(src, 15, **min_max)
         computed = gj2ascii.render(src, 15)
         # Passing in a generator and not specifying x/y min/max requires the features to be iterated over twice
         # which is a problem because generators cannot be reset.  A backup of the generator should be created
         # automatically and iterated over the second time.
         generator_output = gj2ascii.render((f for f in src), 15)
     self.assertEqual(given, computed, generator_output)
예제 #4
0
 def test_compare_bbox_given_vs_detect_collection_vs_compute_vs_as_generator(self):
     # Easiest to compare these 3 things together since they are related
     with fio.open(POLY_FILE) as src:
         given = gj2ascii.render(src, 15, bbox=src.bounds)
         computed = gj2ascii.render([i for i in src], 15)
         fio_collection = gj2ascii.render(src, 15)
         # Passing in a generator and not specifying x/y min/max requires the features to
         # be iterated over twice which is a problem because generators cannot be reset.
         # A backup of the generator should be created automatically and iterated over the
         # second time.
         generator_output = gj2ascii.render((f for f in src), 15)
     for pair in itertools.combinations(
             [given, computed, fio_collection, generator_output], 2):
         self.assertEqual(*pair)
예제 #5
0
파일: test_cli.py 프로젝트: nerik/gj2ascii
 def test_default_char_map(self):
     with fio.open(POLY_FILE) as src:
         expected = gj2ascii.render(src)
     result = self.runner.invoke(cli.main, [
         POLY_FILE
     ])
     self.assertEqual(result.exit_code, 0)
     self.assertTrue(compare_ascii(result.output.strip(), expected.strip()))
 def draw_trackline(self, geojson_file):
     with fiona.open(geojson_file) as src:
         self.log.logger.info((gj2ascii.render(
             src,
             100,
             fill='.',
             char='o',
             bbox=shape(
                 src.next()['geometry']).buffer(0.1).envelope.bounds)))
def main(infile, outfile):

    with fio.open(infile) as src, click.progressbar(src) as features:
        for feat in features:
            geom = shape(feat['geometry'])
            if not geom.is_closed:
                print(gj2ascii.render(geom))
                print(geom.is_valid)
                print(geom.is_simple)
                print(geom.coords[0])
                print(geom.coords[-1])
                return
예제 #8
0
 def test_exception(self):
     with self.assertRaises(ValueError):
         gj2ascii.render([], None, fill='asdf')
     with self.assertRaises(ValueError):
         gj2ascii.render([], None, value='asdf')
     with self.assertRaises(ValueError):
         gj2ascii.render([], width=-1)
예제 #9
0
def test_render_exception():
    with pytest.raises(TypeError):
        gj2ascii.render([], None, fill='asdf')
    with pytest.raises(TypeError):
        gj2ascii.render([], None, char='asdf')
    with pytest.raises(ValueError):
        gj2ascii.render([], width=-1)
예제 #10
0
파일: test_core.py 프로젝트: nerik/gj2ascii
 def test_exception(self):
     with self.assertRaises(TypeError):
         gj2ascii.render([], None, fill='asdf')
     with self.assertRaises(TypeError):
         gj2ascii.render([], None, char='asdf')
     with self.assertRaises(ValueError):
         gj2ascii.render([], width=-1)
예제 #11
0
 def test_styled_write_to_file(self):
     with fio.open(SINGLE_FEATURE_WV_FILE) as src:
         expected = gj2ascii.render(src, width=20, char='1', fill='0')
     with tempfile.NamedTemporaryFile('r+') as f:
         result = self.runner.invoke(cli.main, [
             SINGLE_FEATURE_WV_FILE, '--width', '20', '--properties',
             'NAME,ALAND', '--char', '1=red', '--fill', '0=blue',
             '--outfile', f.name
         ])
         f.seek(0)
         self.assertEqual(result.exit_code, 0)
         self.assertEqual(result.output, '')
         self.assertTrue(compare_ascii(f.read().strip(), expected.strip()))
예제 #12
0
def test_paginate():

    char = '+'
    fill = '.'
    colormap = {
        '+': 'red',
        '.': 'black'
    }
    with fio.open(POLY_FILE) as src1, fio.open(POLY_FILE) as src2:
        for paginated_feat, feat in zip(
                gj2ascii.paginate(src1, char=char, fill=fill, colormap=colormap), src2):
            assert paginated_feat.strip() == gj2ascii.style(
                gj2ascii.render(feat, char=char, fill=fill), stylemap=colormap)
예제 #13
0
def test_styled_write_to_file(runner, single_feature_wv_file, compare_ascii):
    with fio.open(single_feature_wv_file) as src:
        expected = gj2ascii.render(src, width=20, char='1', fill='0')
    with tempfile.NamedTemporaryFile('r+') as f:
        result = runner.invoke(cli.main, [
            single_feature_wv_file, '--width', '20', '--properties',
            'NAME,ALAND', '--char', '1=red', '--fill', '0=blue', '--outfile',
            f.name
        ])
        f.seek(0)
        assert result.exit_code == 0
        assert result.output == ''
        assert compare_ascii(f.read().strip(), expected.strip())
예제 #14
0
파일: test_cli.py 프로젝트: nerik/gj2ascii
 def test_styled_write_to_file(self):
     with fio.open(SINGLE_FEATURE_WV_FILE) as src:
         expected = gj2ascii.render(src, width=20, char='1', fill='0')
     with tempfile.NamedTemporaryFile('r+') as f:
         result = self.runner.invoke(cli.main, [
             SINGLE_FEATURE_WV_FILE,
             '--width', '20',
             '--properties', 'NAME,ALAND',
             '--char', '1=red',
             '--fill', '0=blue',
             '--outfile', f.name
         ])
         f.seek(0)
         self.assertEqual(result.exit_code, 0)
         self.assertEqual(result.output, '')
         self.assertTrue(compare_ascii(f.read().strip(), expected.strip()))
예제 #15
0
def test_render_multiple():
    with fio.open(POLY_FILE) as poly, \
            fio.open(LINE_FILE) as lines, \
            fio.open(POINT_FILE) as points:

        coords = list(poly.bounds) + list(lines.bounds) + list(points.bounds)
        bbox = (min(coords[0::4]), min(coords[1::4]), max(coords[2::4]), max(coords[3::4]))

        width = 20
        lyr_char_pairs = [(poly, '+'), (lines, '-'), (points, '*')]
        actual = gj2ascii.render_multiple(lyr_char_pairs, width, fill='#')

        rendered_layers = []
        for l, char in lyr_char_pairs:
            rendered_layers.append(gj2ascii.render(l, width, fill=' ', bbox=bbox, char=char))
        expected = gj2ascii.stack(rendered_layers, fill='#')

        assert compare_ascii(actual.strip(), expected.strip())
예제 #16
0
def test_multilayer_compute_colormap(runner, multilayer_file, compare_ascii):
    coords = []
    for layer in ('polygons', 'lines'):
        with fio.open(multilayer_file, layer=layer) as src:
            coords += list(src.bounds)
    bbox = min(coords[0::4]), min(coords[1::4]), max(coords[2::4]), max(
        coords[3::4])

    rendered_layers = []
    for layer, char in zip(('polygons', 'lines'), ('0', '1')):
        with fio.open(multilayer_file, layer=layer) as src:
            rendered_layers.append(
                gj2ascii.render(src, width=20, fill=' ', char=char, bbox=bbox))
    expected = gj2ascii.stack(rendered_layers)

    # Explicitly define since layers are not consistently listed in order
    result = runner.invoke(
        cli.main, [multilayer_file + ',polygons,lines', '--width', '20'])
    assert result.exit_code == 0
    assert compare_ascii(expected.strip(), result.output.strip())
예제 #17
0
파일: test_cli.py 프로젝트: nerik/gj2ascii
    def test_multilayer_compute_colormap(self):
        coords = []
        for layer in ('polygons', 'lines'):
            with fio.open(MULTILAYER_FILE, layer=layer) as src:
                coords += list(src.bounds)
        bbox = min(coords[0::4]), min(coords[1::4]), max(coords[2::4]), max(coords[3::4])

        rendered_layers = []
        for layer, char in zip(('polygons', 'lines'), ('0', '1')):
            with fio.open(MULTILAYER_FILE, layer=layer) as src:
                rendered_layers.append(
                    gj2ascii.render(src, width=20, fill=' ', char=char, bbox=bbox))
        expected = gj2ascii.stack(rendered_layers)

        # Explicitly define since layers are not consistently listed in order
        result = self.runner.invoke(cli.main, [
            MULTILAYER_FILE + ',polygons,lines',
            '--width', '20'
        ])
        self.assertEqual(result.exit_code, 0)
        self.assertTrue(compare_ascii(expected.strip(), result.output.strip()))
예제 #18
0
 def test_with_fio(self):
     with fio.open(POLY_FILE) as src:
         r = gj2ascii.render(src, width=40, fill='.', char='+', bbox=src.bounds)
         self.assertEqual(EXPECTED_POLYGON_40_WIDE.strip(), r.strip())
예제 #19
0
def test_with_fio(expected_polygon_40_wide, poly_file):
    with fio.open(poly_file) as src:
        r = gj2ascii.render(src, width=40, fill='.', char='+', bbox=src.bounds)
        assert expected_polygon_40_wide == r.rstrip()
예제 #20
0
#!/usr/bin/env python


"""
Render data with colors
"""


import fiona as fio
import gj2ascii


print("Render a single layer with colors")
with fio.open('sample-data/polygons.geojson') as src:
    rendered = gj2ascii.render(src, 40, char='+')
    print(gj2ascii.style(rendered, stylemap={'+': 'red'}))

print("")

print("Render multiple overlapping layers , apply colors, and zoom in on a bbox")
with fio.open('sample-data/polygons.geojson') as poly, \
        fio.open('sample-data/lines.geojson') as lines, \
        fio.open('sample-data/small-aoi-polygon-line.geojson') as bbox:
    layermap = [
        (poly, 'red'),
        (lines, 'blue')
    ]
    print(gj2ascii.style_multiple(layermap, 40, fill='yellow', bbox=bbox.bounds))
예제 #21
0
 def test_with_fiona(self):
     with fiona.open(POLY_FILE) as src:
         kwargs = dict(zip(('x_min', 'y_min', 'x_max', 'y_max'), src.bounds))
         r = gj2ascii.render(src, width=20, fill='.', value='+', **kwargs)
         self.assertEqual(EXPECTED_POLYGON_20_WIDE.strip(), r.strip())
예제 #22
0
def test_default_char_map(runner, poly_file, compare_ascii):
    with fio.open(poly_file) as src:
        expected = gj2ascii.render(src)
    result = runner.invoke(cli.main, [poly_file])
    assert result.exit_code == 0
    assert compare_ascii(result.output.strip(), expected.strip())
예제 #23
0
 def test_default_char_map(self):
     with fio.open(POLY_FILE) as src:
         expected = gj2ascii.render(src)
     result = self.runner.invoke(cli.main, [POLY_FILE])
     self.assertEqual(result.exit_code, 0)
     self.assertTrue(compare_ascii(result.output.strip(), expected.strip()))
예제 #24
0
#!/usr/bin/env python


"""
Rendering an entire layer and a single user-defined GeoJSON geometry object
with the most common parameters.
"""


import os

import gj2ascii
import fiona as fio


diamond = {
    'type': 'LineString',
    'coordinates': [[-10, 0], [0, 10], [10, 0], [0, -10], [-10, 0]]
}

print("Render a single independent geometry")
print(gj2ascii.render(diamond, 20, char='*', fill='.'))

print("")

print("Render an entire layer")
with fio.open('sample-data/WV.geojson') as src:
    print(gj2ascii.render(src, width=20, char='*', fill='.'))
 def draw_trackline(self, geojson_file):
     with fiona.open(geojson_file) as src:
         self.log.logger.info((gj2ascii.render(src, 100, fill='.', char='o', bbox=shape(src.next()['geometry']).buffer(0.1).envelope.bounds)))
예제 #26
0
def main(infile, outfile, width, iterate, fill_map, char_map, all_touched, crs_def, no_prompt,
         properties, bbox, no_style):

    """
    Render spatial vector data as ASCII with colors and emoji.

    \b
    Multiple layers from multiple files can be rendered as characters, colors,
    or emoji.  When working with multiple layers they are rendered in order
    according to the painters algorithm.

    \b
    When working with multiple layers the layer specific arguments
    can be specified once to apply to all or multiple to apply specific conditions
    to specific layers.  In the latter case the arguments are applied in order so
    the second instance of an argument corresponds to the second layer.

    \b
    Examples:
    \b
        Render the entire layer across 40 text columms:
    \b
            $ gj2ascii ${INFILE} --width 40
    \b
        Read from stdin and fill all pixels that intersect a geometry:
    \b
            $ cat ${INFILE} | gj2ascii - \\
                --width 30 \\
                --all-touched
    \b
        Render individual features across 20 columns and display the attributes
        for two fields:
    \b
            $ gj2ascii ${INFILE} \\
                --properties ${PROP1},${PROP2}  \\
                --width 20 \\
                --iterate
    \b
        Render multiple layers.  The first layer is read from stdin and will be
        rendered as a single character, the second will be the character `*' but
        masked by the color blue, the third will be a randomly assigned character
        but masked by the color black, and the fourth will be the :thumbsup: emoji:
    \b
            $ cat ${SINGLE_LAYER_INFILE} | gj2ascii \\
                - \\
                ${INFILE_2},${LAYER_NAME_1},${LAYER_NAME_2} \\
                ${SINGLE_LAYER_INFILE_1} \\
                --char + \\
                --char \\*=blue \\
                --char black \\
                --char :thumbsup:
    """

    fill_char = [c[0] for c in fill_map][-1]
    num_layers = sum([len(layers) for ds, layers in infile])

    # ==== Render individual features ==== #
    if iterate:

        if num_layers > 1:
            raise click.ClickException(
                "Can only iterate over a single layer.  Specify only one infile for "
                "single-layer datasources and `INFILE,LAYERNAME` for multi-layer datasources.")

        if len(infile) > 1 or num_layers > 1 or len(crs_def) > 1 \
                or len(char_map) > 1 or len(all_touched) > 1:
            raise click.ClickException(
                "Can only iterate over 1 layer - all layer-specific arguments can only be "
                "specified once each.")

        # User is writing to an output file.  Don't prompt for next feature every time
        # TODO: Don't just compare to '<stdout>' but sys.stdout.name throws an exception
        if not no_prompt and hasattr(outfile, 'name') and outfile.name != '<stdout>':
            no_prompt = True

        if not char_map:
            char_map = [(gj2ascii.DEFAULT_CHAR, None)]

        # The odd list slicing is due to infile looking something like this:
        # [
        #     ('sample-data/polygons.geojson', ['polygons']),
        #     ('sample-data/multilayer-polygon-line', ['lines', 'polygons'])
        # ]
        if num_layers > 0:
            layer = infile[-1][1][-1]
        else:
            layer = None
        in_ds = infile[-1][0]
        if in_ds == '-' and not no_prompt:

            # This exception blocks a feature - see the content for more info.
            raise click.ClickException(
                "Unfortunately features cannot yet be directly iterated over when reading "
                "from stdin.  The simplest workaround is to use:" + os.linesep * 2 +
                "    $ cat data.geojson | gj2ascii - --iterate --no-prompt | more" + 
                os.linesep * 2 +
                "This issue has been logged: https://github.com/geowurster/gj2ascii/issues/25"
            )
        with fio.open(infile[-1][0], layer=layer, crs=crs_def[-1]) as src:

            if properties == '%all':
                properties = src.schema['properties'].keys()

            # Get the last specified parameter when possible in case there's a bug in the
            # validation above.
            kwargs = {
                'width': width,
                'char': [_c[0] for _c in char_map][-1],
                'fill': fill_char,
                'properties': properties,
                'all_touched': all_touched[-1],
                'bbox': bbox,
                'colormap': _build_colormap(char_map, fill_map)
            }
            if no_style:
                kwargs['colormap'] = None

            for feature in gj2ascii.paginate(src.filter(bbox=bbox), **kwargs):
                click.echo(feature, file=outfile)
                if not no_prompt and click.prompt(
                        "Press enter for next feature or 'q + enter' to exit",
                        default='', show_default=False, err=True) \
                        not in ('', os.linesep):  # pragma no cover
                    raise click.Abort()

    # ==== Render all input layers ==== #
    else:

        # if len(crs_def) not in (1, num_layers) or len(char_map) not in (0, 1, num_layers) \
        #     or len(all_touched) not in (1, num_layers)

        # User didn't specify any characters/colors but the number of input layers exceeds
        # the number of available colors.
        if not char_map:
            if num_layers > len(gj2ascii.ANSI_COLORMAP):
                raise click.ClickException(
                    "can't auto-generate color ramp - number of input layers exceeds number "
                    "of colors.  Specify one `--char` per layer.")
            elif num_layers is 1:
                char_map = [(gj2ascii.DEFAULT_CHAR, None)]
            else:
                char_map = [(str(_i), gj2ascii.DEFAULT_CHAR_COLOR[str(_i)])
                            for _i in range(num_layers)]
        elif len(char_map) is not num_layers:
            raise click.ClickException(
                "Number of `--char` arguments must equal the number of layers being "
                "processed.  Found %s characters and %s layers.  Characters and colors will "
                "be generated if none are supplied." % (len(char_map), num_layers))
        if not char_map:
            char_map = {gj2ascii.DEFAULT_CHAR: None}

        # User didn't specify a bounding box.  Compute the minimum bbox for all layers.
        if not bbox:
            coords = []
            for ds, layer_names in infile:
                for layer, crs in zip_longest(layer_names, crs_def):
                    with fio.open(ds, layer=layer, crs=crs) as src:
                        coords += list(src.bounds)
            bbox = (min(coords[0::4]), min(coords[1::4]), max(coords[2::4]), max(coords[3::4]))

        # Render everything
        rendered_layers = []
        overall_lyr_idx = 0
        for ds, layer_names in infile:
            for layer, crs, at in zip_longest(layer_names, crs_def, all_touched):
                char = [_c[0] for _c in char_map][overall_lyr_idx]
                overall_lyr_idx += 1
                with fio.open(ds, layer=layer, crs=crs) as src:
                    rendered_layers.append(
                        # Layers will be stacked, which requires fill to be set to a space
                        gj2ascii.render(
                            src, width=width, fill=' ', char=char, all_touched=at, bbox=bbox))

        stacked = gj2ascii.stack(rendered_layers, fill=fill_char)
        if no_style:
            styled = stacked
        else:
            styled = gj2ascii.style(stacked, stylemap=_build_colormap(char_map, fill_map))
        click.echo(styled, file=outfile)