Пример #1
0
    def test_querylayer_time_category(self):
        """layer.QueryLayer time with categories"""
        querylayer = QueryLayer(self.query, time='timecol', color='colorcol')
        # category type
        querylayer.style_cols['colorcol'] = 'string'
        querylayer.style_cols['timecol'] = 'date'

        # if non-point geoms are present (or None), raise an error
        with self.assertRaises(
                ValueError,
                msg='cannot make torque map with non-point geometries'):
            querylayer._setup([BaseMap(), querylayer], 1)  # pylint: disable=protected-access

        querylayer.geom_type = 'point'
        # normal behavior for point geometries
        querylayer._setup([BaseMap(), querylayer], 1)  # pylint: disable=protected-access
        self.assertDictEqual(
            querylayer.scheme,
            dict(name='Antique',
                 bin_method='',
                 bins=[str(i) for i in range(1, 11)]))
        # expect category maps query
        self.assertRegexpMatches(
            querylayer.query, r'(?s)^SELECT\norig\.\*,\s__wrap\.'
            r'cf_value_colorcol\n.*GROUP\sBY.*orig\.'
            r'colorcol$')
        # cartocss should have cdb math mode
        self.assertRegexpMatches(querylayer.cartocss,
                                 r'.*CDB_Math_Mode\(cf_value_colorcol\).*')
Пример #2
0
    def test_querylayer_time_errors(self):
        """layer.QueryLayer time option exceptions"""

        # time str column cannot be the_geom
        with self.assertRaises(ValueError,
                               msg='time column cannot be `the_geom`'):
            QueryLayer(self.query, time='the_geom')

        # time dict must have a 'column' key
        with self.assertRaises(ValueError,
                               msg='time dict must have a `column` key'):
            QueryLayer(self.query, time={'scheme': styling.armyRose(10)})

        # pass an int as the time column
        with self.assertRaises(ValueError,
                               msg='`time` key has to be a str or dict'):
            QueryLayer(self.query, time=7)

        with self.assertRaises(ValueError):
            querylayer = QueryLayer('select * from watermelon', time='seeds')
            querylayer.style_cols['seeds'] = 'string'
            querylayer.geom_type = 'point'
            querylayer._setup([BaseMap(), querylayer], 1)  # pylint: disable=protected-access

        with self.assertRaises(ValueError):
            querylayer = QueryLayer('select * from watermelon', time='seeds')
            querylayer.style_cols['seeds'] = 'date'
            querylayer.geom_type = 'polygon'
            querylayer._setup([BaseMap(), querylayer], 1)  # pylint: disable=protected-access
Пример #3
0
    def test_querylayer_time_category(self):
        """layer.QueryLayer time with categories"""
        ql = QueryLayer(self.query, time='timecol', color='colorcol')
        # category type
        ql.style_cols['colorcol'] = 'string'
        ql.style_cols['timecol'] = 'date'

        # if non-point geoms are present (or None), raise an error
        with self.assertRaises(
                ValueError,
                msg='cannot make torque map with non-point geometries'):
            ql._setup([BaseMap(), ql], 1)

        ql.geom_type = 'point'
        # normal behavior for point geometries
        ql._setup([BaseMap(), ql], 1)
        self.assertDictEqual(
            ql.scheme,
            dict(name='Antique',
                 bin_method='',
                 bins=','.join(str(i) for i in range(1, 11))))
        # expect category maps query
        self.assertRegexpMatches(
            ql.query, '^SELECT orig\.\*, '
            '__wrap.cf_value_colorcol.* '
            'GROUP BY.*orig\.colorcol$')
        # cartocss should have cdb math mode
        self.assertRegexpMatches(ql.cartocss,
                                 '.*CDB_Math_Mode\(cf_value_colorcol\).*')
Пример #4
0
    def test_basemap_invalid(self):
        """layer.Basemap exceptions on invalid source"""
        # Raise ValueError if invalid label is entered
        with self.assertRaises(ValueError):
            BaseMap(labels='watermelon')

        # Raise ValueError if custom URL is entered
        with self.assertRaises(ValueError):
            BaseMap(source='http://spinalmap.com/{z}/{x}/{y}.png')

        # Raise ValueError if non-supported style type is entered
        with self.assertRaises(ValueError):
            BaseMap(source='gulab_jamon')
Пример #5
0
    def setUp(self):
        self.layers = [
            BaseMap('dark'),
            Layer('cb_2013_puma10_500k', color='grey'),
            Layer('tweets_obama', color='yellow', size='favoritescount')
        ]

        self.layers_w_time = [
            BaseMap('dark', labels='front'),
            Layer('acadia'),
            QueryLayer('select * from acadia limit 10', time='foo'),
            Layer('biodiversity'),
            BaseMap('dark', labels='front', only_labels=True)
        ]
Пример #6
0
 def test_querylayer_get_cartocss(self):
     """layer.QueryLayer._get_cartocss"""
     qlayer = QueryLayer(self.query,
                         size=dict(column='cold_brew', min=10, max=20))
     self.assertRegexpMatches(
         qlayer._get_cartocss(BaseMap()),
         ('.*marker-width:\sramp\(\[cold_brew\],\srange\(10,20\),\s'
          'quantiles\(5\)\).*'))
Пример #7
0
    def setUp(self):
        # basemaps with baked-in labels
        self.dark_map_all = BaseMap(source='dark')
        self.light_map_all = BaseMap(source='light')

        # basemaps with no labels
        self.dark_map_no_labels = BaseMap(source='dark', labels=None)
        self.light_map_no_labels = BaseMap(source='light', labels=None)

        # labels with no basemaps
        self.dark_only_labels = BaseMap(source='dark', only_labels=True)
        self.light_only_labels = BaseMap(source='light', only_labels=True)
Пример #8
0
    def test_querylayer_get_cartocss(self):
        """layer.QueryLayer._get_cartocss"""
        qlayer = QueryLayer(self.query,
                            size=dict(column='cold_brew', min=10, max=20))
        qlayer.geom_type = 'point'
        self.assertRegexpMatches(
            qlayer._get_cartocss(BaseMap()),  # pylint: disable=protected-access
            (r'.*marker-width:\sramp\(\[cold_brew\],\srange\(10,20\),\s'
             r'quantiles\(5\)\).*'))

        # test line cartocss
        qlayer = QueryLayer(self.query)
        qlayer.geom_type = 'line'
        self.assertRegexpMatches(
            qlayer._get_cartocss(BaseMap()),  # pylint: disable=protected-access
            r'^\#layer.*line\-width.*$')
        # test point, line, polygon
        for geom in (
                'point',
                'line',
                'polygon',
        ):
            styles = {
                'point': r'marker\-fill',
                'line': r'line\-color',
                'polygon': r'polygon\-fill'
            }
            qlayer = QueryLayer(self.query, color='colname')
            qlayer.geom_type = geom
            self.assertRegexpMatches(
                qlayer._get_cartocss(BaseMap()),  # pylint: disable=protected-access
                r'^\#layer.*{}.*\}}$'.format(styles[geom]))

        # geometry type should be defined
        with self.assertRaises(ValueError, msg='invalid geometry type'):
            querylayer = QueryLayer(self.query, color='red')
            querylayer.geom_type = 'notvalid'
            querylayer._get_cartocss(BaseMap())  # pylint: disable=protected-access
Пример #9
0
    def test_querylayer_time_numeric(self):
        """layer.QueryLayer time with quantitative classification"""
        querylayer = QueryLayer(self.query, time='timecol', color='colorcol')
        # category type
        querylayer.style_cols['colorcol'] = 'number'
        querylayer.style_cols['timecol'] = 'date'
        querylayer.geom_type = 'point'

        # normal behavior for point geometries
        querylayer._setup([BaseMap(), querylayer], 1)  # pylint: disable=protected-access
        self.assertDictEqual(querylayer.scheme, styling.mint(5))
        # expect category maps query
        self.assertRegexpMatches(querylayer.query.strip(),
                                 r'^SELECT \*, colorcol as value '
                                 r'.*_wrap$')
        # cartocss should have cdb math mode
        self.assertRegexpMatches(querylayer.cartocss, r'.*avg\(colorcol\).*')
Пример #10
0
    def test_non_basemap_layers(self):
        """maps.non_basemap_layers"""
        nbm_layers = non_basemap_layers(self.layers)
        # ensure the layers are separated out correctly
        self.assertEqual(self.layers[1],
                         nbm_layers[0],
                         msg=('first non-basemap layer should be second layer '
                              'in original layer list'))

        self.assertEqual(self.layers[2],
                         nbm_layers[1],
                         msg=('second non-basemap layer should be third layer '
                              'in original layer list'))

        # correct number of layers passed out
        self.assertEqual(len(nbm_layers), 2)

        # If no data layers exist, non_basemap_layers should be an empty list
        nbm_no_layers = non_basemap_layers([BaseMap()])
        self.assertEqual(len(nbm_no_layers), 0)

        # If nothing is passed
        nbm_nothing = non_basemap_layers([])
        self.assertEqual(len(nbm_nothing), 0)
Пример #11
0
    def map(self, layers=None, interactive=True,
            zoom=None, lat=None, lng=None, size=(800, 400),
            ax=None):
        """Produce a CARTO map visualizing data layers.

        Example:
            Create a map with two data layers, and one BaseMap layer.
            ::

                import cartoframes
                from cartoframes import Layer, BaseMap, styling
                cc = cartoframes.CartoContext(BASEURL, APIKEY)
                cc.map(layers=[BaseMap(),
                               Layer('acadia_biodiversity',
                                     color={'column': 'simpson_index',
                                            'scheme': styling.tealRose(7)}),
                               Layer('peregrine_falcon_nest_sites',
                                     size='num_eggs',
                                     color={'column': 'bird_id',
                                            'scheme': styling.vivid(10))],
                       interactive=True)
        Args:
            layers (list, optional): List of one or more of the following:

                - Layer: cartoframes Layer object for visualizing data from a
                  CARTO table. See `layer.Layer <#layer.Layer>`__ for all
                  styling options.
                - BaseMap: Basemap for contextualizng data layers. See
                  `layer.BaseMap <#layer.BaseMap>`__ for all styling options.
                - QueryLayer: Layer from an arbitrary query. See
                  `layer.QueryLayer <#layer.QueryLayer>`__ for all styling
                  options.

            interactive (bool, optional): Defaults to ``True`` to show an
                interactive slippy map. Setting to ``False`` creates a static
                map.
            zoom (int, optional): Zoom level of map. Acceptable values are
                usually in the range 0 to 19. 0 has the entire earth on a
                single tile (256px square). Zoom 19 is the size of a city
                block. Must be used in conjunction with ``lng`` and ``lat``.
                Defaults to a view to have all data layers in view.
            lat (float, optional): Latitude value for the center of the map.
                Must be used in conjunction with ``zoom`` and ``lng``. Defaults
                to a view to have all data layers in view.
            lng (float, optional): Longitude value for the center of the map.
                Must be used in conjunction with ``zoom`` and ``lat``. Defaults
                to a view to have all data layers in view.
            size (tuple, optional): List of pixel dimensions for the map. Format
                is ``(width, height)``. Defaults to ``(800, 400)``.

        Returns:
            IPython.display.HTML: Interactive maps are rendered in an ``iframe``,
            while static maps are rendered in ``img`` tags.
        """
        # TODO: add layers preprocessing method like
        #       layers = process_layers(layers)
        #       that uses up to layer limit value error
        if not hasattr(IPython, 'display'):
            raise NotImplementedError('Nope, cannot display maps at the '
                                      'command line.')

        if layers is None:
            layers = []
        elif not isinstance(layers, collections.Iterable):
            layers = [layers]
        else:
            layers = list(layers)

        if len(layers) > 8:
            raise ValueError('map can have at most 8 layers')

        if any([zoom, lat, lng]) != all([zoom, lat, lng]):
            raise ValueError('zoom, lat, and lng must all or none be provided')

        # When no layers are passed, set default zoom
        if ((len(layers) == 0 and zoom is None) or
                (len(layers) == 1 and layers[0].is_basemap)):
            [zoom, lat, lng] = [3, 38, -99]
        has_zoom = zoom is not None

        # Check basemaps, add one if none exist
        base_layers = [idx for idx, layer in enumerate(layers)
                       if layer.is_basemap]
        if len(base_layers) > 1:
            raise ValueError('map can at most take 1 BaseMap layer')
        if len(base_layers) > 0:
            layers.insert(0, layers.pop(base_layers[0]))
        else:
            layers.insert(0, BaseMap())

        # Check for a time layer, if it exists move it to the front
        time_layers = [idx for idx, layer in enumerate(layers)
                       if not layer.is_basemap and layer.time]
        time_layer = layers[time_layers[0]] if len(time_layers) > 0 else None
        if len(time_layers) > 1:
            raise ValueError('Map can at most take 1 Layer with time '
                             'column/field')
        if time_layer:
            raise NotImplementedError('Animated maps are not yet supported')
            if not interactive:
                raise ValueError('map cannot display a static image with a '
                                 'time_column')
            layers.append(layers.pop(time_layers[0]))

        # If basemap labels are on front, add labels layer
        basemap = layers[0]
        if basemap.is_basic() and basemap.labels == 'front':
            layers.append(BaseMap(basemap.source,
                                  labels=basemap.labels,
                                  only_labels=True))

        # Setup layers
        for idx, layer in enumerate(layers):
            layer._setup(layers, idx)

        nb_layers = non_basemap_layers(layers)
        options = {'basemap_url': basemap.url}

        for idx, layer in enumerate(nb_layers):
            self._check_query(layer.query,
                              style_cols=layer.style_cols)
            options['cartocss_' + str(idx)] = layer.cartocss
            options['sql_' + str(idx)] = layer.query


        params = {
            'config': json.dumps(options),
            'anti_cache': random.random(),
        }

        if has_zoom:
            params.update({'zoom': zoom, 'lat': lat, 'lon': lng})
            options.update({'zoom': zoom, 'lat': lat, 'lng': lng})
        else:
            options.update(self._get_bounds(nb_layers))

        map_name = self._send_map_template(layers, has_zoom=has_zoom)
        api_url = '{base_url}api/v1/map'.format(base_url=self.base_url)

        static_url = ('{api_url}/static/named/{map_name}'
                      '/{width}/{height}.png?{params}').format(
                          api_url=api_url,
                          map_name=map_name,
                          width=size[0],
                          height=size[1],
                          params=urlencode(params))

        html = '<img src="{url}" />'.format(url=static_url)

        # TODO: write this as a private method
        if interactive:
            netloc = urlparse(self.base_url).netloc
            domain = 'carto.com' if netloc.endswith('.carto.com') else netloc

            def safe_quotes(text, escape_single_quotes=False):
                """htmlify string"""
                if isinstance(text, str):
                    safe_text = text.replace('"', "&quot;")
                    if escape_single_quotes:
                        safe_text = safe_text.replace("'", "&#92;'")
                    return safe_text.replace('True', 'true')
                return text

            config = {
                'user_name': self.username,
                'maps_api_template': self.base_url[:-1],
                'sql_api_template': self.base_url[:-1],
                'tiler_protocol': 'https',
                'tiler_domain': domain,
                'tiler_port': '80',
                'type': 'torque' if time_layer else 'namedmap',
                'named_map': {
                    'name': map_name,
                    'params': {
                        k: safe_quotes(v, escape_single_quotes=True)
                        for k, v in dict_items(options)
                    },
                },
            }

            map_options = {
                'filter': ['http', 'mapnik', 'torque'],
                'https': True,
            }

            if time_layer:
                config.update({
                    'order': 1,
                    'options': {
                        'query': time_layer.query,
                        'user_name': self.username,
                        'tile_style': time_layer.torque_cartocss,
                    }
                })
                config['named_map'].update({
                    'layers': [{
                        'layer_name': 't',
                    }],
                })
                map_options.update({
                    'time_slider': True,
                    'loop': True,
                })
            bounds = [] if has_zoom else [[options['north'], options['east']],
                                          [options['south'], options['west']]]

            content = self._get_iframe_srcdoc(config=config,
                                              bounds=bounds,
                                              options=options,
                                              map_options=map_options)

            img_html = html
            html = (
                '<iframe srcdoc="{content}" width={width} height={height}>'
                '  Preview image: {img_html}'
                '</iframe>'
            ).format(content=safe_quotes(content),
                     width=size[0],
                     height=size[1],
                     img_html=img_html)
            return IPython.display.HTML(html)
        else:
            try:
                import matplotlib.image as mpi
                import matplotlib.pyplot as plt
            except ImportError:
                warn('Matplotlib not detected. Saving image directly to disk')
                raise NotImplementedError
            raw_data = mpi.imread(static_url)
            f = plt.gcf()
            if ax is None:
                ax = plt.gca()
            ax.imshow(raw_data)
            ax.axis('off')
            return ax
Пример #12
0
class TestBaseMap(unittest.TestCase):
    """Tests for functions in keys module"""
    def setUp(self):
        # basemaps with baked-in labels
        self.dark_map_all = BaseMap(source='dark')
        self.light_map_all = BaseMap(source='light')

        # basemaps with no labels
        self.dark_map_no_labels = BaseMap(source='dark', labels=None)
        self.light_map_no_labels = BaseMap(source='light', labels=None)

        # labels with no basemaps
        self.dark_only_labels = BaseMap(source='dark', only_labels=True)
        self.light_only_labels = BaseMap(source='light', only_labels=True)

    def test_basemap_invalid(self):
        """layer.Basemap exceptions on invalid source"""
        # Raise ValueError if invalid label is entered
        with self.assertRaises(ValueError):
            BaseMap(labels='watermelon')

        # Raise ValueError if custom URL is entered
        with self.assertRaises(ValueError):
            BaseMap(source='http://spinalmap.com/{z}/{x}/{y}.png')

        # Raise ValueError if non-supported style type is entered
        with self.assertRaises(ValueError):
            BaseMap(source='gulab_jamon')

    def test_basemap_source(self):
        """layer.BaseMap with different sources and labels"""

        # ensure correct BaseMap urls are created
        # See URLs here: https://carto.com/location-data-services/basemaps/
        self.assertEqual(
            self.dark_map_all.url,
            'https://cartodb-basemaps-{s}.global.ssl.fastly.net/'
            'dark_all/{z}/{x}/{y}.png')
        self.assertEqual(
            self.light_map_all.url,
            'https://cartodb-basemaps-{s}.global.ssl.fastly.net/'
            'light_all/{z}/{x}/{y}.png')
        self.assertEqual(
            self.dark_map_no_labels.url,
            'https://cartodb-basemaps-{s}.global.ssl.fastly.net/'
            'dark_nolabels/{z}/{x}/{y}.png')
        self.assertEqual(
            self.light_map_no_labels.url,
            'https://cartodb-basemaps-{s}.global.ssl.fastly.net/'
            'light_nolabels/{z}/{x}/{y}.png')
        self.assertEqual(
            self.light_only_labels.url,
            'https://cartodb-basemaps-{s}.global.ssl.fastly.net/'
            'light_only_labels/{z}/{x}/{y}.png')
        self.assertEqual(
            self.dark_only_labels.url,
            'https://cartodb-basemaps-{s}.global.ssl.fastly.net/'
            'dark_only_labels/{z}/{x}/{y}.png')

        # ensure self.is_basic() works as intended
        self.assertTrue(self.light_map_all.is_basic(),
                        msg='is a basic carto basemap')
        self.assertTrue(self.dark_map_all.is_basic())
Пример #13
0
    def test_line_styling(self):  # pylint: disable=too-many-statements
        """layer.QueryLayer line styling"""
        linelayer = QueryLayer('select * from lines', size=5)

        linelayer.geom_type = 'line'
        linelayer._setup([BaseMap(), linelayer], 1)  # pylint: disable=protected-access

        self.assertTrue('line-width: 5' in linelayer.cartocss)

        size = 'size_col'
        color = 'mag'
        linelayer = QueryLayer('select * from lines', size=size, color=color)

        linelayer.geom_type = 'line'
        linelayer.style_cols['mag'] = 'number'
        linelayer.style_cols['size_col'] = 'number'
        linelayer._setup([BaseMap(), linelayer], 1)  # pylint: disable=protected-access

        self.assertTrue(
            'line-width: ramp([size_col], range(1,5), quantiles(5))' in
            linelayer.cartocss)

        self.assertTrue(
            'line-color: ramp([mag], cartocolor(Mint), quantiles(5), >)' in
            linelayer.cartocss)

        size = {'column': 'size_col'}
        color = 'mag'
        linelayer = QueryLayer('select * from lines', size=size, color=color)

        linelayer.geom_type = 'line'
        linelayer.style_cols['mag'] = 'number'
        linelayer.style_cols['size_col'] = 'number'
        linelayer._setup([BaseMap(), linelayer], 1)  # pylint: disable=protected-access

        self.assertTrue(
            'line-width: ramp([size_col], range(1,5), quantiles(5))' in
            linelayer.cartocss)

        self.assertTrue(
            'line-color: ramp([mag], cartocolor(Mint), quantiles(5), >)' in
            linelayer.cartocss)

        size = {'column': 'size_col', 'range': (5, 10)}
        color = 'mag'
        linelayer = QueryLayer('select * from lines', size=size, color=color)
        linelayer.geom_type = 'line'
        linelayer.style_cols['mag'] = 'number'
        linelayer.style_cols['size_col'] = 'number'
        linelayer._setup([BaseMap(), linelayer], 1)  # pylint: disable=protected-access

        self.assertTrue(
            'line-width: ramp([size_col], range(5,10), quantiles(5))' in
            linelayer.cartocss)

        self.assertTrue(
            'line-color: ramp([mag], cartocolor(Mint), quantiles(5), >)' in
            linelayer.cartocss)

        size = 1.5
        color = 'mag'

        linelayer = QueryLayer('select * from lines', size=size, color=color)

        linelayer.geom_type = 'line'
        linelayer.style_cols['mag'] = 'number'
        linelayer.style_cols['size_col'] = 'number'
        linelayer._setup([BaseMap(), linelayer], 1)  # pylint: disable=protected-access

        self.assertTrue('line-width: 1.5' in linelayer.cartocss)

        self.assertTrue(
            'line-color: ramp([mag], cartocolor(Mint), quantiles(5), >)' in
            linelayer.cartocss)

        size = {'column': 'size_col', 'range': [2, 6]}

        color = {'column': 'mag', 'scheme': styling.sunset(7)}

        linelayer = QueryLayer('select * from lines', size=size, color=color)

        linelayer.geom_type = 'line'
        linelayer.style_cols['mag'] = 'number'
        linelayer.style_cols['size_col'] = 'number'
        linelayer._setup([BaseMap(), linelayer], 1)  # pylint: disable=protected-access

        self.assertTrue(
            'line-width: ramp([size_col], range(2,6), quantiles(5))' in
            linelayer.cartocss)

        self.assertTrue(
            'line-color: ramp([mag], cartocolor(Sunset), quantiles(7), >)' in
            linelayer.cartocss)

        # size and color
        size = {
            'column': 'size_col',
            'range': [2, 6],
            'bin_method': BinMethod.jenks
        }
        color = {'column': 'mag', 'scheme': styling.sunset(7)}

        linelayer = QueryLayer('select * from lines', size=size, color=color)

        linelayer.geom_type = 'line'
        linelayer.style_cols['mag'] = 'number'
        linelayer.style_cols['size_col'] = 'number'
        linelayer._setup([BaseMap(), linelayer], 1)  # pylint: disable=protected-access

        self.assertTrue('line-width: ramp([size_col], range(2,6), jenks(5))' in
                        linelayer.cartocss)

        self.assertTrue(
            'line-color: ramp([mag], cartocolor(Sunset), quantiles(7), >)' in
            linelayer.cartocss)

        # category lines

        linelayer = QueryLayer('select * from lines',
                               color={
                                   'column': 'mag',
                                   'scheme': styling.antique(7)
                               })

        linelayer.geom_type = 'line'

        linelayer._setup([BaseMap(), linelayer], 1)  # pylint: disable=protected-access

        self.assertTrue(
            'line-color: ramp([mag], cartocolor(Antique), category(7), =)' in
            linelayer.cartocss)
Пример #14
0
class TestBaseMap(unittest.TestCase):  # pylint: disable=too-many-instance-attributes
    """Tests for functions in keys module"""
    def setUp(self):
        # basemaps with baked-in labels
        self.dark_map_all = BaseMap(source='dark')
        self.light_map_all = BaseMap(source='light')
        self.voyager_labels_under = BaseMap(source='voyager')

        # basemaps with no labels
        self.dark_map_no_labels = BaseMap(source='dark', labels=None)
        self.light_map_no_labels = BaseMap(source='light', labels=None)
        self.voyager_map_no_labels = BaseMap(source='voyager', labels=None)

        # labels with no basemaps
        self.dark_only_labels = BaseMap(source='dark', only_labels=True)
        self.light_only_labels = BaseMap(source='light', only_labels=True)
        self.voyager_only_labels = BaseMap(source='voyager', only_labels=True)

    def test_basemap_repr(self):
        """layer.Basemap.__repr__"""
        self.assertEqual(
            self.dark_only_labels.__repr__(),
            'BaseMap(source=dark, labels=back, only_labels=True)')

    def test_basemap_invalid(self):
        """layer.Basemap exceptions on invalid source"""
        # Raise ValueError if invalid label is entered
        with self.assertRaises(ValueError):
            BaseMap(labels='watermelon')

        # Raise ValueError if custom URL is entered
        with self.assertRaises(ValueError):
            BaseMap(source='http://spinalmap.com/{z}/{x}/{y}.png')

        # Raise ValueError if non-supported style type is entered
        with self.assertRaises(ValueError):
            BaseMap(source='gulab_jamon')

    def test_basemap_source(self):
        """layer.BaseMap with different sources and labels"""

        # ensure correct BaseMap urls are created
        # See URLs here: https://carto.com/location-data-services/basemaps/
        self.assertEqual(
            self.dark_map_all.url,
            'https://{s}.basemaps.cartocdn.com/rastertiles/'
            'dark_all/{z}/{x}/{y}.png')
        self.assertEqual(
            self.light_map_all.url,
            'https://{s}.basemaps.cartocdn.com/rastertiles/'
            'light_all/{z}/{x}/{y}.png')
        self.assertEqual(
            self.voyager_labels_under.url,
            'https://{s}.basemaps.cartocdn.com/rastertiles/'
            'voyager_labels_under/{z}/{x}/{y}.png')
        self.assertEqual(
            self.dark_map_no_labels.url,
            'https://{s}.basemaps.cartocdn.com/rastertiles/'
            'dark_nolabels/{z}/{x}/{y}.png')
        self.assertEqual(
            self.light_map_no_labels.url,
            'https://{s}.basemaps.cartocdn.com/rastertiles/'
            'light_nolabels/{z}/{x}/{y}.png')
        self.assertEqual(
            self.voyager_map_no_labels.url,
            'https://{s}.basemaps.cartocdn.com/rastertiles/'
            'voyager_nolabels/{z}/{x}/{y}.png')
        self.assertEqual(
            self.light_only_labels.url,
            'https://{s}.basemaps.cartocdn.com/rastertiles/'
            'light_only_labels/{z}/{x}/{y}.png')
        self.assertEqual(
            self.dark_only_labels.url,
            'https://{s}.basemaps.cartocdn.com/rastertiles/'
            'dark_only_labels/{z}/{x}/{y}.png')
        self.assertEqual(
            self.voyager_only_labels.url,
            'https://{s}.basemaps.cartocdn.com/rastertiles/'
            'voyager_only_labels/{z}/{x}/{y}.png')

        # ensure self.is_basic() works as intended
        self.assertTrue(self.light_map_all.is_basic(),
                        msg='is a basic carto basemap')
        self.assertTrue(self.dark_map_all.is_basic())
        self.assertTrue(self.voyager_labels_under.is_basic(),
                        msg='is a basic carto basemap')
Пример #15
0
    def test_layer_setup_dataframe(self):
        """layer.Layer._setup()"""
        layer = Layer('cortado', source=self.coffee_temps)

        with self.assertRaises(NotImplementedError):
            layer._setup([BaseMap(), layer], 1)  # pylint: disable=protected-access
Пример #16
0
    def test_querylayer_colors(self):
        """layer.QueryLayer color options tests"""

        # no color options passed
        basic = QueryLayer(self.query)
        self.assertEqual(basic.color, None)

        # check valid dict color options
        dict_colors = [{
            'column': 'mandrill',
            'scheme': styling.armyRose(7)
        }, {
            'column': 'mercxx',
            'scheme': {
                'bin_method': 'equal',
                'bins': 7,
                'name': 'Temps'
            }
        }, {
            'column': 'elephant',
            'scheme': styling.redOr(10, bin_method='jenks')
        }]
        dict_colors_ans = ['mandrill', 'mercxx', 'elephant']
        dict_colors_scheme = [{
            'name': 'ArmyRose',
            'bins': 7,
            'bin_method': 'quantiles'
        }, {
            'name': 'Temps',
            'bins': 7,
            'bin_method': 'equal'
        }, {
            'name': 'RedOr',
            'bins': 10,
            'bin_method': 'jenks'
        }]
        for idx, val in enumerate(dict_colors):
            qlayer = QueryLayer(self.query, color=val)
            self.assertEqual(qlayer.color, dict_colors_ans[idx])
            self.assertEqual(qlayer.scheme, dict_colors_scheme[idx])

        # check valid string color options
        str_colors = ('#FF0000', 'aliceblue', 'cookie_monster', 'big_bird')
        str_colors_ans = ('#FF0000', 'aliceblue', 'cookie_monster', 'big_bird')
        str_scheme_ans = (None, None, styling.mint(5), styling.antique(10))

        for idx, color in enumerate(str_colors):
            qlayer = QueryLayer(self.query, color=color)
            qlayer.geom_type = 'point'
            if color == 'cookie_monster':
                qlayer.style_cols[color] = 'number'
                qlayer._setup([BaseMap(), qlayer], 1)  # pylint: disable=protected-access
            elif color == 'big_bird':
                qlayer.style_cols[color] = 'string'
                qlayer._setup([BaseMap(), qlayer], 1)  # pylint: disable=protected-access
            self.assertEqual(qlayer.color, str_colors_ans[idx])
            self.assertEqual(qlayer.scheme, str_scheme_ans[idx])

        with self.assertRaises(ValueError,
                               msg='styling value cannot be a date'):
            qlayer = QueryLayer(self.query, color='datetime_column')
            qlayer.style_cols['datetime_column'] = 'date'
            qlayer._setup([BaseMap(), qlayer], 1)  # pylint: disable=protected-access

        # Exception testing
        # color column cannot be a geometry column
        with self.assertRaises(ValueError,
                               msg='color clumn cannot be a geometry column'):
            QueryLayer(self.query, color='the_geom')

        # color dict must have a 'column' key
        with self.assertRaises(ValueError,
                               msg='color dict must have a `column` key'):
            QueryLayer(self.query, color={'scheme': styling.vivid(10)})