Interactive mapping. Tbilisi's restaurants rating

Tbilisi DataFest workshop materials. November 16-18, 2019

In the current publication, I'm providing a set of useful resources, data, and code of the interactive bubble map which shows a rating of the restaurants in Tbilisi. It is not a detailed tutorial of how to build a map, however, a well-prepared starter template with all the files inside and a clear structure of the code make it easy to understand the basic logic of the implementation of the map. The detailed instructions on how to find a geographical polygon, how to customize it in your own style, and link it to the map as well other details of the process were explained during the workshop.

Tbilisi Restaurants Rating

Stars

Reviews

Data Source: Tripadvisor

1. Find and download geographical polygons.

Nominatim OSM
Polygons OSM

2. Mapbox Studio: create a custom style map

Mapbox Studio

3. Set up a project

Basic HTML structure

Download ZIP
<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <title>Tbilisi Restaurants Map</title>
  <script src="js/d3.min.js"></script>
  <script src="js/mapbox-gl.js"></script>
  <link href="css/mapbox-gl.css" rel="stylesheet">
  <link href="css/st.css" rel="stylesheet">
</head>
<style>

/* CSS goes here. */

</style>
<body>
<script src="js/elements.js"></script>
<script>

/* JavaScript goes here. */

</script>
</body>

JAVASCRIPT part

Import a background map created at Mapbox Studio website

mapboxgl.accessToken = '...';

let map = new mapboxgl.Map({
    container: 'map',
    style: '...',
    center: [44.800000, 41.700009],
    zoom: 13
})

Create Mapbox canvas element over the map and append SVG container to it.

let container = map.getCanvasContainer();
let svg = d3.select('container').append('svg');

Load and read csv data file.

Trip Advisor data file
d3.csv('...', function(error, data){

  //the rest of the JS code goes here

})

Create dots variable and assign the CSV data to it. Append circle to each row in the CSV file.

let dots = svg.selectAll("circle.dot")
  .data(data)
  .enter()
    .append('circle')
    .attr('r', 5)
    .attr('fill', 'green')

Set x and y position to each circle and render the visualization

function render() {
  dots.attr({
    cx: function(d) {
      let x = project(d).x;
        return x
    },
    cy: function(d) {
      let y = project(d).y;
        return y
    }
  })
}
// render initial visualization
render()

Re-render visualization whenever the view changes

map.on("viewreset", function() {
    render()
})
map.on("move", function() {
    render()
})

Add tooltip when a pointer is over the circle


.on("mouseover", function(d) {
    tooltip
      .style("visibility", "visible")
      .style("left", (d3.event.pageX + 15) + "px")
      .style("top", (d3.event.pageY - 38) + "px")
      .html('<p class="tipTitle">' + d.name +
            '</p><p>Stars: ' + d.stars + '</p>' +
            '<p>Reviews: ' + d.review + '</p>')
          })

Back to the HTML. Legend

Add legend markup to the HTML part right after the div #map

<div class="legend">
  <h1>Tbilisi Restaurants Rating</h1>
  <div class="stars">
    <h2>Stars</h2>
  </div>
  <div class="reviews">
      <h2>Reviews</h2>
  </div>
  <p class="disclaimer">Data Source: Tripadvisor</p>
</div>

Full code of the map is available on Github

Thank you to the Tbilisi DataFest Team and the Deutsche Welle Akademie for the incredible organization of the event and an opportunity to provide the workshop.