Example #1
0
def test_stretched_renderer(tmpdir):
    data = numpy.zeros((100, 100))
    for i in range(0, 100):
        data[i] = i
    colors = (
        (data.min(), Color(255, 0, 0, 255)),
        (data.max(), Color(0, 0, 255, 255))
    )
    renderer = StretchedRenderer(colors)

    assert renderer.name == 'stretched'

    img = renderer.render_image(data)
    assert len(img.getpalette()) / 3 == 256
    assert img.size == (100, 100)
    img.save(str(tmpdir.join("stretched.png")))

    legend = renderer.get_legend(20, 20)
    assert len(legend) == 1
    assert legend[0].image.size == (20, 20)
    legend[0].image.save(str(tmpdir.join("stretched_legend.png")))

    legend = renderer.get_legend(20, 20, discrete_images=True)
    assert len(legend) == 2
    assert legend[0].image.size == (20, 20)

    expected = {
        'colors': [(0.0, '#F00'), (99.0, '#00F')],
        'type': 'stretched',
        'options': {'color_space': 'hsv'}
    }

    assert renderer.serialize() == expected
Example #2
0
def test_classified_rendererer(tmpdir):
    data = numpy.zeros((100, 100))
    for i in range(0, 100):
        data[i] = i
    colors = (
        (10, Color(255, 0, 0, 255)),
        (50, Color(0, 255, 0, 255)),
        (data.max(), Color(0, 0, 255, 255))
    )
    renderer = ClassifiedRenderer(colors)

    assert renderer.name == 'classified'

    img = renderer.render_image(data)
    img.save(str(tmpdir.join("classified.png")))
    assert img.palette.palette == b'\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00'
    assert img.size == (100, 100)

    legend = renderer.get_legend(20, 20)
    assert len(legend) == 3
    for index, element in enumerate(legend):
        element.image.save(str(tmpdir.join("classified_legend_%i.png" % index)))

    expected = {
        'colors': [(10, '#F00'), (50, '#0F0'), (99.0, '#00F')],
        'type': 'classified'
    }
    assert renderer.serialize() == expected
Example #3
0
 def generate_unique_renderer(values, randomize_colors=False):
     if randomize_colors:
         r = random.randint(0, 255)
         g = random.randint(0, 255)
         b = random.randint(0, 255)
         return UniqueValuesRenderer([(v[0], Color(r, g, b))
                                      for v in values],
                                     labels=[v[1] for v in values])
     else:
         return UniqueValuesRenderer(
             [(v[1], Color(*[int(c) for c in v[0].split(',')[1:]]))
              for v in values],
             labels=[v[2] for v in values])
Example #4
0
def test_get_renderers_by_name():
    data = numpy.zeros((100, 100))
    for i in range(0, 100):
        data[i] = i
    colors = (
        (10, Color(255, 0, 0, 255)),
        (50, Color(0, 255, 0, 255)),
        (data.max(), Color(0, 0, 255, 255))
    )
    renderer = get_renderer_by_name("classified")(colors)
    img = renderer.render_image(data)
    assert img.palette.palette == b'\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00'
    assert img.size == (100, 100)
Example #5
0
 def generate_stretched_renderer(info):
     v_min = None
     v_max = None
     for var in info['variables'].keys():
         if var not in ['x', 'y', 'lat', 'lon', 'latitude', 'longitude']:
             variable = info['variables'][var]
             minimum = variable['min']
             maximum = variable['max']
             v_min = minimum if not v_min or minimum < v_min else v_min
             v_max = minimum if not v_max or maximum < v_max else v_max
     v_mid = (v_max - v_min) / 2 + v_min
     return StretchedRenderer([(v_min, Color(240, 59, 32)),
                               (v_mid, Color(254, 178, 76)),
                               (v_max, Color(255, 237, 160))])
Example #6
0
def colormap_to_stretched_renderer(colormap,
                                   colorspace='hsv',
                                   filenames=None,
                                   variable=None,
                                   fill_value=None,
                                   mask=None):
    statistics = None
    if 'min:' in colormap or 'max:' in colormap or 'mean' in colormap:
        if not filenames and variable:
            raise ValueError(
                'filenames and variable are required inputs to use colormap with statistics'
            )
        statistics = collect_statistics(filenames, (variable, ),
                                        mask=mask)[variable]

    colors = []
    for entry in colormap.split(','):
        value, color = entry.split(':')
        # TODO: add proportions of statistics
        if value in ('min', 'max', 'mean'):
            value = statistics[value]
        else:
            value = float(value)
        colors.append((value, Color.from_hex(color)))

    return StretchedRenderer(colors,
                             colorspace=colorspace,
                             fill_value=fill_value)
Example #7
0
def palette_to_stretched_renderer(palette_path,
                                  values,
                                  filenames=None,
                                  variable=None,
                                  fill_value=None,
                                  mask=None):
    palette = get_palette(palette_path)

    values = values.split(',')
    if not len(values) > 1:
        raise ValueError(
            'Must provide at least 2 values for palette-based stretched renderer'
        )

    if 'min' in values or 'max' in values:
        if not filenames and variable:
            raise ValueError(
                'filenames and variable are required inputs to use palette with statistics'
            )
        statistics = collect_statistics(filenames, (variable, ),
                                        mask=mask)[variable]

        for statistic in ('min', 'max'):
            if statistic in values:
                values[values.index(statistic)] = statistics[statistic]

    values = [float(v) for v in values]  # in case any are still strings

    hex_colors = palette.hex_colors

    # TODO: this only works cleanly for min:max or 2 endpoint values.  Otherwise require that the number of palette colors match the number of values

    colors = [(values[0], Color.from_hex(hex_colors[0]))]

    intermediate_colors = hex_colors[1:-1]
    if intermediate_colors:
        interval = (values[-1] - values[0]) / (len(intermediate_colors) + 1)
        for i, color in enumerate(intermediate_colors):
            colors.append(
                (values[0] + (i + 1) * interval, Color.from_hex(color)))

    colors.append((values[-1], Color.from_hex(hex_colors[-1])))

    return StretchedRenderer(
        colors, colorspace='rgb', fill_value=fill_value
    )  # I think all palettable palettes are in RGB ramps
Example #8
0
def _palette_to_stretched_renderer(palette_path,
                                   values,
                                   filenames=None,
                                   variable=None):
    index = palette_path.rindex('.')
    palette = getattr(
        importlib.import_module('palettable.' + palette_path[:index]),
        palette_path[index + 1:])

    values = values.split(',')
    if not len(values) > 1:
        raise ValueError(
            'Must provide at least 2 values for palette-based stretched renderer'
        )

    statistics = None
    if 'min' in values or 'max' in values:
        if not filenames and variable:
            raise ValueError(
                'filenames and variable are required inputs to use palette with statistics'
            )
        statistics = collect_statistics(filenames, (variable, ))[variable]

        for statistic in ('min', 'max'):
            if statistic in values:
                values[values.index(statistic)] = statistics[statistic]

    hex_colors = palette.hex_colors

    # TODO: this only works cleanly for min:max or 2 endpoint values.  Otherwise require that the number of palette colors match the number of values

    colors = [(values[0], Color.from_hex(hex_colors[0]))]

    intermediate_colors = hex_colors[1:-1]
    if intermediate_colors:
        interval = (values[-1] - values[0]) / (len(intermediate_colors) + 1)
        for i, color in enumerate(intermediate_colors):
            colors.append(
                (values[0] + (i + 1) * interval, Color.from_hex(color)))

    colors.append((values[-1], Color.from_hex(hex_colors[-1])))

    return StretchedRenderer(
        colors,
        colorspace='rgb')  # I think all palettable palettes are in RGB ramps
Example #9
0
def test_color():
    color_tuple = (0, 0, 0)
    c = Color(*color_tuple)
    assert c.to_tuple() == color_tuple
    assert c.to_hex() == "#000"
    c2 = Color.from_hsv(*c.to_hsv())
    assert c2.to_tuple() == color_tuple

    assert Color.from_hex("#000000", alpha=100)
Example #10
0
def test_uniquevalues_renderer(tmpdir):
    data = numpy.zeros((100, 100))
    data[10:25] = 10
    data[35:50] = 25
    data[50:75] = 50
    data[85:100] = 100
    colors = (
        (10, Color(255, 0, 0, 255)),
        (25, Color(255, 255, 255, 255)),
        (50, Color(0, 255, 0, 255)),
        (100, Color(0, 0, 255, 255))
    )
    labels = ('A', 'B', 'C', 'D')

    renderer = UniqueValuesRenderer(colors, labels=labels)

    assert renderer.name == 'unique'

    img = renderer.render_image(data)
    img.save(str(tmpdir.join("unique.png")))
    assert img.palette.palette == b'\xff\x00\x00\xff\xff\xff\x00\xff\x00\x00\x00\xff\x00\x00\x00'
    assert img.size == (100, 100)
    legend = renderer.get_legend(20, 20)
    assert len(legend) == 4
    for index, element in enumerate(legend):
        element.image.save(
            str(tmpdir.join("uniquevalues_legend_%i.png" % index)))

    expected = {
        'colors': [
            (10, '#F00'),
            (25, '#FFF'),
            (50, '#0F0'),
            (100, '#00F')],
        'type': 'unique',
        'options': {
            'labels': ('A', 'B', 'C', 'D')
        }
    }
    assert renderer.serialize() == expected
Example #11
0
    def get_polygon_image(self, polygons):
        im = Image.new('RGBA', self.image_size)

        if self._basemap_image is not None:
            im.paste(Image.blend(im, self._basemap_image, 1), (0, 0),
                     self._basemap_image)

        for p in polygons:
            color = Color.from_hex(
                p['properties']['color']).to_tuple() if hasattr(
                    p['properties'], 'color') else (0, 0, 255)
            self.draw_geometry(im, Geometry(str(p['geometry']))[0], color, 3)

        return self.crop_image(im)
Example #12
0
def renderer_from_dict(renderer_dict):
    """Returns a renderer object from a dictionary object"""

    options = renderer_dict.get('options', {})

    try:
        renderer_type = renderer_dict['type']
        renderer_colors = [(float(x[0]), Color.from_hex(x[1])) for x in renderer_dict['colors']]
        fill_value = options.get('fill_value')
        if fill_value is not None:
            fill_value = float(fill_value)
    except KeyError:
        raise ValueError("Missing required keys from renderer renderer_dicturation")

    renderer_kwargs = {
        'colormap': renderer_colors,
        'fill_value': fill_value,
        'background_color': Color(255, 255, 255, 0)
    }

    if renderer_type == "stretched":
        color_space = options.get('color_space', 'hsv').lower().strip()
        if not color_space in ('rgb', 'hsv'):
            raise ValueError("Invalid color space: {}".format(color_space))

        renderer = StretchedRenderer(colorspace=color_space, **renderer_kwargs)
    elif renderer_type == "classified":
        renderer = ClassifiedRenderer(**renderer_kwargs)
    elif renderer_type == "unique":
        try:
            labels = [six.text_type(x) for x in options.get('labels', [])]
        except TypeError:
            raise ValueError("Labels option must be an array")

        renderer = UniqueValuesRenderer(labels=labels, **renderer_kwargs)

    return renderer
Example #13
0
def palette_to_classified_renderer(palette_path,
                                   filenames,
                                   variable,
                                   method='equal',
                                   fill_value=None,
                                   mask=None):
    palette = get_palette(palette_path)
    num_breaks = palette.number
    colors = [Color(r, g, b) for (r, g, b) in palette.colors]

    if method == 'equal':
        statistics = collect_statistics(filenames, (variable, ),
                                        mask=mask)[variable]
        step = (statistics['max'] - statistics['min']) / num_breaks
        breaks = numpy.linspace(statistics['min'] + step, statistics['max'],
                                num_breaks)

    return ClassifiedRenderer(zip(breaks, colors), fill_value=fill_value)
Example #14
0
    def __init__(self, colormap, fill_value, background_color):
        """
        Construct a new renderer.

        :param colormap: [(value or class break, Color object)...]
        :param fill_value: value to fill with background color (if provided) or transparent
        :param background_color: the background color to apply to all areas not specifically handled by colormap, including
        areas with fill_value or masked out.
        """

        if background_color is not None:
            assert isinstance(background_color, Color)
        else:
            background_color = Color(0, 0, 0, 0)

        self.colormap = list(colormap)
        self.fill_value = fill_value
        self.background_color = background_color
        self.colormap.sort(key=lambda x: x[0])
        self.values = numpy.array([entry[0] for entry in self.colormap])
        self._generate_palette()
Example #15
0
import json
from PIL import Image
import numpy

from clover.utilities.color import Color

LEGEND_ELEMENT_BORDER_COLOR = Color(150, 150, 150, 0)
LEGEND_ELEMENT_BORDER_WIDTH = 1


class RasterRenderer(object):
    def __init__(self, colormap, fill_value, background_color):
        """
        Construct a new renderer.

        :param colormap: [(value or class break, Color object)...]
        :param fill_value: value to fill with background color (if provided) or transparent
        :param background_color: the background color to apply to all areas not specifically handled by colormap, including
        areas with fill_value or masked out.
        """

        if background_color is not None:
            assert isinstance(background_color, Color)
        else:
            background_color = Color(0, 0, 0, 0)

        self.colormap = list(colormap)
        self.fill_value = fill_value
        self.background_color = background_color
        self.colormap.sort(key=lambda x: x[0])
        self.values = numpy.array([entry[0] for entry in self.colormap])
Example #16
0
import json

import mercantile
from clover.geometry.bbox import BBox
from clover.utilities.color import Color
from ncdjango.config import RenderConfiguration, ImageConfiguration, LegendConfiguration
from ncdjango.views import GetImageViewBase, LegendViewBase
from pyproj import Proj

TILE_SIZE = (256, 256)
TRANSPARENT_BACKGROUND_COLOR = Color(255, 255, 255, 0)


class GetImageView(GetImageViewBase):
    def get_service_name(self, request, *args, **kwargs):
        return kwargs['service_name']

    def get_render_configurations(self, request, **kwargs):
        tile_bounds = list(
            mercantile.bounds(int(self.kwargs['x']), int(self.kwargs['y']),
                              int(self.kwargs['z'])))
        extent = BBox(
            tile_bounds,
            projection=Proj('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
        ).project(
            Proj(
                '+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +a=6378137 +b=6378137 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs'
            ))

        base_config = ImageConfiguration(
            extent=extent,
Example #17
0
def _parse_colormap(colormap_str):
    colormap = []
    for entry in colormap_str.split(','):
        value, color = entry.split(':')
        colormap.append((float(value), Color.from_hex(color)))
    return colormap