Example #1
0
def test_set_colors():

    mc = MapCanvas((400, 300))

    colors = [('blue', (0, 0, 255)), ('red', (255, 0, 0))]

    mc.add_colors(colors)

    assert mc.fore_image.get_color_names() == mc.back_image.get_color_names()

    colors = mc.get_color_names()

    assert colors == ['transparent', 'black', 'white', 'blue', 'red']
Example #2
0
def test_set_colors():

    mc = MapCanvas((400, 300))

    colors = [('blue', (0, 0, 255)),
              ('red', (255, 0, 0))]

    mc.add_colors(colors)

    assert mc.fore_image.get_color_names() == mc.back_image.get_color_names()

    colors = mc.get_color_names()

    assert colors == ['transparent', 'black', 'white', 'blue', 'red']
Example #3
0
    def __init__(self,
                 ice_movers=None,
                 image_size=(800, 600),
                 projection=None,
                 viewport=None,
                 **kwargs):
        '''
            :param ice_movers: ice_movers associated with this outputter.
            :type ice_movers: An ice_mover object or sequence of ice_mover
                              objects.

            Use super to pass optional \*\*kwargs to base class __init__ method
        '''
        # this is a place where we store our gradient color infomration
        self.gradient_lu = {}

        self.map_canvas = MapCanvas(image_size,
                                    projection=projection,
                                    viewport=viewport,
                                    preset_colors='transparent')
        self.map_canvas.add_colors([('black', (0, 0, 0))])

        self.set_gradient_colors(
            'thickness',
            color_range=(
                (0, 0, 0x7f, 0x7f),  # dark blue
                (0, 0, 0x7f, 0x3f),  # dark blue
                (0, 0, 0x7f, 0x00),  # dark blue
                (0xff, 0, 0, 0x00)),  # red
            scale=(0.0, 6.0),
            num_colors=64)

        self.set_gradient_colors(
            'concentration',
            color_range=(
                (0x80, 0xc0, 0xd0, 0x7f),  # sky blue
                (0, 0x40, 0x60, 0x00)),  # dark blue
            scale=(0.0, 1.0),
            num_colors=64)

        super(IceImageOutput, self).__init__(**kwargs)

        if (isinstance(ice_movers, collections.Iterable)
                and not isinstance(ice_movers, str)):
            self.ice_movers = ice_movers
        elif ice_movers is not None:
            self.ice_movers = (ice_movers, )
        else:
            self.ice_movers = tuple()
Example #4
0
def test_foreground_poly(output_dir):
    """
    test drawing polygons to the foreground
    """
    mc = MapCanvas((400, 300), preset_colors='web')

    mc.background_color = 'transparent'
    mc.clear_background()

    mc.draw_polygon(((-30, 30), (30, 30), (30, -20), (-30, -20)),
                    fill_color='white',
                    line_color='black',
                    background=False)

    mc.save_foreground(os.path.join(output_dir, "foreground.png"))
Example #5
0
def test_foreground_polyline(output_dir):
    """
    test drawing polygons to the background
    """
    mc = MapCanvas((400, 300), preset_colors='web')

    mc.background_color = 'transparent'
    mc.clear_background()

    mc.draw_polyline(((-30, 30), (30, 30), (30, -20), (-30, -20)),
                     line_color='red',
                     line_width=5,
                     background=False)

    mc.save_foreground(os.path.join(output_dir, "foreground_polyline.png"))
Example #6
0
def test_background_poly(output_dir):
    """
    test drawing polygons to the background
    """
    mc = MapCanvas((400, 300), preset_colors='web')

    mc.background_color = 'transparent'
    mc.clear_background()

    mc.draw_polygon(((-30, 30),
                     (30, 30),
                     (30, -20),
                     (-30, -20)),
                    fill_color='blue',
                    line_color='black',
                    background=True)

    mc.save_background(os.path.join(output_dir, "background.png"))
Example #7
0
def test_foreground_polyline(output_dir):
    """
    test drawing polygons to the background
    """
    mc = MapCanvas((400, 300), preset_colors='web')

    mc.background_color = 'transparent'
    mc.clear_background()

    mc.draw_polyline(((-30, 30),
                      (30, 30),
                      (30, -20),
                      (-30, -20)),
                     line_color='red',
                     line_width=5,
                     background=False)

    mc.save_foreground(os.path.join(output_dir, "foreground_polyline.png"))
Example #8
0
    def __init__(self, ice_movers=None,
                 image_size=(800, 600),
                 projection=None,
                 viewport=None,
                 **kwargs):
        '''
            :param ice_movers: ice_movers associated with this outputter.
            :type ice_movers: An ice_mover object or sequence of ice_mover
                              objects.

            Use super to pass optional \*\*kwargs to base class __init__ method
        '''
        # this is a place where we store our gradient color infomration
        self.gradient_lu = {}

        self.map_canvas = MapCanvas(image_size,
                                    projection=projection,
                                    viewport=viewport,
                                    preset_colors='transparent')
        self.map_canvas.add_colors([('black', (0, 0, 0))])

        self.set_gradient_colors('thickness',
                                 color_range=((0, 0, 0x7f, 0x7f),  # dark blue
                                              (0, 0, 0x7f, 0x3f),  # dark blue
                                              (0, 0, 0x7f, 0x00),  # dark blue
                                              (0xff, 0, 0, 0x00)),  # red
                                 scale=(0.0, 6.0),
                                 num_colors=64)

        self.set_gradient_colors('concentration',
                                 color_range=((0x80, 0xc0, 0xd0, 0x7f),  # sky blue
                                              (0, 0x40, 0x60, 0x00)),  # dark blue
                                 scale=(0.0, 1.0),
                                 num_colors=64)

        super(IceImageOutput, self).__init__(**kwargs)

        if (isinstance(ice_movers, collections.Iterable) and
                not isinstance(ice_movers, str)):
            self.ice_movers = ice_movers
        elif ice_movers is not None:
            self.ice_movers = (ice_movers,)
        else:
            self.ice_movers = tuple()
Example #9
0
def test_copy_back_to_fore(output_dir):

    mc = MapCanvas((400, 300), preset_colors='web')

    mc.background_color = 'white'
    mc.clear_background()
    mc.clear_foreground()

    mc.draw_polyline(((-30, 30), (30, 30), (30, -20), (-30, -20)),
                     line_color='red',
                     line_width=5,
                     background=True)

    mc.copy_back_to_fore()
    mc.draw_polyline(((-20, 20), (20, 20), (20, -10), (-20, -10)),
                     line_color='blue',
                     line_width=5,
                     background=False)

    mc.save_foreground(os.path.join(output_dir, "copy_back_to_fore.png"))
Example #10
0
class IceImageOutput(Outputter):
    '''
        Class that outputs ice data as an image for each ice mover.

        The image is PNG encoded, then Base64 encoded to include in a
        JSON response.
    '''
    _schema = IceImageSchema

    def __init__(self,
                 ice_movers=None,
                 image_size=(800, 600),
                 projection=None,
                 viewport=None,
                 **kwargs):
        '''
            :param ice_movers: ice_movers associated with this outputter.
            :type ice_movers: An ice_mover object or sequence of ice_mover
                              objects.

            Use super to pass optional \*\*kwargs to base class __init__ method
        '''
        # this is a place where we store our gradient color infomration
        self.gradient_lu = {}

        self.map_canvas = MapCanvas(image_size,
                                    projection=projection,
                                    viewport=viewport,
                                    preset_colors='transparent')
        self.map_canvas.add_colors([('black', (0, 0, 0))])

        self.set_gradient_colors(
            'thickness',
            color_range=(
                (0, 0, 0x7f, 0x7f),  # dark blue
                (0, 0, 0x7f, 0x3f),  # dark blue
                (0, 0, 0x7f, 0x00),  # dark blue
                (0xff, 0, 0, 0x00)),  # red
            scale=(0.0, 6.0),
            num_colors=64)

        self.set_gradient_colors(
            'concentration',
            color_range=(
                (0x80, 0xc0, 0xd0, 0x7f),  # sky blue
                (0, 0x40, 0x60, 0x00)),  # dark blue
            scale=(0.0, 1.0),
            num_colors=64)

        super(IceImageOutput, self).__init__(**kwargs)

        if (isinstance(ice_movers, collections.Iterable)
                and not isinstance(ice_movers, str)):
            self.ice_movers = ice_movers
        elif ice_movers is not None:
            self.ice_movers = (ice_movers, )
        else:
            self.ice_movers = tuple()

    def set_gradient_colors(
            self,
            gradient_name,
            color_range=(
                (0, 0, 0x7f),  # dark blue
                (0, 0xff, 0xff)),  # cyan
            scale=(0.0, 10.0),
            num_colors=16):
        '''
            Add a color gradient to our palette representing the colors we
            will use for our ice thickness

            :param gradient_name: The name of the gradient.
            :type gradient_name: str

            :param color_range: The colors we will build our gradient with.
            :type color_range: A 2 element sequence of 3-tuples containing
                               8-bit RGB values.

            :param scale: A range of values representing the low and high end
                          of our gradient.
            :type scale: A 2 element sequence of float

            :param num_colors: The number of colors to use for the gradient.
            :type num_colors: Number
        '''
        color_names = self.add_gradient_to_canvas(color_range, gradient_name,
                                                  num_colors)

        self.gradient_lu[gradient_name] = (scale, np.array(color_names))

    def add_gradient_to_canvas(self, color_range, color_prefix, num_colors):
        '''
            Add a color gradient to our palette

            NOTE: Probably not the most efficient way to do this.

            :param color_range: The colors that we would like to use to
                                generate our gradient
            :type color_range: A sequence of 2 or more 3-tuples

            :param color_prefix: The prefix that will be used in the naming
                                 of the colors in the gradient
            :type color_prefix: str

            :param num_colors: The number of gradient colors to generate
            :type num_colors: Number
        '''
        color_range_idx = range(len(color_range))
        color_space = np.linspace(color_range_idx[0],
                                  color_range_idx[-1],
                                  num=num_colors)

        r_grad = np.interp(color_space, color_range_idx,
                           [c[0] for c in color_range])
        g_grad = np.interp(color_space, color_range_idx,
                           [c[1] for c in color_range])
        b_grad = np.interp(color_space, color_range_idx,
                           [c[2] for c in color_range])

        if all([len(c) >= 4 for c in color_range]):
            a_grad = np.interp(color_space, color_range_idx,
                               [c[3] for c in color_range])
        else:
            a_grad = np.array([0.] * num_colors)

        new_colors = []
        for i, (r, g, b, a) in enumerate(zip(r_grad, g_grad, b_grad, a_grad)):
            new_colors.append(('{}{}'.format(color_prefix, i), (r, g, b, a)))

        self.map_canvas.add_colors(new_colors)

        return [c[0] for c in new_colors]

    def lookup_gradient_color(self, gradient_name, values):
        try:
            (low_val, high_val), color_names = self.gradient_lu[gradient_name]
        except IndexError:
            return None

        scale_range = high_val - low_val
        q_step_range = scale_range / len(color_names)

        idx = (np.floor(values / q_step_range).astype(int).clip(
            0,
            len(color_names) - 1))

        return color_names[idx]

    def write_output(self, step_num, islast_step=False):
        """
            Generate image from data
        """
        # I don't think we need this for this outputter:
        #   - it does stuff with cache initialization
        super(IceImageOutput, self).write_output(step_num, islast_step)

        if (self.on is False or not self._write_step
                or len(self.ice_movers) == 0):
            return None

        # fixme -- doing all this cache stuff just to get the timestep..
        # maybe timestep should be passed in.
        for sc in self.cache.load_timestep(step_num).items():
            model_time = date_to_sec(sc.current_time_stamp)
            iso_time = sc.current_time_stamp.isoformat()

        thick_image, conc_image, bb = self.render_images(model_time)

        # web_mercator = 'EPSG:3857'
        equirectangular = 'EPSG:32662'

        # info to return to the caller
        output_dict = {
            'step_num': step_num,
            'time_stamp': iso_time,
            'thickness_image': thick_image,
            'concentration_image': conc_image,
            'bounding_box': bb,
            'projection': equirectangular,
        }

        return output_dict

    def get_sample_image(self):
        """
            This returns a base 64 encoded PNG image for testing,
            just so we have something

            This should be removed when we have real functionality
        """
        # hard-coding the base64 really confused my editor..
        image_file_file_path = os.path.join(
            os.path.split(__file__)[0], 'sample.b64')

        return open(image_file_file_path).read()

    def render_images(self, model_time):
        """
            render the actual images
            This uses the MapCanvas code to do the actual rendering

            returns: thickness_image, concentration_image
        """
        canvas = self.map_canvas

        # We kinda need to figure our our bounding box before doing the
        # rendering.  We will try to be efficient about it mainly by not
        # grabbing our grid data twice.
        mover_grid_bb = None
        mover_grids = []

        for mover in self.ice_movers:
            mover_grids.append(mover.get_grid_data())
            mover_grid_bb = mover.get_grid_bounding_box(
                mover_grids[-1], mover_grid_bb)

        canvas.viewport = mover_grid_bb
        canvas.clear_background()

        # Here is where we draw our grid data....
        for mover, mover_grid in zip(self.ice_movers, mover_grids):
            mover_grid_bb = mover.get_grid_bounding_box(
                mover_grid, mover_grid_bb)

            concentration, thickness = mover.get_ice_fields(model_time)

            thickness_colors = self.lookup_gradient_color(
                'thickness', thickness)
            concentration_colors = self.lookup_gradient_color(
                'concentration', concentration)

            dtype = mover_grid.dtype.descr
            unstructured_type = dtype[0][1]
            new_shape = mover_grid.shape + (len(dtype), )
            mover_grid = (mover_grid.view(dtype=unstructured_type).reshape(
                *new_shape))

            for poly, tc, cc in zip(mover_grid, thickness_colors,
                                    concentration_colors):
                canvas.draw_polygon(poly, fill_color=tc)
                canvas.draw_polygon(poly, fill_color=cc, background=True)

        # py_gd does not currently have the capability to generate a .png
        # formatted buffer in memory. (libgd can be made to do this, but
        # the wrapper is yet to be written)
        # So we will just write to a tempfile and then read it back.
        # If we ever have to do this anywhere else, a context manger would be good.
        tempdir = tempfile.mkdtemp()
        tempfilename = os.path.join(tempdir, "gnome_temp_image_file.png")

        canvas.save_foreground(tempfilename)
        thickness_image = open(tempfilename, 'rb').read().encode('base64')

        canvas.save_background(tempfilename)
        coverage_image = open(tempfilename, 'rb').read().encode('base64')

        os.remove(tempfilename)
        os.rmdir(tempdir)

        return ("data:image/png;base64,{}".format(thickness_image),
                "data:image/png;base64,{}".format(coverage_image),
                mover_grid_bb)

    def ice_movers_to_dict(self):
        '''
        a dict containing 'obj_type' and 'id' for each object in
        list/collection
        '''
        return self._collection_to_dict(self.ice_movers)
Example #11
0
    def __init__(
        self,
        filename,
        images_dir,
        image_size=(800, 600),
        cache=None,
        output_timestep=None,
        output_zero_step=True,
        output_last_step=True,
        draw_ontop='forecast',
        **kwargs
        ):
        """
        Init the image renderer.

        Following args are passed to base class Outputter's init:

        :param cache: sets the cache object from which to read data. The model
            will automatically set this param

        :param output_timestep: default is None in which case everytime the
            write_output is called, output is written. If set, then output is
            written every output_timestep starting from model_start_time.
        :type output_timestep: timedelta object

        :param output_zero_step: default is True. If True then output for
            initial step (showing initial release conditions) is written
            regardless of output_timestep
        :type output_zero_step: boolean

        :param output_last_step: default is True. If True then output for
            final step is written regardless of output_timestep
        :type output_last_step: boolean

        :param draw_ontop: draw 'forecast' or 'uncertain' LEs on top. Default
            is to draw 'forecast' LEs, which are in black on top
        :type draw_ontop: str

        Remaining kwargs are passed onto baseclass's __init__ with a direct
        call: MapCanvas.__init__(..)

        Optional parameters (kwargs)

        :param projection_class: gnome.utilities.projections class to use.
            Default is gnome.utilities.projections.FlatEarthProjection
        :param map_BB:  map bounding box. Default is to use
            land_polygons.bounding_box. If land_polygons is None, then this is
            the whole world, defined by ((-180,-90),(180, 90))
        :param viewport: viewport of map -- what gets drawn and on what scale.
            Default is to set viewport = map_BB
        :param image_mode: Image mode ('P' for palette or 'L' for Black and
            White image). BW_MapCanvas inherits from MapCanvas and sets the
            mode to 'L'. Default image_mode is 'P'.
        :param id: unique identifier for a instance of this class (UUID given
            as a string). This is used when loading an object from a persisted
            model.
        """

        # set up the canvas

        self._filename = filename
        polygons = haz_files.ReadBNA(filename, 'PolygonSet')
        Outputter.__init__(self, cache, output_timestep, output_zero_step,
                           output_last_step)
        MapCanvas.__init__(self, image_size, land_polygons=polygons,
                           **kwargs)

        self.images_dir = images_dir

        self.last_filename = ''

        self.draw_ontop = draw_ontop
Example #12
0
def test_projection(output_dir):
    """
    draw the "same sized" rectangle at three latitudes to see how the look
    """
    mc = MapCanvas((400, 400), preset_colors='web')

    mc.viewport = ((-20, 25), (20, 65))
    mc.draw_polygon(((-15, 60), (15, 60), (15, 30), (-15, 30)),
                    fill_color='maroon',
                    line_color='black')

    mc.save_foreground(os.path.join(output_dir, "image_projection_north.png"))

    mc.viewport = ((-20, -20), (20, 20))
    mc.draw_polygon(((-15, 15), (15, 15), (15, -15), (-15, -15)),
                    fill_color='maroon',
                    line_color='black')

    mc.save_foreground(os.path.join(output_dir,
                                    "image_projection_equator.png"))

    mc.viewport = ((-20, -45), (20, -90))
    mc.draw_polygon(((-15, -80), (15, -80), (15, -50), (-15, -50)),
                    fill_color='maroon',
                    line_color='black')

    mc.save_foreground(os.path.join(output_dir, "image_projection_south.png"))
Example #13
0
def test_init():
    """
    can we even initialize one
    """
    mc = MapCanvas((400, 300))
Example #14
0
def test_copy_back_to_fore(output_dir):

    mc = MapCanvas((400, 300), preset_colors='web')

    mc.background_color = 'white'
    mc.clear_background()
    mc.clear_foreground()

    mc.draw_polyline(((-30, 30),
                      (30, 30),
                      (30, -20),
                      (-30, -20)),
                     line_color='red',
                     line_width=5,
                     background=True)

    mc.copy_back_to_fore()
    mc.draw_polyline(((-20, 20),
                      (20, 20),
                      (20, -10),
                      (-20, -10)),
                     line_color='blue',
                     line_width=5,
                     background=False)

    mc.save_foreground(os.path.join(output_dir, "copy_back_to_fore.png"))
Example #15
0
class IceImageOutput(Outputter):
    '''
        Class that outputs ice data as an image for each ice mover.

        The image is PNG encoded, then Base64 encoded to include in a
        JSON response.
    '''
    _state = copy.deepcopy(Outputter._state)

    # need a schema and also need to override save so output_dir
    # is saved correctly - maybe point it to saveloc
    _state.add_field(Field('ice_movers',
                           save=True, update=True, iscollection=True))

    _schema = IceImageSchema

    def __init__(self, ice_movers=None,
                 image_size=(800, 600),
                 projection=None,
                 viewport=None,
                 **kwargs):
        '''
            :param ice_movers: ice_movers associated with this outputter.
            :type ice_movers: An ice_mover object or sequence of ice_mover
                              objects.

            Use super to pass optional \*\*kwargs to base class __init__ method
        '''
        # this is a place where we store our gradient color infomration
        self.gradient_lu = {}

        self.map_canvas = MapCanvas(image_size,
                                    projection=projection,
                                    viewport=viewport,
                                    preset_colors='transparent')
        self.map_canvas.add_colors([('black', (0, 0, 0))])

        self.set_gradient_colors('thickness',
                                 color_range=((0, 0, 0x7f, 0x7f),  # dark blue
                                              (0, 0, 0x7f, 0x3f),  # dark blue
                                              (0, 0, 0x7f, 0x00),  # dark blue
                                              (0xff, 0, 0, 0x00)),  # red
                                 scale=(0.0, 6.0),
                                 num_colors=64)

        self.set_gradient_colors('concentration',
                                 color_range=((0x80, 0xc0, 0xd0, 0x7f),  # sky blue
                                              (0, 0x40, 0x60, 0x00)),  # dark blue
                                 scale=(0.0, 1.0),
                                 num_colors=64)

        super(IceImageOutput, self).__init__(**kwargs)

        if (isinstance(ice_movers, collections.Iterable) and
                not isinstance(ice_movers, str)):
            self.ice_movers = ice_movers
        elif ice_movers is not None:
            self.ice_movers = (ice_movers,)
        else:
            self.ice_movers = tuple()

    def set_gradient_colors(self, gradient_name,
                            color_range=((0, 0, 0x7f),  # dark blue
                                         (0, 0xff, 0xff)),  # cyan
                            scale=(0.0, 10.0),
                            num_colors=16):
        '''
            Add a color gradient to our palette representing the colors we
            will use for our ice thickness

            :param gradient_name: The name of the gradient.
            :type gradient_name: str

            :param color_range: The colors we will build our gradient with.
            :type color_range: A 2 element sequence of 3-tuples containing
                               8-bit RGB values.

            :param scale: A range of values representing the low and high end
                          of our gradient.
            :type scale: A 2 element sequence of float

            :param num_colors: The number of colors to use for the gradient.
            :type num_colors: Number
        '''
        color_names = self.add_gradient_to_canvas(color_range,
                                                  gradient_name, num_colors)

        self.gradient_lu[gradient_name] = (scale, np.array(color_names))

    def add_gradient_to_canvas(self, color_range, color_prefix, num_colors):
        '''
            Add a color gradient to our palette

            NOTE: Probably not the most efficient way to do this.

            :param color_range: The colors that we would like to use to
                                generate our gradient
            :type color_range: A sequence of 2 or more 3-tuples

            :param color_prefix: The prefix that will be used in the naming
                                 of the colors in the gradient
            :type color_prefix: str

            :param num_colors: The number of gradient colors to generate
            :type num_colors: Number
        '''
        color_range_idx = range(len(color_range))
        color_space = np.linspace(color_range_idx[0], color_range_idx[-1],
                                  num=num_colors)

        r_grad = np.interp(color_space, color_range_idx,
                           [c[0] for c in color_range])
        g_grad = np.interp(color_space, color_range_idx,
                           [c[1] for c in color_range])
        b_grad = np.interp(color_space, color_range_idx,
                           [c[2] for c in color_range])

        if all([len(c) >= 4 for c in color_range]):
            a_grad = np.interp(color_space, color_range_idx,
                               [c[3] for c in color_range])
        else:
            a_grad = np.array([0.] * num_colors)

        new_colors = []
        for i, (r, g, b, a) in enumerate(zip(r_grad, g_grad, b_grad, a_grad)):
            new_colors.append(('{}{}'.format(color_prefix, i), (r, g, b, a)))

        self.map_canvas.add_colors(new_colors)

        return [c[0] for c in new_colors]

    def lookup_gradient_color(self, gradient_name, values):
        try:
            (low_val, high_val), color_names = self.gradient_lu[gradient_name]
        except IndexError:
            return None

        scale_range = high_val - low_val
        q_step_range = scale_range / len(color_names)

        idx = (np.floor(values / q_step_range)
               .astype(int)
               .clip(0, len(color_names) - 1))

        return color_names[idx]

    def write_output(self, step_num, islast_step=False):
        """
            Generate image from data
        """
        # I don't think we need this for this outputter:
        #   - it does stuff with cache initialization
        super(IceImageOutput, self).write_output(step_num, islast_step)

        if (self.on is False or
                not self._write_step or
                len(self.ice_movers) == 0):
            return None

        # fixme -- doing all this cache stuff just to get the timestep..
        # maybe timestep should be passed in.
        for sc in self.cache.load_timestep(step_num).items():
            model_time = date_to_sec(sc.current_time_stamp)
            iso_time = sc.current_time_stamp.isoformat()

        thick_image, conc_image, bb = self.render_images(model_time)

        # info to return to the caller
        web_mercator = 'EPSG:3857'
        equirectangular = 'EPSG:32662'
        output_dict = {'step_num': step_num,
                       'time_stamp': iso_time,
                       'thickness_image': thick_image,
                       'concentration_image': conc_image,
                       'bounding_box': bb,
                       'projection': equirectangular,
                       }

        return output_dict

    def get_sample_image(self):
        """
            This returns a base 64 encoded PNG image for testing,
            just so we have something

            This should be removed when we have real functionality
        """
        # hard-coding the base64 really confused my editor..
        image_file_file_path = os.path.join(os.path.split(__file__)[0],
                                            'sample.b64')

        return open(image_file_file_path).read()

    def render_images(self, model_time):
        """
            render the actual images
            This uses the MapCanvas code to do the actual rendering

            returns: thickness_image, concentration_image
        """
        canvas = self.map_canvas

        # We kinda need to figure our our bounding box before doing the
        # rendering.  We will try to be efficient about it mainly by not
        # grabbing our grid data twice.
        mover_grid_bb = None
        mover_grids = []
        for mover in self.ice_movers:
            mover_grids.append(mover.get_grid_data())
            mover_grid_bb = mover.get_grid_bounding_box(mover_grids[-1],
                                                        mover_grid_bb)

        canvas.viewport = mover_grid_bb
        canvas.clear_background()

        # Here is where we draw our grid data....
        for mover, mover_grid in zip(self.ice_movers, mover_grids):
            mover_grid_bb = mover.get_grid_bounding_box(mover_grid,
                                                        mover_grid_bb)

            concentration, thickness = mover.get_ice_fields(model_time)

            thickness_colors = self.lookup_gradient_color('thickness',
                                                          thickness)
            concentration_colors = self.lookup_gradient_color('concentration',
                                                              concentration)

            dtype = mover_grid.dtype.descr
            unstructured_type = dtype[0][1]
            new_shape = mover_grid.shape + (len(dtype),)
            mover_grid = (mover_grid
                          .view(dtype=unstructured_type)
                          .reshape(*new_shape))

            for poly, tc, cc in zip(mover_grid,
                                    thickness_colors, concentration_colors):
                canvas.draw_polygon(poly, fill_color=tc)
                canvas.draw_polygon(poly, fill_color=cc, background=True)

        # diagnostic so we can see what we have rendered.
        # print '\ndrawing reference objects...'
        # canvas.draw_graticule(False)
        # canvas.draw_tags(False)
        # canvas.save_background('background.png')
        # canvas.save_foreground('foreground.png')

        # py_gd does not currently have the capability to generate a .png
        # formatted buffer in memory. (libgd can be made to do this, but
        # the wrapper is yet to be written)
        # So we will just write to a tempfile and then read it back.
        with NamedTemporaryFile() as fp:
            canvas.save_foreground(fp.name)
            fp.seek(0)
            thickness_image = fp.read().encode('base64')

        with NamedTemporaryFile() as fp:
            canvas.save_background(fp.name)
            fp.seek(0)
            coverage_image = fp.read().encode('base64')

        return ("data:image/png;base64,{}".format(thickness_image),
                "data:image/png;base64,{}".format(coverage_image),
                mover_grid_bb)

    def rewind(self):
        'remove previously written files'
        super(IceImageOutput, self).rewind()

    def ice_movers_to_dict(self):
        '''
        a dict containing 'obj_type' and 'id' for each object in
        list/collection
        '''
        return self._collection_to_dict(self.ice_movers)

    @classmethod
    def deserialize(cls, json_):
        """
        append correct schema for current mover
        """
        schema = cls._schema()
        _to_dict = schema.deserialize(json_)

        if 'ice_movers' in json_:
            _to_dict['ice_movers'] = []
            for i, cm in enumerate(json_['ice_movers']):
                cm_cls = class_from_objtype(cm['obj_type'])
                cm_dict = cm_cls.deserialize(json_['ice_movers'][i])

                _to_dict['ice_movers'].append(cm_dict)

        return _to_dict
Example #16
0
    def __init__(self,
                 map_filename=None,
                 output_dir='./',
                 image_size=(800, 600),
                 projection=None,
                 viewport=None,
                 map_BB=None,
                 land_polygons=None,
                 draw_back_to_fore=True,
                 draw_map_bounds=False,
                 draw_spillable_area=False,
                 formats=['png', 'gif'],
                 draw_ontop='forecast',
                 cache=None,
                 output_timestep=None,
                 output_zero_step=True,
                 output_last_step=True,
                 output_start_time=None,
                 on=True,
                 timestamp_attrib={},
                 **kwargs):
        """
        Init the image renderer.

        :param str map_filename=None: name of file for basemap (BNA)
        :type map_filename: str

        :param str output_dir='./': directory to output the images

        :param 2-tuple image_size=(800, 600): size of images to output

        :param projection=None: projection instance to use: If None,
                                set to projections.FlatEarthProjection()
        :type projection: a gnome.utilities.projection.Projection instance

        :param viewport: viewport of map -- what gets drawn and on what scale.
                         Default is full globe: (((-180, -90), (180, 90)))
                         If not specifies, it will be set to the map's bounds.
        :type viewport: pair of (lon, lat) tuples ( lower_left, upper right )

        :param map_BB=None: bounding box of map if None, it will use the
                            bounding box of the mapfile.

        :param draw_back_to_fore=True: draw the background (map) to the
                                       foregound image when outputting
                                       the images each time step.
        :type draw_back_to_fore: boolean

        :param formats=['gif']: list of formats to output.
        :type formats: string or list of strings. Options are:
                       ['bmp', 'jpg', 'jpeg', 'gif', 'png']

        :param draw_ontop: draw 'forecast' or 'uncertain' LEs on top. Default
            is to draw 'forecast' LEs, which are in black on top
        :type draw_ontop: str

        Following args are passed to base class Outputter's init:

        :param cache: sets the cache object from which to read prop. The model
            will automatically set this param

        :param output_timestep: default is None in which case everytime the
            write_output is called, output is written. If set, then output is
            written every output_timestep starting from model_start_time.
        :type output_timestep: timedelta object

        :param output_zero_step: default is True. If True then output for
            initial step (showing initial release conditions) is written
            regardless of output_timestep
        :type output_zero_step: boolean

        :param output_last_step: default is True. If True then output for
            final step is written regardless of output_timestep
        :type output_last_step: boolean

        Remaining kwargs are passed onto baseclass's __init__ with a direct
        call: Outputter.__init__(..)

        """
        projection = (projections.FlatEarthProjection()
                      if projection is None else projection)

        # set up the canvas
        self.map_filename = map_filename
        self.output_dir = output_dir

        if map_filename is not None and land_polygons is None:
            self.land_polygons = haz_files.ReadBNA(map_filename, 'PolygonSet')
        elif land_polygons is not None:
            self.land_polygons = land_polygons
        else:
            self.land_polygons = []  # empty list so we can loop thru it

        self.last_filename = ''
        self.draw_ontop = draw_ontop
        self.draw_back_to_fore = draw_back_to_fore

        Outputter.__init__(self, cache, on, output_timestep, output_zero_step,
                           output_last_step, output_start_time, output_dir,
                           **kwargs)

        if map_BB is None:
            if not self.land_polygons:
                map_BB = ((-180, -90), (180, 90))
            else:
                map_BB = self.land_polygons.bounding_box

        self.map_BB = map_BB

        viewport = self.map_BB if viewport is None else viewport
        MapCanvas.__init__(self,
                           image_size,
                           projection=projection,
                           viewport=viewport)

        # assorted rendering flags:
        self.draw_map_bounds = draw_map_bounds
        self.draw_spillable_area = draw_spillable_area

        self.raster_map = None
        self.raster_map_fill = True
        self.raster_map_outline = False

        # initilize the images:
        self.add_colors(self.map_colors)
        self.background_color = 'background'

        if self.map_filename is not None:
            file_prefix = os.path.splitext(self.map_filename)[0]
            sep = '_'
        else:
            file_prefix = sep = ''

        fn = '{}{}anim.gif'.format(file_prefix, sep)
        self.anim_filename = os.path.join(output_dir, fn)

        self.formats = formats
        self.delay = 50
        self.repeat = True
        self.timestamp_attribs = {}

        self.set_timestamp_attrib(**timestamp_attrib)

        self.grids = []
        self.props = []
Example #17
0
    def __init__(
        self,
        filename=None,
        images_dir="./",
        image_size=(800, 600),
        cache=None,
        output_timestep=None,
        output_zero_step=True,
        output_last_step=True,
        draw_ontop="forecast",
        draw_back_to_fore=True,
        **kwargs
    ):
        """
        Init the image renderer.

        Following args are passed to base class Outputter's init:

        :param filename: the name of the image file

        :param images_dir: the folder in which to write the image

        :param image_size: the width and height of the image

        :param cache: sets the cache object from which to read data. The model
            will automatically set this param

        :param output_timestep: default is None in which case everytime the
            write_output is called, output is written. If set, then output is
            written every output_timestep starting from model_start_time.
        :type output_timestep: timedelta object

        :param output_zero_step: default is True. If True then output for
            initial step (showing initial release conditions) is written
            regardless of output_timestep
        :type output_zero_step: boolean

        :param output_last_step: default is True. If True then output for
            final step is written regardless of output_timestep
        :type output_last_step: boolean

        :param draw_ontop: draw 'forecast' or 'uncertain' LEs on top. Default
            is to draw 'forecast' LEs, which are in black on top
        :type draw_ontop: str

        :param draw_back_to_fore=True: draw the background (map) to the
            foregound image when drawing Elements.
        :type draw_ontop: boolean

        Remaining kwargs are passed onto baseclass's __init__ with a direct
        call: MapCanvas.__init__(..)

        Optional parameters (kwargs)

        :param projection_class: gnome.utilities.projections class to use.
            Default is gnome.utilities.projections.FlatEarthProjection
        :param map_BB:  map bounding box. Default is to use
            land_polygons.bounding_box. If land_polygons is None, then this is
            the whole world, defined by ((-180,-90),(180, 90))
        :param viewport: viewport of map -- what gets drawn and on what scale.
            Default is to set viewport = map_BB
        :param image_mode: Image mode ('P' for palette or 'L' for Black and
            White image). BW_MapCanvas inherits from MapCanvas and sets the
            mode to 'L'. Default image_mode is 'P'.
        """

        # set up the canvas

        self._filename = filename

        if filename is not None:
            polygons = haz_files.ReadBNA(filename, "PolygonSet")
        else:
            polygons = None

        self.images_dir = images_dir
        self.last_filename = ""
        self.draw_ontop = draw_ontop
        self.draw_back_to_fore = draw_back_to_fore

        Outputter.__init__(
            self,
            cache,
            kwargs.pop("on", True),
            output_timestep,
            output_zero_step,
            output_last_step,
            kwargs.pop("name", None),
        )

        MapCanvas.__init__(self, image_size, land_polygons=polygons, **kwargs)
Example #18
0
def test_projection(output_dir):
    """
    draw the "same sized" rectangle at three latitudes to see how the look
    """
    mc = MapCanvas((400, 400), preset_colors='web')

    mc.viewport = ((-20, 25), (20, 65))
    mc.draw_polygon(((-15, 60),
                     (15, 60),
                     (15, 30),
                     (-15, 30)),
                    fill_color='maroon',
                    line_color='black')

    mc.save_foreground(os.path.join(output_dir, "image_projection_north.png"))

    mc.viewport = ((-20, -20), (20, 20))
    mc.draw_polygon(((-15, 15),
                     (15, 15),
                     (15, -15),
                     (-15, -15)
                     ),
                    fill_color='maroon',
                    line_color='black')

    mc.save_foreground(os.path.join(output_dir,
                                    "image_projection_equator.png"))

    mc.viewport = ((-20, -45), (20, -90))
    mc.draw_polygon(((-15, -80),
                     (15, -80),
                     (15, -50),
                     (-15, -50)),
                    fill_color='maroon',
                    line_color='black')

    mc.save_foreground(os.path.join(output_dir, "image_projection_south.png"))
Example #19
0
    def __init__(self,
                 map_filename=None,
                 output_dir='./',
                 image_size=(800, 600),
                 projection=None,
                 viewport=None,
                 map_BB=None,
                 land_polygons=None,
                 draw_back_to_fore=True,
                 draw_map_bounds=False,
                 draw_spillable_area=False,
                 formats=['png', 'gif'],
                 draw_ontop='forecast',
                 cache=None,
                 output_timestep=None,
                 output_zero_step=True,
                 output_last_step=True,
                 output_start_time=None,
                 on=True,
                 timestamp_attrib={},
                 **kwargs
                 ):
        """
        Init the image renderer.

        :param str map_filename=None: name of file for basemap (BNA)
        :type map_filename: str

        :param str output_dir='./': directory to output the images

        :param 2-tuple image_size=(800, 600): size of images to output

        :param projection=None: projection instance to use: If None,
                                set to projections.FlatEarthProjection()
        :type projection: a gnome.utilities.projection.Projection instance

        :param viewport: viewport of map -- what gets drawn and on what scale.
                         Default is full globe: (((-180, -90), (180, 90)))
                         If not specifies, it will be set to the map's bounds.
        :type viewport: pair of (lon, lat) tuples ( lower_left, upper right )

        :param map_BB=None: bounding box of map if None, it will use the
                            bounding box of the mapfile.

        :param draw_back_to_fore=True: draw the background (map) to the
                                       foregound image when outputting
                                       the images each time step.
        :type draw_back_to_fore: boolean

        :param formats=['gif']: list of formats to output.
        :type formats: string or list of strings. Options are:
                       ['bmp', 'jpg', 'jpeg', 'gif', 'png']

        :param draw_ontop: draw 'forecast' or 'uncertain' LEs on top. Default
            is to draw 'forecast' LEs, which are in black on top
        :type draw_ontop: str

        Following args are passed to base class Outputter's init:

        :param cache: sets the cache object from which to read prop. The model
            will automatically set this param

        :param output_timestep: default is None in which case everytime the
            write_output is called, output is written. If set, then output is
            written every output_timestep starting from model_start_time.
        :type output_timestep: timedelta object

        :param output_zero_step: default is True. If True then output for
            initial step (showing initial release conditions) is written
            regardless of output_timestep
        :type output_zero_step: boolean

        :param output_last_step: default is True. If True then output for
            final step is written regardless of output_timestep
        :type output_last_step: boolean

        Remaining kwargs are passed onto baseclass's __init__ with a direct
        call: Outputter.__init__(..)

        """
        projection = (projections.FlatEarthProjection()
                      if projection is None
                      else projection)

        # set up the canvas
        self.map_filename = map_filename
        self.output_dir = output_dir

        if map_filename is not None and land_polygons is None:
            self.land_polygons = haz_files.ReadBNA(map_filename, 'PolygonSet')
        elif land_polygons is not None:
            self.land_polygons = land_polygons
        else:
            self.land_polygons = []  # empty list so we can loop thru it

        self.last_filename = ''
        self.draw_ontop = draw_ontop
        self.draw_back_to_fore = draw_back_to_fore

        Outputter.__init__(self,
                           cache,
                           on,
                           output_timestep,
                           output_zero_step,
                           output_last_step,
                           output_start_time,
                           output_dir,
                           **kwargs)

        if map_BB is None:
            if not self.land_polygons:
                map_BB = ((-180, -90), (180, 90))
            else:
                map_BB = self.land_polygons.bounding_box

        self.map_BB = map_BB

        viewport = self.map_BB if viewport is None else viewport
        MapCanvas.__init__(self, image_size, projection=projection,
                           viewport=viewport)

        # assorted rendering flags:
        self.draw_map_bounds = draw_map_bounds
        self.draw_spillable_area = draw_spillable_area

        self.raster_map = None
        self.raster_map_fill = True
        self.raster_map_outline = False

        # initilize the images:
        self.add_colors(self.map_colors)
        self.background_color = 'background'

        if self.map_filename is not None:
            file_prefix = os.path.splitext(self.map_filename)[0]
            sep = '_'
        else:
            file_prefix = sep = ''

        fn = '{}{}anim.gif'.format(file_prefix, sep)
        self.anim_filename = os.path.join(output_dir, fn)

        self.formats = formats
        self.delay = 50
        self.repeat = True
        self.timestamp_attribs = {}

        self.set_timestamp_attrib(**timestamp_attrib)

        self.grids = []
        self.props = []
Example #20
0
    def __init__(self,
                 filename=None,
                 images_dir='./',
                 image_size=(800, 600),
                 cache=None,
                 output_timestep=None,
                 output_zero_step=True,
                 output_last_step=True,
                 draw_ontop='forecast',
                 draw_back_to_fore=True,
                 **kwargs):
        """
        Init the image renderer.

        Following args are passed to base class Outputter's init:

        :param filename: the name of the image file

        :param images_dir: the folder in which to write the image

        :param image_size: the width and height of the image

        :param cache: sets the cache object from which to read data. The model
            will automatically set this param

        :param output_timestep: default is None in which case everytime the
            write_output is called, output is written. If set, then output is
            written every output_timestep starting from model_start_time.
        :type output_timestep: timedelta object

        :param output_zero_step: default is True. If True then output for
            initial step (showing initial release conditions) is written
            regardless of output_timestep
        :type output_zero_step: boolean

        :param output_last_step: default is True. If True then output for
            final step is written regardless of output_timestep
        :type output_last_step: boolean

        :param draw_ontop: draw 'forecast' or 'uncertain' LEs on top. Default
            is to draw 'forecast' LEs, which are in black on top
        :type draw_ontop: str

        :param draw_back_to_fore=True: draw the background (map) to the
            foregound image when drawing Elements.
        :type draw_ontop: boolean

        Remaining kwargs are passed onto baseclass's __init__ with a direct
        call: MapCanvas.__init__(..)

        Optional parameters (kwargs)

        :param projection_class: gnome.utilities.projections class to use.
            Default is gnome.utilities.projections.FlatEarthProjection
        :param map_BB:  map bounding box. Default is to use
            land_polygons.bounding_box. If land_polygons is None, then this is
            the whole world, defined by ((-180,-90),(180, 90))
        :param viewport: viewport of map -- what gets drawn and on what scale.
            Default is to set viewport = map_BB
        :param image_mode: Image mode ('P' for palette or 'L' for Black and
            White image). BW_MapCanvas inherits from MapCanvas and sets the
            mode to 'L'. Default image_mode is 'P'.
        """

        # set up the canvas

        self._filename = filename

        if filename is not None:
            polygons = haz_files.ReadBNA(filename, 'PolygonSet')
        else:
            polygons = None

        self.images_dir = images_dir
        self.last_filename = ''
        self.draw_ontop = draw_ontop
        self.draw_back_to_fore = draw_back_to_fore

        Outputter.__init__(self,
                           cache,
                           kwargs.pop('on', True),
                           output_timestep,
                           output_zero_step,
                           output_last_step,
                           kwargs.pop('name', None))

        MapCanvas.__init__(self,
                           image_size,
                           land_polygons=polygons,
                           **kwargs)