CARTOframes

A Python package for integrating CARTO maps, analysis, and data services into data science workflows.

Cartography

Map creation in cartoframes happens through the CartoContext.map method. This method takes a list of map layers, each with independent styling options. The layers can be a base map (BaseMap), table layer (Layer), or a query against data in the user’s CARTO account (QueryLayer). Each of the layers is styled independently and appear on the map in the order listed. Basemaps are an exception to this ordering rule: they always appear on the bottom regardless of its order in the list.

Base Maps

To create a map with only the BaseMap, do the following:

1
2
3
4
5
6
from cartoframes import CartoContext, BaseMap
cc = CartoContext(
    base_url='<your_base_url>',
    api_key='<your_api_key>'
)
cc.map(layers=BaseMap())

Or more simply, the last line can be made simpler because a base map is added by default if one is not provided:

1
cc.map()

This produces the following output:

To get a custom view, pass the longitude, latitude, and zoom as arguments to cc.map:

1
cc.map(lat=34.7982209, lng=113.6489703, zoom=11)

To change the base map style to CARTO’s ‘dark matter’, pass 'dark' to the BaseMap class:

1
cc.map(layers=BaseMap('dark'))

For a light base map, change the source to 'light'.

Remove labels with labels=None or put them in back with labels='back'.

Single Layer Map

To add a data layer to your map, first find a table you want to visualize.

We’re going to use the NYC Taxi dataset from cartoframes examples, which you can put into your account with this snippet:

1
2
3
4
5
6
7
from cartoframes.examples import read_taxi
# write taxi data to your account, setting the geometry as pickup location
cc.write(
    read_taxi(),
    'taxi_50k',
    lnglat=('pickup_longitude', 'pickup_latitude')
)

See the cartoframes Quickstart to cover basics used here.

1
2
3
4
cc.map(layers=[
    BaseMap('dark'),
    Layer('taxi_50k', color='fare_amount')
])

Map from a QueryLayer

Maps can be created from arbitrary queries of tables you have in your account. With our example taxi dataset, you may have noticed that there are two sets of long/lat coordinates: one for pickup location, another for dropoff location. We can use this information to draw a straight-line path and get this length. Of course, the real route would be more useful, but this isn’t in the data. We could simulate it with CARTO’s routing functions, but we’ll stick with the simpler example of straight-line paths for demonstration.

In this example, you’ll notice a few features:

  1. The line geometry is created with the PostGIS functions ST_MakeLine from points created with the cartodb-postgresql helper function CDB_LatLng](https://github.com/CartoDB/cartodb-postgresql/blob/master/scripts-available/CDB_LatLng.sql)
  2. We filter out locations at lnt/lat (0, 0) which are from null values
  3. We order by the distance (fourth in the SELECT) to make sure the shortest paths are drawn on top and not obscured by longer paths
  4. Color by the distance between the pick up and drop off locations
  5. Zoom into a location of interest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from cartoframes import QueryLayer
cc.map(
    QueryLayer('''
        SELECT
            ST_Transform(the_geom, 3857) AS the_geom_webmercator,
            the_geom,
            cartodb_id,
            ST_Length(the_geom::geography) AS distance
        FROM (
            SELECT
                ST_MakeLine(
                    CDB_LatLng(pickup_latitude, pickup_longitude),
                    CDB_LatLng(dropoff_latitude, dropoff_longitude)
                ) AS the_geom,
                cartodb_id
            FROM taxi_50k
            WHERE pickup_latitude <> 0 AND dropoff_latitude <> 0
        ) AS _w
        ORDER BY 4 DESC''',
        color='distance'),
    zoom=11, lng=-73.9442, lat=40.7473,
    interactive=False)

QueryLayers are a great way to take advantage of the relational database underlying CARTO without creating new datasets. For resource-intensive operations, it is recommended to first create a new dataset for visualization with Layer as it will offer better performance and be less likely to hit platform limits. To create new tables from queries, use CartoContext.query('<query>', table_name='<new_table_name>').

Multi-layer Map

To add more than one layer to your map, add them in the order you want the layers to display. Here we’re adding a base map using a light styling, a polygon layer of poverty rates in Brooklyn, and the taxi data for fares above $50 sized by the amount.

1
2
3
4
5
6
7
8
cc.map(layers=[
    BaseMap('light'),
    Layer('brooklyn_poverty', color='poverty_per_pop'),
    QueryLayer(
        'SELECT * FROM taxi_50k WHERE fare_amount > 50',
        size='fare_amount'
    )
])

Style Size by Variable

To style by size variable, use the size keyword at the layer level for each layer passed. This only work for point data.

This sizes each point the same size (3 pixels wide):

1
cc.map(layers=Layer('taxi_50k', size=3))

To size by a variable, pass a column name instead of a number:

1
2
3
4
5
cc.map(
    layers=Layer(
        'taxi_50k',
        size='fare_amount'
    ))

Just like the color keyword, the size option can take a dictionary.

1
2
3
4
5
6
7
8
9
10
11
cc.map(
    layers=Layer(
        'taxi_50k',
        size={
            'column': 'fare_amount',
            'min': 2,
            'max': 10,
            'bin_method': 'headtails'
        }
    )
)

Your results will look as follows:

Style Color by Variable

Styling values by color is similar to styling by size but using the color keyword in the Layer object instead. Color by value works for points, lines, and polygons.

Using the brooklyn_poverty dataset, we can style by poverty_per_pop:

1
2
from cartofrmaes import Layer
cc.map(Layer('brooklyn_poverty', color='poverty_per_pop'))

To specify a specific color scheme, we can expand the argument to color and using some of the color utility functions in the styling module:

1
2
3
4
5
6
7
8
from cartoframes import Layer, styling
cc.map(
    Layer(
        'brooklyn_poverty',
        color={'column': 'poverty_per_pop',
               'scheme': styling.sunset(7)}
    )
)

Animated Map

To style a map with time, use the time keyword on a numeric or time field in your dataset. Here we use the US Geological Survey data feed on earthquakes which has a time column.

To get this data into your CARTO account with CARTOframes, do the following:

1
2
3
import pandas as pd
eq_url = 'https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.csv'
cc.write(pd.read_csv(eq_url), 'usgs_all_month')

To visualize the data in time, specify the column that has the time information (in this case time). We can also style by color. Here we’re using the net column which is a category.

1
cc.map(Layer('usgs_all_month', time='time', color='net'))