Skip to main content

PMTiles arrive in Icon Map Pro

· 4 min read
James Dales
Co-founder of Tekantis

We’re submitting the next version of Icon Map Pro to Microsoft today for publishing on AppSource in a couple of weeks. I’m quite excited about this release for a number of reasons, but one of the main ones is our initial support for PMTiles.

I’ve recently been working with a customer who needed to create a choropleth (filled) map for Canada. Canada is a challenge as it has the largest coastline of any country, but really compact population centres, meaning that to represent census boundaries, we need to be able to plot very large polygons with a detailed coastline, whilst at the same time, really small polygons that might only cover a few blocks in a city centre.

alt text

In terms of doing this in Power BI, we’re unable to use a GeoJSON or shape file as they’re either too large – or once simplified, lose too much definition. As an example, the official GeoJSON file for Canada’s dissemination areas is over 1gb – far too large to import into a Power BI report by some orders of magnitude.

My normal recommendation in these cases is to use Well-Known Text (WKT) shapes loaded into the map via Power BI data model. But Power BI has a maximum number of characters limit that, even with the usual workarounds, is not enough to accommodate some of Canada’s largest territories and provinces.

This doesn’t mean it’s not possible to achieve already with Icon Map Pro though. We can use vector tiles to only retrieve the shapes that need to be displayed on the part of the map that we’re looking at, and at a resolution appropriate for the current zoom level. The issue with vector tiles is that they needed to be either pre-processed, and/or served using a GIS server. This could be an enterprise GIS solution such as Esri’s ArcGIS, an online provider such as Mapbox or an opensource server such as GeoServer. All provide workable solutions, but it’s an additional provider, and sometimes significant cost to add to the mix.

Enter PMTiles. PMTiles provides a new cloud-native way to serve vector (or raster) tiles. Designed to use a highly efficient compression algorithm, the resulting PMTiles file is a single file that sits, usually in cloud storage. It requires a server that supports HTTP range requests – supported by Azure Blob Storage and Amazon S3 buckets. Rather than the whole file being downloaded each time, HTTP range requests are used to download just the segment of the file for that tile. And the file sizes are much smaller than the original – meaning storage costs are minimal – and there’s no compute costs. No GIS server required. Canada’s 1gb dissemination areas file is less than 100mb as a PMTiles file.

This Power BI report, uses 4 levels of drilldown to present Canada’s census data from Territory/Province level, through Census Divisions, Census Sub Divisions to Dissemination Areas. As well as simply displaying the file, in Power BI we use the embedded properties to link it back to the data in Power BI data model, and use conditional formatting to create our filled, choropleth map on the fly. We’re able to either drill into each area at a time, or simply view all 75,000 dissemination areas at the same time.

And that's not our only use for PMTiles, we've also added some additional background maps thanks to Protomaps.

To create the PMTiles files used in this report, I used the open-source tool, Tippecanoe, but we’re working on building a Microsoft product range that will incorporate this capability, to make it easy to generate your own PMTiles in future. Watch this space - there's so much more coming!

WebGL Mode – what’s it all about?

· 4 min read
James Dales
Co-founder of Tekantis

In our February release of Icon Map Pro, you’ll notice a new settings option, “Rendering”, so I thought I’d explain in more detail what’s behind this option, and why it’s there.

Let’s start by explaining a bit more about the code libraries that Icon Map Pro uses to draw the map. If you go back to when I first created the original Icon Map visual nearly 10 years ago, there were 2 main opensource libraries used for creating web maps, OpenLayers and a more lightweight library, Leaflet.

The original Icon Map was built on top of Leaflet, which provided great support for most of the features required for mapping in Power BI. It also had a wide range of plugins available which added some of the more advanced capabilities.

At Tekantis, when we started to write Icon Map Pro last year, we didn’t want to provide fewer capabilities than were available in the older Icon Map visual, so again we chose Leaflet to ensure we were able to provide the full range of features.

However, Icon Map Pro is capable of drawing more rows of data than the original visual, which was limited to 20,000, then later 30,000 rows. When drawing large amount of complex objects, or images on the map, Leaflet starts to suffer from performance issues. We therefore started to look at how to overcome this.

A lot has happened in the web mapping world in the last 10 years. Volodymyr Agafonkin, who created the original Leaflet library, started to work for Mapbox and created a new map library that was built using WebGL rendering, using the power of the GPU for better performance. Whilst this library was initially open source, at some point Mapbox forked the library to create version 3, after which a Mapbox license key was required to use it.

The version 2 library became the Maplibre project and development of this library has continued separately to the Mapbox library. It’s this Maplibre library that is the foundation for many other mapping libraries such as the Azure Maps JavaScript API.

In Icon Map Pro we’ve been using a plugin that uses Maplibre on top of Leaflet to provide some of the features such as our vector tiles based background mapping. We’ve also provided some experimental layers using WebGL to provide better performance for rendering large GeoJSON layers for example. However, using this plugin has limitations as each layer using WebGL created a separate instantiation of Maplibre and WebGL, and we therefore started to hit limitations in regard to the number of WebGL instances possible, and in terms of memory.

In the February release of Icon Map Pro, we’re removed the experimental WebGL options (for new maps) and replaced them with a new WebGL rendering option. This now uses a single Maplibre instance to draw all the overlay and data-bound layers, which means we don’t hit the same limitations. It’s also enabled some additional functionality where items overlap on the map, such as combined tooltips.

To enable this, we’ve made it a single choice between using WebGL via Maplibre vs traditional rendering via Leaflet. In this initial release, not all overlay and data-bound layer types are available, but we’re planning to enable all of them going forward.

Currently we’re still using the Maplibre plugin for Leaflet, so all the current controls are available. The downside of this however, is that additional features such as the ability to rotate and tilt the map are not available, as these aren’t supported by Leaflet.

In a future release, we’re aiming to provide an additional option that will only use Maplibre, and we can therefore add these additional capabilities.

User Driven Format Rules

· 2 min read
James Dales
Co-founder of Tekantis

We had an interesting support request come through yesterday from a customer. They were using Power BI's rule based conditional formatting to specify line colours based on values associated with those lines:

alt text

However, the report viewers - the end users - had requested to be able to not only specify their own colours, but also the value ranges at which they take effect.

I was keen therefore to see if we could build that kind of capability using standard Power BI visuals. To achieve it I created a set of tables containing colour values for each of the ranges, and a set of corresponding numeric range parameter tables. The result is that the users can press a Power BI button to show the controls. 3 slider slicers allow them to enter the numeric ranges from which the colours take effect, and I used the new card slicer visual to allow them to pick from a set of colours.

A DAX measure is then used to return the appropriate colour based on the slicer selections and the value associated with the line

Track Colour = 
VAR _TrackValue = AVERAGE(Track[Track Value]) * 100
VAR _Colour = IF (
ISBLANK(_TrackValue), "#000000",
IF (_TrackValue < 'Range 1'[Range 1 Value], MAX ('Colours 1'[Selected Colour]),
IF (_TrackValue < Range2[Range2 Value], MAX ('Colours 2'[Selected Colour]),
IF (_TrackValue < Range3[Range3 Value], MAX ('Colours 3'[Selected Colour]),
MAX ('Colours 4'[Selected Colour])
))))
RETURN _Colour

Here's the final report. Feel free to download the pbix file and deconstruct it.

Drawing routes along roads using the Azure Maps API

· 6 min read
James Dales
Co-founder of Tekantis

Yesterday I published a blog about drawing drive time isochrones on the map using the Azure Maps API called from PowerQuery, all inside of Power BI. Today I've built a similar report, but this time I'm calling the Azure Maps routing API to draw the routes by road between Heathrow Airport and a number of the UK's other major airports.

alt text

Whilst Icon Map Pro has built in options for drawing lines (straight, curved or geodesic) as well as linestrings from GeoJSON or well-known text (WKT), it can't currently draw lines following the best path along roads. This isn't something that can be handled in the presentation layer, especially if traffic, low bridges, width restrictions, etc are to be taken into account.

On this basis, the Azure Maps API seems like a great way to handle this. I've started with a simple table of source and destination locations, from which I call the API.

alt text

To do this I created a PowerQuery function:

let
GetRouteDirections = (apiKey as text, sourceLon as number, sourceLat as number, destLon as number, destLat as number) =>
let
// Define the API endpoint
url = "https://atlas.microsoft.com/route/directions?api-version=2024-07-01-preview&subscription-key=" & apiKey,

// Construct the request body
requestBody = Json.FromValue([
type = "FeatureCollection",
features = {
[
type = "Feature",
geometry = [
coordinates = {sourceLon, sourceLat},
type = "Point"
],
properties = [
pointIndex = 0,
pointType = "waypoint"
]
],
[
type = "Feature",
geometry = [
coordinates = {destLon, destLat},
type = "Point"
],
properties = [
pointIndex = 1,
pointType = "waypoint"
]
]
},
optimizeRoute = "fastestWithTraffic",
routeOutputOptions = {"routePath"},
maxRouteCount = 1,
travelMode = "driving"
]),

// Convert the JSON request body to binary format
requestBodyBinary = requestBody,

// Make the API call
response = Web.Contents(url, [
Headers = [
#"Content-Type" = "application/json"
],
Content = requestBodyBinary
]),

// Parse the JSON response
json = Text.FromBinary(response)
in
json
in
GetRouteDirections

This returns a lot of information, so I created a function to extract out the lines making up the route, as well as the length and durations.

let
ExtractMultiLineString = (responseText as text) =>
let
// Parse the response text into a JSON object
jsonResponse = Json.Document(responseText),

// Access the 'features' array in the JSON response
features = jsonResponse[features],

// Filter the features to find the one with geometry.type = "MultiLineString"
multiLineStringFeature = List.First(List.Select(features, each _[geometry][type] = "MultiLineString"), null),

// Extract additional properties
distanceInMeters = if multiLineStringFeature = null then null else multiLineStringFeature[properties][distanceInMeters],
durationInSeconds = if multiLineStringFeature = null then null else multiLineStringFeature[properties][durationInSeconds],
durationTrafficInSeconds = if multiLineStringFeature = null then null else multiLineStringFeature[properties][durationTrafficInSeconds],

// Convert duration to minutes
durationInMinutes = if durationInSeconds = null then null else Number.Round(durationInSeconds / 60, 2),
durationTrafficInMinutes = if durationTrafficInSeconds = null then null else Number.Round(durationTrafficInSeconds / 60, 2),

distanceInKm = if distanceInMeters = null then null else Number.Round(distanceInMeters / 1000, 2),

// Convert the MultiLineString feature to text
multiLineStringText = if multiLineStringFeature = null then null else Text.FromBinary(Json.FromValue(multiLineStringFeature)),

// Construct the output object
result = [
multiLineStringFeatureAsText = multiLineStringText,
distanceInKm = distanceInKm,
durationInMinutes = durationInMinutes,
durationTrafficInMinutes = durationTrafficInMinutes
]
in
result
in
ExtractMultiLineString

This is enough to display the routes in Icon Map Pro, but some of the routes I'd requested are long, far exceeding the maximum length of a field in Power BI. Whilst the report handles this by splitting these long routes into multiple rows, I decided to convert the GeoJSON returned by Azure Maps to Well-Known Text format, which is slightly more compact.

Again to do this I created a function, which also reduces the decimal precision of the coordinates, to further reduce the number of characters used:

let
GeoJSONToWKT = (geoJsonText as text, precision as number) =>
let
// Parse the GeoJSON text to a record
geoJson = Json.Document(geoJsonText),

// Extract the geometry and its type
geometry = geoJson[geometry],
geometryType = Text.Upper(geometry[type]),
coordinates = geometry[coordinates],

// Function to format a single coordinate with the specified precision
FormatCoordinate = (coord as number) =>
Number.ToText(Number.Round(coord, precision), "F" & Number.ToText(precision)),

// Function to format a single point (lon, lat)
FormatPoint = (point as list) =>
Text.Combine(List.Transform(point, each FormatCoordinate(_)), " "),

// Function to format a list of points (e.g., for LineString)
FormatLineString = (line as list) =>
"(" & Text.Combine(List.Transform(line, each FormatPoint(_)), ", ") & ")",

// Function to format a list of LineStrings (e.g., for MultiLineString or Polygon)
FormatMultiLineString = (lines as list) =>
"(" & Text.Combine(List.Transform(lines, each FormatLineString(_)), ", ") & ")",

// Function to format a list of Polygons (e.g., for MultiPolygon)
FormatMultiPolygon = (polygons as list) =>
"(" & Text.Combine(List.Transform(polygons, each FormatMultiLineString(_)), ", ") & ")",

// Match geometry type and convert to WKT
WKT =
if geometryType = "POINT" then
"POINT (" & FormatPoint(coordinates) & ")"
else if geometryType = "MULTIPOINT" then
"MULTIPOINT " & FormatLineString(coordinates)
else if geometryType = "LINESTRING" then
"LINESTRING " & FormatLineString(coordinates)
else if geometryType = "MULTILINESTRING" then
"MULTILINESTRING " & FormatMultiLineString(coordinates)
else if geometryType = "POLYGON" then
"POLYGON " & FormatMultiLineString(coordinates)
else if geometryType = "MULTIPOLYGON" then
"MULTIPOLYGON " & FormatMultiPolygon(coordinates)
else
error "Unsupported geometry type: " & geometryType
in
WKT
in
GeoJSONToWKT

And then finally, I created one further function to generate a random colour to assign to each route:

let
GenerateDarkHexColorFromSeed = (seed as text) =>
let
// Convert the seed text into a list of character codes
charCodes = List.Transform(Text.ToList(seed), each Character.ToNumber(_)),

// Sum the character codes to create a simple numeric seed
numericSeed = List.Sum(charCodes),

// Generate pseudo-random RGB values using the numeric seed
red = Number.Mod(numericSeed * 37, 256),
green = Number.Mod(numericSeed * 59, 256),
blue = Number.Mod(numericSeed * 73, 256),

// Adjust RGB values to ensure they are dark enough
minBrightness = 100, // Minimum brightness for each channel
darkRed = if red > 255 - minBrightness then 255 - minBrightness else red,
darkGreen = if green > 255 - minBrightness then 255 - minBrightness else green,
darkBlue = if blue > 255 - minBrightness then 255 - minBrightness else blue,

// Convert each component to a two-digit hexadecimal string
redHex = Text.PadStart(Number.ToText(Number.RoundDown(darkRed), "X"), 2, "0"),
greenHex = Text.PadStart(Number.ToText(Number.RoundDown(darkGreen), "X"), 2, "0"),
blueHex = Text.PadStart(Number.ToText(Number.RoundDown(darkBlue), "X"), 2, "0"),

// Combine the components into a hex color string
hexColor = "#" & redHex & greenHex & blueHex
in
hexColor
in
GenerateDarkHexColorFromSeed

I use this to create an SVG image that I show at the end of the lines, and also in the table. The image is created as a DAX measure, so I can assign the colour dynamically:

Destination Image = "data:image/svg+xml,<svg xmlns=""http://www.w3.org/2000/svg"" width=""20"" height=""20"" viewBox=""0 0 20 20""><circle cx=""10"" cy=""10"" r=""10"" fill=""" & SUBSTITUTE( MAX (Routes[Color]), "#", "%23") & """/></svg>"

Here's the final report. Feel free to download the pbix file and deconstruct it. There's hopefully some useful PowerQuery functions inside that can be put to use in other reports. You will need to use your own Azure Maps API Key - set in a PowerQuery parameter.

Fire Station Drive Times with Azure Maps API

· 4 min read
James Dales
Co-founder of Tekantis

Yesterday Microsoft published a blog post about Isochrones in the Azure Maps Route Range API. Isochrones are a great way to represent the amount of time it takes to travel from a point. We've included an isochrone example in our sample Power BI report file since we launched Icon Map Pro six months or so ago.

With Microsoft now supporting isochrones in geoJSON format as part of their API, I was keen to see if I could incorporate this into Power BI's data load processes using Power Query, without needing to use a Python notebook.

To test this out I've built a report that shows the extent that all the fire stations in West Sussex can reach within a 10 minute drive time.

alt text

I started with a list of fire stations, their addresses and the corresponding longitudes and latitudes:

alt text

The plan was to use the coordinates as the start points for the drive time call for the Azure Maps API.

I created a Power Query function to call the API, which I then call for each fire station:

let

CallAzureMapsRangeApi = (ApiKey as text, Longitude as number, Latitude as number, TimeBudget as number, TravelMode as text, Height as number, Length as number, Width as number) as text =>
let
// Define the API endpoint
ApiUrl = "https://atlas.microsoft.com/route/range?api-version=2024-07-01-preview&subscription-key=" & ApiKey,

// Create the request body
RequestBody = Text.FromBinary(Json.FromValue([
type = "Feature",
geometry = [
type = "Point",
coordinates = {Longitude, Latitude}
],
properties = [
timeBudgetInSec = TimeBudget,
travelMode = TravelMode,
vehicleSpec = [
height = Height,
length = Length,
width = Width
]
]
])),

// Define the headers
Headers = [
#"Content-Type" = "application/json"
],

// Make the POST request
Response = Web.Contents(ApiUrl, [
Headers = Headers,
Content = Text.ToBinary(RequestBody)
]),

// Treat the response as plain text
ResponseText = Text.FromBinary(Response)
in
ResponseText
in
CallAzureMapsRangeApi

The function takes in the your Azure Maps API key, the coordinates, amount of time, vehicle type and dimensions of the vehicle as parameters.

Calling this returns a geoJSON file for each fire station:

alt text

Whilst Icon Map Pro can display geoJSON files, it can't display them when the whole file is stored in a field. It can however display geoJSON features stored in a row in your dataset, so I created another PowerQuery function to extract the isochrone polygon, and its centroid from the geoJSON:

let
ExtractFeature = (GeoJsonText as text) as table =>
let
// Parse the input JSON text
ParsedJson = Json.Document(GeoJsonText),

// Extract the "features" array
Features = ParsedJson[features],

// Extract the "geometry" object for the "Polygon" type
PolygonGeometry = List.First(
List.Select(Features, each _[geometry][type] = "Polygon")
)[geometry],

// Extract coordinates for the "Point" type
PointFeature = List.First(
List.Select(Features, each _[geometry][type] = "Point")
),

PointCoordinates = PointFeature[geometry][coordinates],
Longitude = PointCoordinates{0},
Latitude = PointCoordinates{1},

// Convert the Polygon object to JSON text
PolygonText = Text.FromBinary(Json.FromValue([
type = PolygonGeometry[type],
coordinates = PolygonGeometry[coordinates]
])),

// Prepare the output table
Result = Table.FromRecords({
[
Longitude = Longitude,
Latitude = Latitude,
Polygon = PolygonText
]
})
in
Result
in
ExtractFeature

From this we now just have the Polygon feature for each isochrone, and not the whole file.

alt text

This is enough to display the isochrones on the map, but I also wanted to add a circle showing the centroid, and add a label with the fire station name. To do this I added another set of rows for each fire station with the longitude and latitude, and appended it to the fire stations table. Now I have a set of rows for each isochrone, and a set of rows for each centroid.

alt text

Then in Icon Map Pro, I've enabled the circle layer, and WKT / GeoJSON (from data) layer and dragged in the corresponding fields. I also set up the label to show below the circles.

alt text

Finally I added in a reference layer with the UK's local authorities - but with West Sussex deleted. This meant that I could highlight the West Sussex area on the map.

The last touch was to add tooltips, and a Power BI slicer to be able to zoom in to specific fire stations.

alt text

Here's the final report using Icon Map Pro, and you can download the Power BI file to see how it was constructed. You will need to add your own Azure Maps API key (obtained from the Azure admin portal) as a Power Query parameter.


Source of local authority boundaries: Office for National Statistics licensed under the Open Government Licence v.3.0. Contains OS data © Crown copyright and database right 2024

Bus Routes

· 2 min read
James Dales
Co-founder of Tekantis

During the recent 30 Day Map Challenge I published a report with many of Europe's railway routes, which gained a lot of interest. I thought I'd see whether the same thing was possible for bus routes.

I'd sourced the data for the railway networks from OpenStreetMap, but it seems OpenStreetMap doesn't have sufficient data for bus routes - it's either inconsistent or partially populated.

However, I found that the Department for Transport has a Bus Open Data Site. This seems a great source of data, and I've only had chance to scratch the surface. I've started with timetable data. There's a lot of it! For starters, buses stop a lot more than trains, so there are a lot more stops, and the coordinates between each stop along the routes are detailed, as again, roads have many more turns (and roundabouts!) than railway lines.

The data downloads are large, so I've focussed on just one operator for now, the GoAhead group and downloaded their timetable data for the North East. This report represents all of their routes. A Power BI slicer enables you to pick a route, or alternatively you can search for a specific stop and all the routes that service that stop will be displayed. The chosen stop is highlighted in red.

alt text

Hovering over a stop with the mouse cursor will display the timetable information for all the buses that service that stop.

alt text

There are complexities, and nuances in the data that I haven't represented in the report, but it was a good proof of concept to see what could be achieved with bus data in a few hours. I see there's an API to retrieve the realtime locations of buses, so I'm looking forward to an excuse to explore that!

30 Days of Maps Day 30 - The Final Map

· 3 min read
James Dales
Co-founder of Tekantis

We made it! It's the 30th so the final day of this year's #30DayMapChallenge. The theme for this final map is "The final map" - The final challenge—your choice! Revisit a technique from earlier in the month, refine an idea, or try something completely new. End the challenge on a high note with a map that showcases your creativity, growth, or just pure fun!

So today's report isn't pretty, it's not a great map, but it is useful! It's actually one of our test reports. Over the previous releases of Icon Map Pro, we've been providing some great capabilities for drawing items on the map, that either come out of the Power BI dataset, or are linked to it. These include:

  • Circles
  • Lines
  • Images
  • H3 hexagons, from coordinates, or cell IDs
  • Heatmap
  • Well Known Text or GeoJSON from the dataset
  • GeoJSON, TopoJSON, Esri shapefiles, KML files linked to data
  • ArcGIS features layers linked to data (and formattable)
  • Vector tile layers linked to data

For our next release, which should land within the next 2 weeks, we've done a chunk of work to ensure these work together on the map at the same time. This is no easy task as ideally we would have a different, disconnected set of fields for each layer in the map, but Power BI infrastructure doesn't provide this capability. We work around this by determining the type of object to draw based on the which data is provided in each row. For example if you provide a longitude, latitude and a image URL, then we know that row relates to an image, where as a longitude, latitude and a circle size value relates to a circle. It's not ideal, but with some careful data modelling, it's possible to achieve a map with everything combined. You can determine the order the layers appear by setting the 'z-index'.

Hence the report below, this is one of the reports we use to test that this field mapping is working correctly. This report includes a GeoJSON file formatted using Power BI conditional formatting as a choropleth, circles with three configurations of formatting, a couple of WKT linestrings, some images with text labels, H3 cells, a heatmap and a couple of curved lines, one with a circle at the destination. And this only represents a fraction of the different combinations possible!

If you'd like to see how the report was built, you can download it here.

30 Days of Maps Day 29 - Overture

· 2 min read
James Dales
Co-founder of Tekantis

The penultimate day - it's day 29 of the #30DayMapChallenge and today's topic is "Overture" - Use data from the Overture Maps Foundation. Explore data from Overture Maps Foundation to create a map that highlights new geographic datasets. A great opportunity to dive into open geospatial data!

For those not familiar with it, Overture Maps is a collaborative, open-source project aimed at creating high-quality, up-to-date map data that's freely available for anyone to use. One of the key aspects of Overture Maps is its use of web-native technologies like PMTiles. PMTiles is a file format designed to efficiently store and deliver map tiles over the web. This means maps can load faster and perform better directly in the browser, even without heavy server infrastructure behind them.

We're still building our PM Tiles integration into Icon Map Pro, but progress is well underway. Here's an example showing Overture Maps building outlines loaded from PM Tiles. The key thing, is that the tiles are a single 135gb file stored in cloud blob storage.

In this report, we're showing the building outlines, extruded based on the buildings' height. Where available, we're colouring the buildings based on their type. Power BI tooltips are used to expose the building's name and type.

Buildings data from Overture Maps is released under the ODbL license.

© OpenStreetMap contributors. Available under the Open Database License. Data from Microsoft Esri Community Maps contributors. Available under CC BY 4.0. Google Open Buildings. Available under CC BY 4.0. USGS 3D Elevation Program Digital Elevation Program.

30 Days of Maps Day 28 - The blue planet

· One min read
James Dales
Co-founder of Tekantis

Nearly there - it's day 28 of the #30DayMapChallenge and today's topic is "The blue planet" - Map oceans, rivers, and lakes. Focus on water today. Map the oceans, rivers, or lakes, diving deep into marine environments or water systems.

For this report, I've used fishing catch statistics from the International Council for the Exploration of the Sea (ICES) and am showing catch, landings and fish stock numbers within the fishing areas for the different species of fish. I'm using the "Oceans" base map from Esri to overlay a choropleth map that updates according to the criteria selected.

If you'd like to see how the report was built, you can download it here.

30 Days of Maps Day 27 - Micromapping

· One min read
James Dales
Co-founder of Tekantis

And we're up to day 27 of the #30DayMapChallenge and today's topic is "Micromapping" - Map something small and precise. Zoom in and map a small area in high detail. It could be a single building, a street corner, or a tiny plot of land. Focus on accuracy at a small scale.

Today's challenge takes us to Manchester in the UK, and more specifically, inside the Trafford shopping centre. It's worth shouting out that all of the data is fictional - these are not the real sales, and may not be the correct outlets either. I've created the shape file from a photo of the store plan! However the scenario is very real. This report gives us a view of the sales, size and sales per m2 of each of the outlets. With the right data, we could even create an equivalent report showing the plan within each store too, as we've increased the maximum zoom level to 24.

If you'd like to see how the report was built, you can download it here.