Advanced Map Styling Techniques


This post may describe functionality for an old version of CARTO. Find out about the latest and cloud-native version here.
Advanced Map Styling Techniques

Recently I was working with an utility company that wanted to use CARTO as a web mapping platform replacement for the way they currently generate maps of their physical infrastructure: AutoCAD.

Maps in AutoCAD? Yes! As in many industries utilities have requirements for very precise and specific map designs. Sets of inlets connection points electrical components and pipes and cables can be housed close together or in intricate formations. It's important for field technicians to be able to tell the difference by looking at their maps which need to convey this level of detail and precision.

The utility company was hesitant about whether CARTO would suit their needs which included:

  • custom symbology
  • symbol rotation
  • custom labeling and label placement
  • a variety of line types (colored dashed etc)
  • rotation of the map from true North

These are intricate requirements we don't often see in web mapping but CARTO is more than capable and up to the job! Here's how we handled it all:

Custom Symbology

This was probably the simplest requirement. CARTO has three sets of interesting symbol icons for you to use with your maps straight out of the box but we also support uploading your own! SVG icons work best for multiple zoom levels and sizes but other image files work well too. In this case the utility had a set of common trade symbols to use for different categories of their infrastructure assets. See below a representative screenshot with four different types of symbol in play:

Custom Symbology

Symbol Rotation

Once we had custom symbol icons uploaded the next requirement was that these icons be rotated according to a "rotation angle" column in the dataset. This is important as some asset classes were placed along roadways that curve and turn and portraying their position and orientation was important to the client.

The rotation column had a simple number of degrees from 0 that each asset's record needed to be rotated by. CartoCSS is an extensive language with many symbolizers and properties beyond what most people commonly use. One of these is the [marker-transform property] which you can feed any SVG transformation function. What is an SVG transformation function? There are six mentioned in the W3C's SVG specification one of which is rotate(a x y). This function will rotate a graphic "a" degrees around a point (x y). Even though our markers are PNG and not SVG we can use this function in our CartoCSS along with our rotation column in our data for an appropriate rotation by record as seen below:


transformers[subtypecd=3] {

marker-file: url(; marker-width: 10; marker-transform: rotate([symbolrotation] 0 0); } ##_END_REPLACE_ME_PRE_##

Notice how well the rotated symbols follow the curvature of the road below!

Symbol Rotation

Custom Labeling and Label Placement

Utility maps can be information dense - not only is the symbology and positioning important but the text labels are too. Moreover this particular client had labels in their CAD maps split into two lines and composed of several data fields. This too is an intricate but doable job for CartoCSS using some basic string operations such as including an escaped newline character and concatenating a few fields in the "text-name" property. Due to the length of these labels we also set them to appear only at close zoom levels so they didn't overload the map. Also CartoCSS labels have the ability to be positioned in several compass rose directions and you can even specify an algorithm to try a few of these positions so the labels don't get drawn overlapping each other with the [text-allow-overlap] [text-placement-type] and [text-placements] properties.


transformers::labels [zoom >= 17] {

text-name: [facilityid] + "\n" + "-" + [operatingvoltage] + [phasedesignationdesc]; text-face-name: 'DejaVu Sans Book'; text-size: 10; text-label-position-tolerance: 0; text-fill: #000; text-halo-fill: #FFF; text-halo-radius: 1; text-dy: -20; text-allow-overlap: false; text-placement: point; text-placement-type: simple; text-placements: "N E S W"; } ##_END_REPLACE_ME_PRE_##

Notice how the tight cluster of components below have labels that don't overlap each other:

Label Placement

Line Styling

CartoCSS' versatility is not limited to just point markers - lines also have an impressive array of options for styling that's not immediately apparent if you're just using the CARTO wizards. The utility we were working with had traditional ways of representing its wiring systems as lines of different widths and "dashings" depending on the type of wire. Enter CartoCSS's [line-dasharray] property to the rescue!


priugelectriclinesegment {

line-width: 3; line-opacity: 0.7; }

priugelectriclinesegment[subtypecd=1] {

line-color: #FF5700; line-dasharray: 7 3; }

priugelectriclinesegment[subtypecd=2] {

line-color: #FF5700; line-dasharray: 7 2 2; }

priugelectriclinesegment[subtypecd=3] {

line-color: #FF5700; line-dasharray: 13 2 4 2; } ##_END_REPLACE_ME_PRE_##

The line-dasharray property takes an array of numbers to define dash lengths and spacing lengths. Using this property it's possible to create uniformly dashed lines lines that have long dashes followed by short dashes with short spacing dashes that are the same length but have different spacing every so often or some combination! The below shows 4 types of line in action:

Dashed Lines

Map Rotation

The vast majority of web maps are in North-up Mercator-type projections. This can be a challenge if your organization has legacy maps that portray information in different regions with different standard compass roses. In this utility company's case they were very interested in continuing the "deviation from true North" display their technicians had gotten used to. This is not an operation CartoCSS can solve but thanks to CARTO's full embrace of PostGIS putting a direction other than North "up" is something we can do by manipulating the data with SQL. ST_ROTATE will rotate your data by a number of radians (you can find compass degrees to radian converters easily online) and ST_TRANSLATE will move (or translate) your data by a certain x and/or y delta.

Now you cannot manipulate your basemap with SQL. So this rotation technique best works with a blank color basemap. You can download the features you'd like in a basemap from OpenStreetMap such as roads and import that into a CARTO table you can also rotate and translate just as much as your main data and make a multilayer map. Storing the entire Planet.osm file in CARTO would take a lot of storage so this is best for small areas!

Below is the general SQL query to accomplish this:

{% highlight SQL %} SELECT cartodb_id other_fields ST_TRANSLATE( ST_ROTATE( ST_TRANSLATE(the_geom_webmercator -1center_x_webmercator -1center_y_webmercator) -pi()/4 ) delta_x_webmercator delta_y_webmercator ) as the_geom_webmercator FROM your_table ##_END_REPLACE_ME_PRE_##

A few points to note:

  • other_fields: any other columns you want to select when you make this translation for instance ones you're using to set CartoCSS. If you don't select them individually they won't be part of your new translated dataset!
  • center_x_webmercator and center_y_webmercator: This is the centroid of your data in webmercator coordinates. You could find this with select ST_AsText(ST_Centroid(ST_Union(the_geom))) from your_table;
  • delta_x_webmercator and delta_y_webmercator: These are the number of web mercator meters of delta to translate your points after they have been rotated. After the rotate your data will likely be far far away from where it was originally - this won't really matter much unless you're using a basemap (which will be wrong after rotating your data anyway) and you could use the centroid x and y from above here as the delta x/y as well. If you want the points to appear roughly near where they were originally you'll need to come up with a delta.

Alternatively you can translate and rotate by the_geom and about a regular lat/long centroid but to get the resulting dataset to display in CARTO you'll need to "Create a new dataset from your query" ie create a new table after running the below:

{% highlight SQL %} SELECT cartodb_id other_fields ST_TRANSLATE( ST_ROTATE( ST_TRANSLATE(the_geom -1center_x -1center_y) -pi()/4 ) delta_x delta_y ) as the_geom FROM your_table ##_END_REPLACE_ME_PRE_##

Regardless once you've done the translate-rotate-translate shuffle here's the effect you'll see:

Rotated to East Up

Pretty cool!

What advanced maps will you create with CartoCSS and SQL?

Happy data mapping!