Scatter Plots on Tile Maps in JavaScript

How to make scatter plots on tile maps in Plotly.JS


Plotly Studio: Transform any dataset into an interactive data application in minutes with AI. Try Plotly Studio now.

var data = [{
  type:'scattermap',
  lat:['45.5017'],
  lon:['-73.5673'],
  mode:'markers',
  marker: {
    size:14
  },
  text:['Montreal']
}]

var layout = {
  autosize: true,
  hovermode:'closest',
  map: {
    bearing:0,
    center: {
      lat:45,
      lon:-73
    },
    pitch:0,
    zoom:5
  },
}

Plotly.newPlot('myDiv', data, layout)
</script>\n</head>\n\n<body>\n\t<div id='myDiv'><!-- Plotly chart will be drawn inside this DIV --></div>\n</body>","js":"var data = [{\n type:'scattermap',\n lat:['45.5017'],\n lon:['-73.5673'],\n mode:'markers',\n marker: {\n size:14\n },\n text:['Montreal']\n}]\n\nvar layout = {\n autosize: true,\n hovermode:'closest',\n map: {\n bearing:0,\n center: {\n lat:45,\n lon:-73\n },\n pitch:0,\n zoom:5\n },\n}\n\nPlotly.newPlot('myDiv', data, layout)\n"}">
d3.csv('https://raw.githubusercontent.com/bcdunbar/datasets/master/meteorites_subset.csv', function(err, rows){

  var classArray = unpack(rows, 'class');
  var classes = [...new Set(classArray)];

  function unpack(rows, key) {
    return rows.map(function(row) { return row[key]; });
  }

  var data = classes.map(function(classes) {
    var rowsFiltered = rows.filter(function(row) {
        return (row.class === classes);
    });
    return {
       type: 'scattermap',
       name: classes,
       lat: unpack(rowsFiltered, 'reclat'),
       lon: unpack(rowsFiltered, 'reclong')
    };
  });

  var layout = {
	 title: {text: 'Meteorite Landing Locations'},
	 font: {
		 color: 'white'
	 },
    dragmode: 'zoom',
    map: {
      center: {
        lat: 38.03697222,
        lon: -90.70916722
      },
      domain: {
        x: [0, 1],
        y: [0, 1]
      },
      style: 'dark',
      zoom: 1
    },
    margin: {
      r: 20,
      t: 40,
      b: 20,
      l: 20,
      pad: 0
    },
    paper_bgcolor: '#191A1A',
    plot_bgcolor: '#191A1A',
    showlegend: true,
	 annotations: [{
		 x: 0,
       y: 0,
       xref: 'paper',
       yref: 'paper',
		 text: 'Source: <a href="/?originalUrl=https%3A%2F%2Fplotly.com%2F%26quot%3Bhttps%3A%2F%2Fdata.nasa.gov%2FSpace-Science%2FMeteorite-Landings%2Fgh4g-9sfh%26quot%3B%2520style%3D%26quot%3Bcolor%3A%2520rgb(255%2C255%2C255)%26quot%3B%26gt%3BNASA%26lt%3B%2Fa%26gt%3B",
		 showarrow: false
	 }]
  };

  Plotly.newPlot('myDiv', data, layout);
});
</script>\n\t<script src="/?originalUrl=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fd3%2F3.5.17%2Fd3.min.js"></script>\n</head>\n\n<body>\n\t<div id='myDiv'><!-- Plotly chart will be drawn inside this DIV --></div>\n</body>","js":"d3.csv('https://raw.githubusercontent.com/bcdunbar/datasets/master/meteorites_subset.csv', function(err, rows){\n\n var classArray = unpack(rows, 'class');\n var classes = [...new Set(classArray)];\n\n function unpack(rows, key) {\n return rows.map(function(row) { return row[key]; });\n }\n\n var data = classes.map(function(classes) {\n var rowsFiltered = rows.filter(function(row) {\n return (row.class === classes);\n });\n return {\n type: 'scattermap',\n name: classes,\n lat: unpack(rowsFiltered, 'reclat'),\n lon: unpack(rowsFiltered, 'reclong')\n };\n });\n\n var layout = {\n\t title: {text: 'Meteorite Landing Locations'},\n\t font: {\n\t\t color: 'white'\n\t },\n dragmode: 'zoom',\n map: {\n center: {\n lat: 38.03697222,\n lon: -90.70916722\n },\n domain: {\n x: [0, 1],\n y: [0, 1]\n },\n style: 'dark',\n zoom: 1\n },\n margin: {\n r: 20,\n t: 40,\n b: 20,\n l: 20,\n pad: 0\n },\n paper_bgcolor: '#191A1A',\n plot_bgcolor: '#191A1A',\n showlegend: true,\n\t annotations: [{\n\t\t x: 0,\n y: 0,\n xref: 'paper',\n yref: 'paper',\n\t\t text: 'Source: <a href="/?originalUrl=https%3A%2F%2Fplotly.com%2F%26quot%3Bhttps%3A%2F%2Fdata.nasa.gov%2FSpace-Science%2FMeteorite-Landings%2Fgh4g-9sfh%2F%26quot%3B%2520style%3D%2F%26quot%3Bcolor%3A%2520rgb(255%2C255%2C255)%2F%26quot%3B%26gt%3BNASA%26lt%3B%2Fa%26gt%3B%26%2339%3B%2C%5Cn%5Ct%5Ct%2520showarrow%3A%2520false%5Cn%5Ct%2520%7D%5D%5Cn%2520%2520%7D%3B%5Cn%5Cn%2520%2520Plotly.newPlot(%26%2339%3BmyDiv%26%2339%3B%2C%2520data%2C%2520layout)%3B%5Cn%7D)%3B%5Cn%26quot%3B%7D">
d3.csv('https://raw.githubusercontent.com/plotly/datasets/master/2015_06_30_precipitation.csv', function(err, rows){
      function unpack(rows, key) {
          return rows.map(function(row) { return row[key]; });
      }

 scl = [[0, 'rgb(150,0,90)'],[0.125, 'rgb(0, 0, 200)'],[0.25,'rgb(0, 25, 255)'],[0.375,'rgb(0, 152, 255)'],[0.5,'rgb(44, 255, 150)'],[0.625,'rgb(151, 255, 0)'],[0.75,'rgb(255, 234, 0)'],[0.875,'rgb(255, 111, 0)'],[1,'rgb(255, 0, 0)']];

    var data = [{
        type: 'scattermap',
        mode: 'markers',
        text: unpack(rows, 'Globvalue'),
        lon: unpack(rows, 'Lon'),
        lat: unpack(rows, 'Lat'),
        marker: {
          color: unpack(rows, 'Globvalue'),
          colorscale: scl,
          cmin: 0,
          cmax: 1.4,
          reversescale: true,
          opacity: 0.5,
          size: 3,
          colorbar:{
            thickness: 10,
            title: {side:
              'right'
            },
            outlinecolor: 'rgba(68,68,68,0)',
            ticks: 'outside',
            ticklen: 3,
            shoticksuffix: 'last',
            ticksuffix: 'inches',
            dtick: 0.1
          }
        },
        name: 'NA Precipitation'
    }];

    layout = {
      dragmode: 'zoom',
      map: {
        center: {
          lat: 38.03697222,
          lon: -90.70916722
        },
        domain: {
          x: [0, 1],
          y: [0, 1]
        },
        style: 'light',
        zoom: 3
      },
      margin: {
        r: 0,
        t: 0,
        b: 0,
        l: 0,
        pad: 0
      },
      showlegend: false
   };

    Plotly.newPlot('myDiv', data, layout);
  });
</script>\n\t<script src="/?originalUrl=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fd3%2F3.5.17%2Fd3.min.js"></script>\n</head>\n\n<body>\n\t<div id='myDiv'><!-- Plotly chart will be drawn inside this DIV --></div>\n</body>","js":"d3.csv('https://raw.githubusercontent.com/plotly/datasets/master/2015_06_30_precipitation.csv', function(err, rows){\n function unpack(rows, key) {\n return rows.map(function(row) { return row[key]; });\n }\n\n scl = [[0, 'rgb(150,0,90)'],[0.125, 'rgb(0, 0, 200)'],[0.25,'rgb(0, 25, 255)'],[0.375,'rgb(0, 152, 255)'],[0.5,'rgb(44, 255, 150)'],[0.625,'rgb(151, 255, 0)'],[0.75,'rgb(255, 234, 0)'],[0.875,'rgb(255, 111, 0)'],[1,'rgb(255, 0, 0)']];\n\n var data = [{\n type: 'scattermap',\n mode: 'markers',\n text: unpack(rows, 'Globvalue'),\n lon: unpack(rows, 'Lon'),\n lat: unpack(rows, 'Lat'),\n marker: {\n color: unpack(rows, 'Globvalue'),\n colorscale: scl,\n cmin: 0,\n cmax: 1.4,\n reversescale: true,\n opacity: 0.5,\n size: 3,\n colorbar:{\n thickness: 10,\n title: {side:\n 'right'\n },\n outlinecolor: 'rgba(68,68,68,0)',\n ticks: 'outside',\n ticklen: 3,\n shoticksuffix: 'last',\n ticksuffix: 'inches',\n dtick: 0.1\n }\n },\n name: 'NA Precipitation'\n }];\n\n layout = {\n dragmode: 'zoom',\n map: {\n center: {\n lat: 38.03697222,\n lon: -90.70916722\n },\n domain: {\n x: [0, 1],\n y: [0, 1]\n },\n style: 'light',\n zoom: 3\n },\n margin: {\n r: 0,\n t: 0,\n b: 0,\n l: 0,\n pad: 0\n },\n showlegend: false\n };\n\n Plotly.newPlot('myDiv', data, layout);\n });\n"}">
d3.csv('https://raw.githubusercontent.com/plotly/datasets/c34aaa0b1b3cddad335173cb7bc0181897201ee6/2011_february_aa_flight_paths.csv', function(err, rows){
    function unpack(rows, key) {
        return rows.map(function(row) { return row[key]; });}

    function getMaxOfArray(numArray) {
        return Math.max.apply(null, numArray);
    }

    var data = [];
    var count = unpack(rows, 'cnt');
    var startLongitude = unpack(rows, 'start_lon');
    var endLongitude = unpack(rows, 'end_lon');
    var startLat = unpack(rows, 'start_lat');
    var endLat = unpack(rows, 'end_lat');

    for ( var i = 0 ; i < count.length; i++ ) {
        var opacityValue = count[i]/getMaxOfArray(count);

        var result = {
            type: 'scattermap',
            lon: [ startLongitude[i] , endLongitude[i] ],
            lat: [ startLat[i] , endLat[i] ],
            mode: 'lines',
            line: {
                width: 1,
                color: 'red'
            },
            opacity: opacityValue
        };

        data.push(result);
    };

    layout = {
      dragmode: 'zoom',
      map: {
        center: {
          lat: 38.03697222,
          lon: -90.70916722
        },
        domain: {
          x: [0, 1],
          y: [0, 1]
        },
        style: 'dark',
        zoom: 2
      },
      margin: {
        r: 0,
        t: 0,
        b: 0,
        l: 0,
        pad: 0
      },
      paper_bgcolor: '#191A1A',
      plot_bgcolor: '#191A1A',
      showlegend: false
   };

  Plotly.newPlot("myDiv", data, layout, {showLink: false});

});
</script>\n\t<script src="/?originalUrl=https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fd3%2F3.5.17%2Fd3.min.js"></script>\n</head>\n\n<body>\n\t<div id='myDiv'><!-- Plotly chart will be drawn inside this DIV --></div>\n</body>","js":"d3.csv('https://raw.githubusercontent.com/plotly/datasets/c34aaa0b1b3cddad335173cb7bc0181897201ee6/2011_february_aa_flight_paths.csv', function(err, rows){\n function unpack(rows, key) {\n return rows.map(function(row) { return row[key]; });}\n\n function getMaxOfArray(numArray) {\n return Math.max.apply(null, numArray);\n }\n\n var data = [];\n var count = unpack(rows, 'cnt');\n var startLongitude = unpack(rows, 'start_lon');\n var endLongitude = unpack(rows, 'end_lon');\n var startLat = unpack(rows, 'start_lat');\n var endLat = unpack(rows, 'end_lat');\n\n for ( var i = 0 ; i < count.length; i++ ) {\n var opacityValue = count[i]/getMaxOfArray(count);\n\n var result = {\n type: 'scattermap',\n lon: [ startLongitude[i] , endLongitude[i] ],\n lat: [ startLat[i] , endLat[i] ],\n mode: 'lines',\n line: {\n width: 1,\n color: 'red'\n },\n opacity: opacityValue\n };\n\n data.push(result);\n };\n\n layout = {\n dragmode: 'zoom',\n map: {\n center: {\n lat: 38.03697222,\n lon: -90.70916722\n },\n domain: {\n x: [0, 1],\n y: [0, 1]\n },\n style: 'dark',\n zoom: 2\n },\n margin: {\n r: 0,\n t: 0,\n b: 0,\n l: 0,\n pad: 0\n },\n paper_bgcolor: '#191A1A',\n plot_bgcolor: '#191A1A',\n showlegend: false\n };\n\n Plotly.newPlot(\"myDiv\", data, layout, {showLink: false});\n\n});\n"}">

This example uses symbol attribute to set the marker symbol.

var data = [
	{
		type: "scattermap",
		mode: "markers+text+lines",
		lon: [-75, -80, -50],
		lat: [45, 20, -20],
		marker: { size: 20, symbol: ["bus", "harbor", "airport"] },
		text: ["Bus", "Harbor", "Airport"],
		textposition: "bottom right"
	}
];

var layout = {
	map: { style: "outdoors", zoom: 0.7 },
	showlegend: false, height: 500, width: 700
};

Plotly.newPlot("myDiv", data, layout);
</script>\n</head>\n\n<body>\n\t<div id='myDiv'><!-- Plotly chart will be drawn inside this DIV --></div>\n</body>","js":"var data = [\n\t{\n\t\ttype: \"scattermap\",\n\t\tmode: \"markers+text+lines\",\n\t\tlon: [-75, -80, -50],\n\t\tlat: [45, 20, -20],\n\t\tmarker: { size: 20, symbol: [\"bus\", \"harbor\", \"airport\"] },\n\t\ttext: [\"Bus\", \"Harbor\", \"Airport\"],\n\t\ttextposition: \"bottom right\"\n\t}\n];\n\nvar layout = {\n\tmap: { style: \"outdoors\", zoom: 0.7 },\n\tshowlegend: false, height: 500, width: 700\n};\n\nPlotly.newPlot(\"myDiv\", data, layout);\n"}">

> Mapbox traces are deprecated and may be removed in a future version of Plotly.js.

Earlier examples use traces that render with Maplibre GL JS. These traces were introduced in Plotly.js 2.35.0 and replace Mapbox-based tile maps, which are now deprecated. Here's one of the earlier examples using the Mapbox-based choroplethmapbox trace

var data = [{
  type:'scattermapbox',
  lat:['45.5017'],
  lon:['-73.5673'],
  mode:'markers',
  marker: {
    size:14
  },
  text:['Montreal']
}]

var layout = {
  autosize: true,
  hovermode:'closest',
  mapbox: {
    bearing:0,
    center: {
      lat:45,
      lon:-73
    },
    pitch:0,
    zoom:5
  },
}

Plotly.setPlotConfig({
  mapboxAccessToken: "your access token"
})

Plotly.newPlot('myDiv', data, layout)
</script>\n</head>\n\n<body>\n\t<div id='myDiv'><!-- Plotly chart will be drawn inside this DIV --></div>\n</body>","js":"var data = [{\n type:'scattermapbox',\n lat:['45.5017'],\n lon:['-73.5673'],\n mode:'markers',\n marker: {\n size:14\n },\n text:['Montreal']\n}]\n\nvar layout = {\n autosize: true,\n hovermode:'closest',\n mapbox: {\n bearing:0,\n center: {\n lat:45,\n lon:-73\n },\n pitch:0,\n zoom:5\n },\n}\n\nPlotly.setPlotConfig({\n mapboxAccessToken: \"your access token\"\n})\n\nPlotly.newPlot('myDiv', data, layout)\n"}">