Mastering Grafana Map Markers and Geomaps
TheGrafana Geomappanel is a powerful visualisation. With it, you can show both static and movingobjects on a map in realtime. In this tutorial, we'll look at how to use Grafanamaps with QuestDB, and share tips and tricks along the way.
Sample data
For this tutorial, we will applythis csv filefull of Sydney, Australia bus data.
Start Grafana and QuestDB
Grafana provides an official QuestDB plugin.
To run through this tutorial, you'll need:
- Sample data (Check!)
- Running QuestDB
- Running Grafana instance
Need a hand?
Read our blog to getQuestDB and Grafana running with the official plugin.
Making map magic
Adding a Geomap panel
ClickAdd
in your Grafana dashboard.
Then selectVisualization
.
From there, choose theGeomap
panel.

Point the panel to your QuestDB data source:

We can then add a query to start getting positional data. In this case, we'lluse the previously linked Sydney Bus dataset. We'll use theLATEST BY
statement which displays the last known datapoint for each individual bus:
buses LATESTBY plate;
By default, this plots a map using amarkers
layer. Neat! However, the map isnot quite how we would like it. Since all the buses are in the New South Walesarea of Australia, we don't need to see the whole world:

Why do we see all of Earth? Grafana automatically recognized thelatitude
andlongitude
fields and displayed them as a result ofLocation Mode: Auto
:

Depending on your dataset, you may need to select theData
query in the Datafield, or change theLocation mode
to manually set the coordinate fields,Geohash or other to get the same results:

Fitting maps automatically
Thankfully, Grafana allows us to configure the map view so that it fits the areaof interest to the data. TheFit to data
option is available under theMap view
setting under theview
dropdown:

The resulting fit is more readable, and includes only Australia:

Fitting maps manually
Alternatively, adjust the view and save it to fit maps manually.
To do so:
- Zoom in and out of the map using the mouse wheel
- Pan across the map by clicking and dragging it around

Once you are satisfied with your view, click theUse current map settings
button. This will automatically set theView
toCoordinates
and save thecoordinates and zoom level corresponding to your view:

This method will ensure the map always loads the area of interest. However, donote that it does not act as a filter on the data. It may still load pointsoutside the range which won't be displayed.
If performance is a consideration, for example if Grafana is overloaded by manypoints which don't end up being displayed, you may filter on coordinates in youroriginal query.
Renaming layers
Let's rename our layers to be more friendly to the average dashboarder.
In theMap layers
, find the layer in question.
To rename the map layer, click on the blue label, and select the name you wish:

The resulting layer will now be correctly named on the map:

Making markers more expressive
The default markers may not always be adequate for the use case. For instance,your dataset may include other information such as heading, speed, trafficconditions, and so on. We can transform our markers to reflect this informationon the map in a synthetic way.
If we look at the result of our query, there is more data than thelatitude
andlongitude
coordinates. You can see the underlying data either by using theGrafanaQuery inspector
and selecting theData
tab, or by running the queryin theQuestDB web console:

Indicate direction with marker rotation
We can use thebearing
field to orient our map marker into the correctdirection. To do this, use therotation angle
property in thelayer
configuration. By default, rotation is set toFixed value
, but we can use thedropdown to select any appropriate field, which in this case isbearing
:

However, since the default markers are circles, we would not be able to see thebearing yet. Let's change the markersymbol
property in thestyles
sectionof thelayer
configuration. In this case, we'll use a pointing up chevronicon:

We'll do two things to our icon:
- Adjust the size to make them larger
- Increase the
fill opacity
to 100% to make them more visible
And with that, we are now able to see the buses headings in addition to theircurrent position:

Indicate speed with marker color
We can further enrich this layer with colour to indicate another dimension, suchas speed. Similar to the rotation property, theColor
property is set tofixed color
by default.
We can change this color to scale according to one of our dimensions. Let's setthespeed
dimension by selecting it from the dropdown:

By default, the colors would not be very meaningful because they are based onthe setthresholds
which are<80
(denominated asbase
) and>80
. Since nobus is going above 80Mph, all are displayed as the base color (green):


To display this information in a more meaningful way, we can either change thecolor scheme to follow a gradient…


… Or alternatively set our own thresholds:

In this case, buses going less than 2Mph are red (likely buses at a stop, or intraffic). Buses going above 10Mph are colored green:

Another dimension can provide more color to the markers. What if we set thereported level of traffic, or the reported level of occupancy? For example, inthe below, the purple buses are reporting higher congestion levels, which isconsistent with the speeds above:

Adding map labels
We can further augment the map by adding labels next to the markers using any ofour query result fields. To do this, head to theText label
section of thelayer
configuration. You can either use a fixed label by typing it in thevalue
field, or set source tofield
to use a query result field:

Note that by default, the label will be centred on top of our marker which maymake it hard to read…

From here, we can use theX offset
andY offset
properties to separate thelabel from the marker:


Plotting trails and routes
Let's take a step back.
It's wild to think that our initial query was this simple:
buses LATESTBY plate;
This query only displays the latest position for each bus.
However, we can expand this query to display a short positional history. We canchange thelayer type
frommarkers
toroute
(which is marked as a Grafanabeta feature currently) to plot historical positions:

SELECT*FROM busesWHERE $__timeFilter(timestamp)
Lots of potential!
But, err... if we plot all the routes in one go, we'd end up with this…

Currently Grafana is not able to separate the routes, even when we usetransformations to separate the data such as thepartition by values
transformation. Instead, it treats all locations as a single series and plotsbetween them resulting in an endless zigzag. It's a trip.
This is a current Grafana limitation which othershave reported before us, andit's reasonable to hope that it will be lifted in an upcoming release.
So what can we do?
To plot routes, we need to limit each layer to a single path.
For example by filtering on the bus plate:
SELECT*FROM busesWHERE $__timeFilter(timestamp)AND plate='MO1691'
The result looks more like what we expect:

We can then adjust the settings like we did for themarkers
to enrich the mapwith more detail such as colouring by speed, and usingArrows: forward
toindicate historical direction.
We could even create a second layer with the latest position as amarker
todisplay the current position (purple marker) along with the trailing route overthe last 15 minutes:

Going further: plotting multiple routes
Given the aforementioned Grafana limitation, we would need to create as manyseparate charts as there are individual buses. Doing this is easy bytransforming the query to useGrafana variables, and usingtherepeat by
panel option.
This will automatically repeat the above chart for all plates and achieve thedesired outcome:

Hopefully, Grafana will soon release an update so that multiple routes can beplotted in an individual panel, making this map element even more powerful atsynthesising geospatial data!
Thanks for reading.
Interested in more Grafana tutorials?
Check these out: