MapHub Documentation

Documentation for MapHub.net

Choose a topic from the left side menu (☰).

Map provider keys

MapHub provides a wide range of basemaps, some of which are from commercial providers (Mapbox, ESRI, HERE, etc.).

If your map uses a commercial basemap and receives too much traffic, we ask you to sign up for the provider's free plan and add a key here.

Without a provider key, maps with heavy usage will be limited to MapHub Classic for 24 hours.

How to add map provider keys

Mapbox

HERE Maps

ESRI

Thunderforest

Mapbox provider key

How to add a Mapbox provider key to MapHub

  1. Sign up to for free account on Mapbox: link

  2. Navigate to the Tokens section on mapbox.com: link mapbox-1

  3. Under access tokens, look for Default public token, and click the blue icon to copy the token to the clipboard. You can also select the text and copy it manually. Important: make sure the token you are selecting starts with pk. mapbox-2

  4. Go to your MapHub account's Map provider keys page: link

  5. Paste the copied text to Mapbox Public Token field and click Save. maphub-basemaps

  6. Congratulations, you can now use Mapbox basemaps on MapHub.

HERE Maps provider key

How to add HERE Maps provider key to MapHub

  1. Sign up to for Freemium account on HERE Developers: link
  2. (Optional) If you don't get automatically redirected to your Projects page, navigate to your Projects page and select your Freemium project: link
  3. In the REST section, click "Generate App".
  4. Click "Create API key"
  5. Copy the generated API key
  6. Go to your MapHub account's Map provider keys page: link
  7. Paste the copied text to HERE API key and click Save. maphub-basemaps
  8. Congratulations, you can now use HERE basemaps on MapHub.

ESRI provider key

How to add ESRI provider key to MapHub

  1. Sign up for an ArcGIS Location Platform account: link
  2. On the "Confirm account details" enter anything for username, portal URL and portal display name - it doesn't matter.
  3. Verify your email and sign in.
  4. On the "Finish setting up your account" click "Skip for now" in the lower left corner.
  5. Click "Create a developer credential"
  6. Click "New item"
  7. Click "Developer credentials"
  8. Click "API key credentials" and "Next"
  9. Set Expiration date one year in the future
  10. Enable Basemaps
  11. Skip the "Grant item access" screen.
  12. Write any title for "Title" on the next screen, like "basemaps"
  13. Generate key first choice
  14. Copy the key, and temporarily paste it somewhere, like in a text file or note. This dialog is only displayed once.
  15. Go to your MapHub account's Map provider keys page: link
  16. Paste the copied text to ESRI API key and click Save. maphub-basemaps
  17. Congratulations, you can now use ESRI basemaps on MapHub.

After one year

In one year, when the API key expires, you can renew it by clicking on this button:

After, you can select today's date next year:

Finally, this key needs to be entered on MapHub's Map provider keys page: link, like before.

Thunderforest provider key

How to add a Thunderforest provider key to MapHub

  1. Sign up to a free Hobby Project account on Thunderforest Maps: link

    thunderforest-1

  2. Confirm your account via the verification email.

  3. Log in with your registered credentials.

  4. Copy the API Key from the dashboard. thunderforest-2

  5. Go to your MapHub account's Map provider keys page: link

  6. Paste the copied text to Thunderforest API key field and click Save. maphub-basemaps

  7. Congratulations, you can now use Thunderforest basemaps on MapHub.

Import and Export

Import

XLSX / CSV import

XLSX / CSV import

MapHub supports importing data from CSV or XLSX files. We recommend using the XLSX format.

When uploading a table file, MapHub tries to guess the right file format. The only requirements is to have the following 2 columns present:

  • lat or latitude, as a number. For example New York is 40.71
  • lon, long, lng or longitude, as a number. For example New York is -74.00

If your data does not have these columns, follow the tutorial which explains how to convert street addresses to lat-lon coordinate pairs:

Converting addresses to lat-lon coordinates

Other columns

(all of these are optional)

  • title or name - the title of the item

  • description or desc - the description of the item, Markdown supported

  • group - the name of the item's group

  • url - a link URL

  • color - hex code for the item's color, for example #CC1B15

  • visible - true/false - if the item is visible (true) or hidden (false). Also accepts 1/0.

  • media_url - a media URL, for example a YouTube video.

  • icon - a MapHub icon id

  • maphub_image_url - allows you to set an image for an item. You have to previously upload that image onto a map and export that map as a CSV or XLSX file to get these values.

Sample data

On the following map, you can click Download / Excel XLSX or CSV to get a sample file:

XLSX / CSV sample

MapHub API

The HTTP API is inspired by the Dropbox API v2.

  1. MapHub API uses HTTP POST requests with JSON arguments and JSON responses.

  2. Request authentication is via API keys using the Authorization: Token <api_key> request header.

  3. You can create API keys from the Settings page:

  4. To use the API, you need to verify your email address.

  5. Errors are returned in the error JSON field, status code is always 200.

    A successful response has no error field.

Request and response formats

Endpoints accept arguments as JSON in the request body and return results as JSON in the response body.

The Upload and Append endpoints accept file content in the request body, so their arguments are instead passed as JSON in the MapHub-API-Arg request header.

Endpoints

You can see the currently implemented endpoints in the left side menu.

If you'd like to see more API endpoints or need some added features, please contact us.

MapHub Enterprise API usage

The API for Enterprise users is the same as with the public website, except the maphub.net URL is changed to your server's URL. For example, instead of

https://maphub.net/api/1/map/list

please use

https://companyname.maphub.net/api/1/map/list

MapHub API

The HTTP API is inspired by the Dropbox API v2.

  1. MapHub API uses HTTP POST requests with JSON arguments and JSON responses.

  2. Request authentication is via API keys using the Authorization: Token <api_key> request header.

  3. You can create API keys from the Settings page:

  4. To use the API, you need to verify your email address.

  5. Errors are returned in the error JSON field, status code is always 200.

    A successful response has no error field.

Request and response formats

Endpoints accept arguments as JSON in the request body and return results as JSON in the response body.

The Upload and Append endpoints accept file content in the request body, so their arguments are instead passed as JSON in the MapHub-API-Arg request header.

Endpoints

You can see the currently implemented endpoints in the left side menu.

If you'd like to see more API endpoints or need some added features, please contact us.

MapHub Enterprise API usage

The API for Enterprise users is the same as with the public website, except the maphub.net URL is changed to your server's URL. For example, instead of

https://maphub.net/api/1/map/list

please use

https://companyname.maphub.net/api/1/map/list

List maps

https://maphub.net/api/1/map/list

List all maps available for the user.

Arguments

This endpoint takes no arguments.

Response

The response returns 3 keys, each containing list of maps:

  • owner: the user's maps
  • editor: maps where the user can edit, but is not the owner
  • viewer: maps where the user can view, but cannot edit and is not the owner

For each map in the lists, the following properties are returned:

  • id: id of the map
  • url: URL of the map
  • owner: map owner's username
  • short_name: short name of the map, used in the URL
  • title: title of the map
  • visibility: visibility mode of the map. One of public, unlisted, private, select.

Code example

curl

curl https://maphub.net/api/1/map/list \
    --header 'Authorization: Token <api_key>' \
    --data-raw ''

Python

import requests

url = 'https://maphub.net/api/1/map/list'

api_key = '<api_key>'

headers = {'Authorization': 'Token ' + api_key}
r = requests.post(url, headers=headers)

print(r.json())

Get map

https://maphub.net/api/1/map/get

Get all information about single map, including GeoJSON.

Arguments

  • map_id (required): the id of the map. To find out a map's id, please use the list maps endpoint.

Response

The response returns the following keys:

  • id: The id of the map.

  • url: The full URL of the map.

  • owner: The map owner's username.

  • short_name: The short name of the map, used in the URL.

  • title: The title of the map.

  • description: The description of the map.

  • geojson: The GeoJSON for the map. This includes information related to groups, custom icons and images as well.

  • basemap: The basemap used by the map.

  • visibility: The visibility mode of the map. One of public, unlisted, private, select.

  • collaborate: Whether collaboration is enabled/disabled for the map. True/False

  • viewer_users: The list of specified viewers, if visibility mode is select .

  • editor_users: The list of editors, if collaboration is enabled.

  • created_date: The date when the map was created. ISO datetime string in UTC timezone.

  • modified_date: The date when the map was last updated. ISO datetime string in UTC timezone.

  • images: The list of image ids present in the map's GeoJSON.

  • markers: The list of marker ids present in the map's GeoJSON. Markers = custom icons on the web interface.

Code example

curl

curl https://maphub.net/api/1/map/get \
    --header 'Authorization: Token <api_key>' \
    --data-raw '{"map_id": 12345}'

Python

import requests

url = 'https://maphub.net/api/1/map/get'

api_key = '<api_key>'

args = {
    'map_id': 12345,
}

headers = {'Authorization': 'Token ' + api_key}
r = requests.post(url, json=args, headers=headers)

print(r.json())

Upload map

https://maphub.net/api/1/map/upload

Upload a file and create a new map.

When empty is used for file_type, an empty map will be created.

A static image is automatically generated for the uploaded map.

For this endpoint you'll need to

  • send the arguments as a JSON encoded string in the MapHub-API-Arg header
  • send the uploaded file as binary data in the request body (except with empty file_type)

Arguments

  • file_type (required): one of empty, kml, gpx, geojson. For ".kmz" files, use kml
  • visibility (required): The visibility option of the map. One of public, unlisted, private.
  • title (optional): the preferred title of the map
  • description (optional): the preferred description of the map
  • short_name (optional): the short name of the map, visible in the URL. This is just a preference, the final URL will be returned in the response.

Response

  • id: id of the map
  • url: URL of the map
  • owner: map owner's username
  • short_name: short name of the map, used in the URL
  • title: title of the map
  • visibility: visibility mode of the map. One of public, unlisted, private, select.

Limitations

Following limits apply to uploads:

  • maximum file size 15 MB
  • maximum processing time 2 minutes

On a MapHub Enterprise server, there are no limits. If you are interested in MapHub Enterprise, contact us.

Code example

curl with file

curl https://maphub.net/api/1/map/upload \
    --header 'Authorization: Token <api_key>' \
    --header 'MapHub-API-Arg: {"file_type": "gpx", "visibility": "public"}' \
    --data-binary @test.gpx

curl with geojson data

curl https://maphub.net/api/1/map/upload \
    --header 'Authorization: Token <api_key>' \
    --header 'MapHub-API-Arg: {"file_type": "geojson", "visibility": "public"}' \
    --data-raw '{"type": "FeatureCollection", "features": [{"type": "Feature", "geometry": {"type": "Point", "coordinates": [12.34, 56.78]}, "properties": {"title": "Test point", "description": "Test description", "group": 12345}}], "groups": [{"title": "Test group", "id": 12345}]}'

Python with file

import json
import requests

url = 'https://maphub.net/api/1/map/upload'

api_key = '<api_key>'

args = {
    'file_type': 'gpx',
    'title': 'Sample Title',
    'short_name': 'short name',
    'visibility': 'public',
}

headers = {
    'Authorization': 'Token ' + api_key,
    'MapHub-API-Arg': json.dumps(args),
}

with open('test.gpx', 'rb') as f:
    r = requests.post(url, headers=headers, data=f)

print(r.json())

Python with geojson data

import json
import requests

url = 'https://maphub.net/api/1/map/upload'

api_key = '<api_key>'

args = {
    'file_type': 'geojson',
    'title': 'Sample Title',
    'short_name': 'short name',
    'visibility': 'public',
}

headers = {
    'Authorization': 'Token ' + api_key,
    'MapHub-API-Arg': json.dumps(args),
}

geojson = {
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "geometry": {"type": "Point", "coordinates": [12.34, 56.78]},
            "properties": {
                "title": 'Test point',
                "description": 'Test description',
                "group": 12345,
            },
        }
    ],
    "groups": [{"title": 'Test group', "id": 12345}],
}


r = requests.post(url, headers=headers, data=json.dumps(geojson))
print(r.json())

Python empty map

import json
import requests

url = 'https://maphub.net/api/1/map/upload'

api_key = '<api_key>'

args = {
    'file_type': 'empty',
    'title': 'Sample Title',
    'short_name': 'short name',
    'visibility': 'public',
}

headers = {
    'Authorization': 'Token ' + api_key,
    'MapHub-API-Arg': json.dumps(args),
}


r = requests.post(url, headers=headers)
print(r.json())

Update map

https://maphub.net/api/1/map/update

Update a map, including the GeoJSON.

For GeoJSON it means that the contents of the whole map is replaced with the new supplied geojson data.

Only the included arguments will be updated. For example if only short_name is included, nothing else will be changed.

When updating the GeoJSON of a map, images and markers are "linked", you do not need to upload them again.

Static map image is not updated automatically. If you'd like to update it, call the refresh map image endpoint manually.

A new map version is not saved.

Arguments

  • map_id (required): the id of the map. To find out a map's id, please use the list maps endpoint.

  • title (optional): The title of the map.

  • short_name (optional): The short name of the map, used in the URL.

  • description (optional): The description of the map.

  • geojson (optional): The GeoJSON for the map. This includes information related to groups, custom icons and images as well.

  • basemap (optional): The basemap used by the map.

  • visibility (optional): The visibility setting of the map. One of public, unlisted, private.

Response

  • id: id of the map
  • url: URL of the map
  • owner: map owner's username
  • short_name: short name of the map, used in the URL
  • title: title of the map
  • visibility: visibility mode of the map. One of public, unlisted, private, select.

Code example

curl

curl https://maphub.net/api/1/map/update \
    --header 'Authorization: Token <api_key>' \
    --data-raw '{"map_id": 12345, "short_name": "test_short_name_abc", "title": "Test Title ABC", "geojson": {"type": "FeatureCollection", "features": [{"type": "Feature", "geometry": {"type": "Point", "coordinates": [12.34, 56.78]}, "properties": {"title": "Test point", "description": "Test description", "group": 12345}}], "groups": [{"title": "Test group", "id": 12345}]}}'

Python

import requests

url = 'https://maphub.net/api/1/map/update'

api_key = '<api_key>'

geojson = {
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "geometry": {"type": "Point", "coordinates": [12.34, 56.78]},
            "properties": {
                "title": 'Test point',
                "description": 'Test description',
                "group": 12345,
            },
        },
        {
            "type": "Feature",
            "geometry": {"type": "Point", "coordinates": [13.34, 57.78]},
            "properties": {
                "title": 'Test point 2',
                "description": 'Test description',
                "group": 12345,
            },
        }
    ],
    "groups": [{"title": 'Test group', "id": 12345}],
}

args = {
    'map_id': 12345,
    'short_name': 'test_short_name_abc',
    'title': 'Test Title ABC',
    'geojson': geojson,
}

headers = {'Authorization': 'Token ' + api_key}
r = requests.post(url, json=args, headers=headers)

print(r.json())

Append map

https://maphub.net/api/1/map/append

Upload a file and append to an existing map.

Static map image is not updated automatically. If you'd like to update it, call the refresh map image endpoint manually.

A new map version is not saved.

For this endpoint you'll need to

  • send the arguments as a JSON encoded string in the MapHub-API-Arg header
  • send the uploaded file as binary data in the request body

Arguments

  • map_id (required): The id of the map. To find out a map's id, please use the list maps endpoint.
  • file_type (required): One of kml, gpx, geojson. For ".kmz" files, use kml
  • new_group (optional): A string, specifying the title of a new group. If specified, a new group will be created and all new items will be placed into this group.

Response

  • id: id of the map
  • url: URL of the map
  • owner: map owner's username
  • short_name: short name of the map, used in the URL
  • title: title of the map
  • visibility: visibility mode of the map. One of public, unlisted, private, select.

Limitations

Following limits apply to uploads:

  • maximum file size 15 MB
  • maximum processing time 2 minutes

On a MapHub Enterprise server, there are no limits. If you are interested in MapHub Enterprise, contact us.

Code example

curl with file

curl https://maphub.net/api/1/map/append \
    --header 'Authorization: Token <api_key>' \
    --header 'MapHub-API-Arg: {"map_id": 12345, "file_type": "kml"}' \
    --data-binary @test.kml

curl with geojson data

curl https://maphub.net/api/1/map/append \
    --header 'Authorization: Token <api_key>' \
    --header 'MapHub-API-Arg: {"map_id": 12345, "file_type": "geojson"}' \
    --data-raw '{"type": "FeatureCollection", "features": [{"type": "Feature", "geometry": {"type": "Point", "coordinates": [23.45, 34.56]}, "properties": {"title": "Test point", "description": "Test description", "group": 12345}}], "groups": [{"title": "Test group", "id": 12345}]}'

Python with file

import json
import requests

url = 'https://maphub.net/api/1/map/append'

api_key = '<api_key>'

args = {
    'map_id': 12345,
    'file_type': 'kml',
}

headers = {
    'Authorization': 'Token ' + api_key,
    'MapHub-API-Arg': json.dumps(args),
}

with open('test.kml', 'rb') as f:
    r = requests.post(url, headers=headers, data=f)

print(r.json())

Python with geojson data

import json
import requests

url = 'https://maphub.net/api/1/map/append'

api_key = '<api_key>'

args = {
    'map_id': 12345,
    'file_type': 'geojson',
}

headers = {
    'Authorization': 'Token ' + api_key,
    'MapHub-API-Arg': json.dumps(args),
}

geojson = {
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "geometry": {"type": "Point", "coordinates": [12.34, 56.78]},
            "properties": {
                "title": 'Test point',
                "description": 'Test description',
                "group": 2345,
            },
        }
    ],
    "groups": [{"title": 'Test group 234', "id": 2345}],
}


r = requests.post(url, headers=headers, data=json.dumps(geojson))
print(r.json())

Refresh static map image

https://maphub.net/api/1/map/refresh_image

Refresh the static image of a map.

Static map images are used by embeds and the Download / Image dialog.

If the map is using a premium basemap, you need to add the basemap's API key first.

Note: This endpoint is very resource intensive, please limit it to max. 1 call every 5 minutes.

Arguments

  • map_id (required): the id of the map. To find out a map's id, please use the list maps endpoint.

Response

The response returns the following keys:

  • id: id of the map
  • url: URL of the map
  • owner: map owner's username
  • short_name: short name of the map, used in the URL
  • title: title of the map
  • visibility: visibility mode of the map. One of public, unlisted, private, select.

Code example

curl

curl https://maphub.net/api/1/map/refresh_image \
    --header 'Authorization: Token <api_key>' \
    --data-raw '{"map_id": 12345}'

Python

import requests

url = 'https://maphub.net/api/1/map/refresh_image'

api_key = '<api_key>'

args = {
    'map_id': 12345,
}

headers = {'Authorization': 'Token ' + api_key}
r = requests.post(url, json=args, headers=headers)

print(r.json())

Upload image

https://maphub.net/api/1/image/upload

This endpoint uploads a JPG or PNG image, resizes it to responsive sizes and stores it on the server.

The endpoint returns the image_id of the uploaded image, as well as width/height and other properties that you need to use when uploading or updating a GeoJSON of map.

When updating the GeoJSON of a map, images and markers are "linked", you do not need to upload them again.

Images are automatically deleted once they are no longer used in any map.

For this endpoint you'll need to

  • send the arguments as a JSON encoded string in the MapHub-API-Arg header
  • send the uploaded file as binary data in the request body

Arguments

  • file_type (required): one of jpg, png

Response

  • image_id: the id of the image
  • width: the width of the image in pixels
  • height: the height of the image in pixels
  • tip_color: the color of the image popup's tip at the bottom center
  • avg_color: the average color of the image, displayed before loading
  • has_gps: if the image has GPS information, true/false
  • geometry: GeoJSON geometry if the image has GPS information. null if not.
  • date_str: image's original created date in a human readable text
  • date_iso: image's original created date in ISO datetime format

Limitations

Following limits apply to uploads:

  • maximum file size 15 MB
  • maximum processing time 2 minutes

On a MapHub Enterprise server, there are no limits. If you are interested in MapHub Enterprise, contact us.

Code example

curl

curl https://maphub.net/api/1/image/upload \
    --header 'Authorization: Token <api_key>' \
    --header 'MapHub-API-Arg: {"file_type": "png"}' \
    --data-binary @test.png

Python

import json
import requests

url = 'https://maphub.net/api/1/image/upload'

api_key = '<api_key>'

args = {
    'file_type': 'jpg',
}

headers = {
    'Authorization': 'Token ' + api_key,
    'MapHub-API-Arg': json.dumps(args),
}

with open('test.jpg', 'rb') as f:
    r = requests.post(url, headers=headers, data=f)

print(r.json())

Upload marker

https://maphub.net/api/1/marker/upload

Markers are custom icons which can be uploaded for points.

This endpoint uploads a PNG image, resizes it to the right size and stores it on the server.

The endpoint returns the marker_id of the uploaded marker, that you need to use when uploading or updating a GeoJSON of map.

When updating the GeoJSON of a map, images and markers are "linked", you do not need to upload them again.

Markers are automatically deleted once they are no longer used in any map.

For this endpoint you'll need to

  • send the arguments as a JSON encoded string in the MapHub-API-Arg header
  • send the uploaded file as binary data in the request body

Arguments

  • file_type (required): currently only supported: png

Response

  • marker_id: the id of the marker

Limitations

Following limits apply to uploads:

  • maximum file size 15 MB
  • maximum processing time 2 minutes

On a MapHub Enterprise server, there are no limits. If you are interested in MapHub Enterprise, contact us.

Code example

curl

curl https://maphub.net/api/1/marker/upload \
    --header 'Authorization: Token <api_key>' \
    --header 'MapHub-API-Arg: {"file_type": "png"}' \
    --data-binary @test.png

Python

import json
import requests

url = 'https://maphub.net/api/1/marker/upload'

api_key = '<api_key>'

args = {
    'file_type': 'png',
}

headers = {
    'Authorization': 'Token ' + api_key,
    'MapHub-API-Arg': json.dumps(args),
}

with open('test.png', 'rb') as f:
    r = requests.post(url, headers=headers, data=f)

print(r.json())

Converting street addresses to lat-lon coordinates using Google Sheets

Frequently, you would like to import an Excel CSV or XLSX file onto a MapHub map but you don't have lat-lon coordinates. The following tutorial shows you how to convert a table of street addresses into coordinates.

Note: If for some reason you cannot use Google Docs, there is an alternative (more complicated) tutorial using Google Earth: link

Sample data

Our sample data is the following table, containing museum names, descriptions, addresses and country. table

You can download this file here: museums.csv

Using Google Sheets

The simplest way to geocode a table is to upload it to Google Docs / Sheets and use the addon: Geocode by Awesome Table

  1. Install the addon: Geocode by Awesome Table
  2. Reload your table and click Extensions / Geocode by Awesome Table / Start Geocoding
  1. Click X and select your address column, if if's not automatically detected.
  1. Finally click the blue Geocode! button at the end. Don't click "Customize Tooltip" or "Open Map", we only need the lat-lon coordinates from this extension.
  1. After this, you can export your table in Excel XLSX format, ready to be imported to MapHub.

MapHub API tutorial
Create a map from a CSV table

This is a detailed tutorial explaining the concepts behind MapHub's API.

As part of this tutorial, you'll create a Python script, which takes a table (in CSV format) and a directory of images and creates an interactive MapHub map, entirely programmatically.

The table
titledescriptionurlicon_defaulticon_customimagelongitudelatitude
British MuseumThe world-famous British Museum...https://www.britishmuseum.org/museumbritish.jpg-0.12801851.519294
National GalleryThe crowning glory of Trafalgar Square...starnational.jpg-0.12837451.508884
Tate ModernSitting grandly on the banks of the Thames is Tate Modern...https://www.tate.org.uk/visit/tate-modernmuseumtatemodern.jpg-0.09934251.507429
Victoria and Albert MuseumThe V&A celebrates art and design with 3,000 years'...https://www.vam.ac.uk/va.pngva.jpg-0.17163751.496884
The created Map

Source code for the tutorial on GitHub: repo - zip archive

Table on Google Docs: link

Preparation

You need Python 3.6+ and the requests library. The tutorial is the same for macOS, Windows and Linux. To install requests, run

pip3 install requests

You can download all the images and the table in CSV format on the following link: zip archive. The files for this tutorial are in the map_from_table folder.

Create your API token

If you haven't done it already, you need to make an API token for MapHub. This is explained on the following page: API docs.

MapHub API tutorial
Create a map from a CSV table

This is a detailed tutorial explaining the concepts behind MapHub's API.

As part of this tutorial, you'll create a Python script, which takes a table (in CSV format) and a directory of images and creates an interactive MapHub map, entirely programmatically.

The table
titledescriptionurlicon_defaulticon_customimagelongitudelatitude
British MuseumThe world-famous British Museum...https://www.britishmuseum.org/museumbritish.jpg-0.12801851.519294
National GalleryThe crowning glory of Trafalgar Square...starnational.jpg-0.12837451.508884
Tate ModernSitting grandly on the banks of the Thames is Tate Modern...https://www.tate.org.uk/visit/tate-modernmuseumtatemodern.jpg-0.09934251.507429
Victoria and Albert MuseumThe V&A celebrates art and design with 3,000 years'...https://www.vam.ac.uk/va.pngva.jpg-0.17163751.496884
The created Map

Source code for the tutorial on GitHub: repo - zip archive

Table on Google Docs: link

Preparation

You need Python 3.6+ and the requests library. The tutorial is the same for macOS, Windows and Linux. To install requests, run

pip3 install requests

You can download all the images and the table in CSV format on the following link: zip archive. The files for this tutorial are in the map_from_table folder.

Create your API token

If you haven't done it already, you need to make an API token for MapHub. This is explained on the following page: API docs.

Step 2: Create a new map

To create an empty map, we'll call the Upload map endpoint. The core function is the following:

url = 'https://maphub.net/api/1/map/upload'

args = {
    'file_type': 'empty',
    'title': 'London Attractions',
    'short_name': 'london-attractions',
    'visibility': 'public',
}

headers = {
    'Authorization': 'Token ' + API_KEY,
    'MapHub-API-Arg': json.dumps(args),
}

res = requests.post(url, headers=headers)
data = res.json()

When used with file_type=empty, the Upload map endpoint creates a new map.

In the script, we save the returned map's id into a JSON file (map_data.json). In later steps, we'll read the map id from this JSON file.

map_data.json sample

{
  "id": 12345,
  "url": "https://maphub.net/test/london-attractions",
  "owner": "test",
  "short_name": "london-attractions",
  "title": "London Attractions",
  "visibility": "public"
}

Full script file

link

Step 3: Upload images and markers

MapHub treats images separate from maps. If you'd like to use an image in a map, you'll have to upload it first. Once an image is uploaded, you have to store the returned information about the image, so you can later use it in a map. In this tutorial, we store this information in a JSON file, next to each image.

A note about markers: markers are user-uploaded, custom icons for points. You have to upload them in advance, just like images.

The code for this step is in 2 parts:

1. Loop through each image and marker to upload them

# for each image in the images dir
for file_path in list(IMAGES_DIR.glob('*.jpg')) + list(IMAGES_DIR.glob('*.png')):
    # upload image
    upload_image_marker('image', file_path)

# for each marker in the markers dir
for file_path in MARKERS_DIR.glob('*.png'):
    # upload marker
    upload_image_marker('marker', file_path)

2. The core of the upload function:

def upload_image_marker(kind, file_path):
    # path where we store the info JSON
    info_json = file_path.parent / f'{file_path.stem}.json'

    # if the JSON file exists, the image/marker is already uploaded, skip the upload
    if info_json.is_file():
        print(f'Skipping {kind} {file_path.name}')
        return

    url = f'https://maphub.net/api/1/{kind}/upload'

    # use the file's extension as file_type
    args = {
        'file_type': file_path.suffix[1:],
    }

    headers = {
        'Authorization': 'Token ' + API_KEY,
        'MapHub-API-Arg': json.dumps(args),
    }

    with open(file_path, 'rb') as f:
        # the upload request
        res = requests.post(url, headers=headers, data=f)
        data = res.json()

    # check that upload was successful, if not print error
    if f'{kind}_id' not in data:
        print(data['error'])
        return

    # save the image_info dict to disk
    with open(info_json, 'w') as f:
        json.dump(data, f, indent=2)

image.json sample

{
  "image_id": "nnhio1dgalldkf4x",
  "width": 640,
  "height": 360,
  "tip_color": "#bfbbcb",
  "avg_color": "#8a93a9",
  "has_gps": false,
  "geometry": null,
  "date_str": null,
  "date_iso": null
}

marker.json sample

{
  "marker_id": "eeumhz32iv0yfcfn"
}

Full script file

link

Step 4: Make the GeoJSON

In this step, we'll generate a GeoJSON from the CSV table data. Later we call the Update map endpoint with the generated GeoJSON.

GeoJSON on MapHub

Every map on MapHub is stored as a GeoJSON document. All map data: points, polygons, etc. are stored in this single document. To understand the structure of a MapHub map, the best thing is to download a map you've created as GeoJSON.

You can do this by opening one of your maps on MapHub.net and clicking on the "Download" button in the right side panel and then selecting "MapHub GeoJSON".

For example, the finished map of this tutorial has the following GeoJSON:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": 515312282,
      "geometry": {
        "type": "Point",
        "coordinates": [-0.128018, 51.519294]
      },
      "properties": {
        "title": "British Museum",
        "description": "The world-famous British Museum exhibits the works of man from prehistoric to modern times, from around the world. Highlights include the Rosetta Stone, the Parthenon sculptures and the mummies in the Ancient Egypt collection.",
        "url": "https://www.britishmuseum.org/",
        "marker-symbol": "museum",
        "image": {
          "id": "pwasvdaus75tnn3w",
          "w": 640,
          "h": 360,
          "tip_color": "#bdbbcb",
          "avg_color": "#8895aa"
        }
      }
    },
    {
      "type": "Feature",
      "id": 521910492,
      "geometry": {
        "type": "Point",
        "coordinates": [-0.128374, 51.508884]
      },
      "properties": {
        "title": "National Gallery",
        "description": "The crowning glory of Trafalgar Square, London's National Gallery is a vast space filled with western European paintings from the 13th to the 19th centuries. Find works by masters such as Van Gogh, da Vinci, Botticelli, Constable, Renoir, Titian and Stubbs.",
        "marker-symbol": "star",
        "image": {
          "id": "pr1xhpavd1atxs5l",
          "w": 640,
          "h": 360,
          "tip_color": "#8d857b",
          "avg_color": "#8c8c8e"
        }
      }
    },
    {
      "type": "Feature",
      "id": 1233836134,
      "geometry": {
        "type": "Point",
        "coordinates": [-0.099342, 51.507429]
      },
      "properties": {
        "title": "Tate Modern",
        "description": "Sitting grandly on the banks of the Thames is Tate Modern, Britain's national museum of modern and contemporary art. Its unique shape is due to it previously being a power station. The gallery's restaurants offer fabulous views across the city.",
        "url": "https://www.tate.org.uk/visit/tate-modern",
        "marker-symbol": "museum",
        "image": {
          "id": "yibgsqadfifyaste",
          "w": 640,
          "h": 360,
          "tip_color": "#8493ab",
          "avg_color": "#9c9ea1"
        }
      }
    },
    {
      "type": "Feature",
      "id": 3383498660,
      "geometry": {
        "type": "Point",
        "coordinates": [-0.171637, 51.496884]
      },
      "properties": {
        "title": "Victoria and Albert Museum",
        "description": "The V&A celebrates art and design with 3,000 years' worth of amazing artefacts from around the world. A real treasure trove of goodies, you never know what you'll discover next: furniture, paintings, sculpture, metalwork and textiles; the list goes on.",
        "url": "https://www.vam.ac.uk/",
        "marker_id": "bvd5ykfilp7ekxyh",
        "image": {
          "id": "ikxqpaqycbrpannw",
          "w": 640,
          "h": 360,
          "tip_color": "#d1b896",
          "avg_color": "#725d42"
        }
      }
    }
  ],
  "groups": []
}

Note: Some keys like markers, properties and export are not displayed here, as they are not important for this tutorial.

The id fields are optional, you can leave them out and they'll be automatically created.

Creating the GeoJSON from the table data

The following function is the core of this tutorial, it creates a GeoJSON from the table data we have. It also reads information from the image and marker JSONs and inserts it into the GeoJSON.

def create_geojson_from_csv(csv_file):
    assert csv_file.is_file()

    features = []

    with open(csv_file, newline='') as f:
        # auto-detect the CSV dialect
        dialect = csv.Sniffer().sniff(f.read())
        f.seek(0)

        # use DictReader which gives a dict for each row
        reader = csv.DictReader(f, dialect=dialect)

        # for each row in the CSV file
        for row in reader:
            row = dict(row)

            lat = float(row['latitude'])
            lon = float(row['longitude'])

            # basic properties
            properties = {
                "title": row['title'],
                "description": row['description'],
                "url": row['url'],
            }

            # if we have an icon from the default set, use it
            if row['icon_default']:
                properties['marker-symbol'] = row['icon_default']

            # if we have a custom icon, use the uploaded marker
            if row['icon_custom']:
                marker_info = get_image_marker_info('marker', row['icon_custom'])
                if marker_info:
                    properties['marker_id'] = marker_info['marker_id']

            # if we have an image, use the uploaded image
            if row['image']:
                image_info = get_image_marker_info('image', row['image'])
                if image_info:
                    properties['image'] = {
                        'id': image_info['image_id'],
                        'w': image_info['width'],
                        'h': image_info['height'],
                        'tip_color': image_info['tip_color'],
                        'avg_color': image_info['avg_color'],
                    }

            # create the GeoJSON for the item
            feature = {
                "type": "Feature",
                "geometry": {"type": "Point", "coordinates": [lon, lat]},
                "properties": properties,
            }
            features.append(feature)

    geojson = {
        "type": "FeatureCollection",
        "features": features,
    }

    return geojson

The core of get_image_marker_info helper function:

def get_image_marker_info(kind, file_name):
    assert kind in {'image', 'marker'}

    if kind == 'image':
        file_path = IMAGES_DIR / file_name
    else:
        file_path = MARKERS_DIR / file_name

    info_json = file_path.parent / f'{file_path.stem}.json'

    with open(info_json) as f:
        return json.load(f)

In the next step, we will call the Update map endpoint with the generated GeoJSON.

Step 5: Update the map

Time to call the Update map endpoint with the generated GeoJSON from the previous step.

def update_map(geojson):
    with open(MAP_DATA_JSON) as f:
        map_data = json.load(f)

    url = 'https://maphub.net/api/1/map/update'

    args = {
        'map_id': map_data['id'],
        'geojson': geojson,
        'basemap': 'maphub-light',
        'description': (
            'Sample map for MapHub API tutorial:\n'
            '[Create a map from a table CSV file](https://docs.maphub.net/tutorials/first_map/tutorial.html)\n\n'
            'Texts and images are from visitlondon.com'
        ),
        'visibility': 'public',
    }

    headers = {'Authorization': 'Token ' + API_KEY}

    res = requests.post(url, json=args, headers=headers)
    data = res.json()

    if 'id' not in data:
        print(data['error'])
        return

    print('Map updated')
    print(json.dumps(map_data, indent=2, ensure_ascii=False))

Full script file

link

Step 6: Refresh static image

Each MapHub map has a static image, which is used in the following places:

  • Embed view, before the user clicks the "Play button".
  • The Download / Images links.
  • Small thumbnails on "My Maps" page.

Images can be refreshed in two ways:

  • Manually, when you save the map in the web interface.
  • When using the API, by using the Refresh map image endpoint.

The following function refreshes the map's image through the API.

def refresh_image():
    with open(MAP_DATA_JSON) as f:
        map_data = json.load(f)

    url = 'https://maphub.net/api/1/map/refresh_image'

    args = {
        'map_id': map_data['id'],
    }

    headers = {'Authorization': 'Token ' + API_KEY}

    res = requests.post(url, json=args, headers=headers)
    data = res.json()

    if 'id' not in data:
        print(data['error'])
        return

    print(data['message'])

Full script file

link

Creating your first map

In this tutorial, we'll create a new map, search for a place and save it to your My Maps folder.

  1. Go to MapHub.net

  2. If you haven't registered yet, in the top right corner select Sign up. Register with your chosen username and check your email to verify your account.

  3. You can see you are logged in from the top right corner's icon. That opens your personal menu.

  4. Click on the New Map button, to create a new map.

  5. Use the Search icon to search for an interesting place. After typing the name and press the Enter key to search.

  6. Click Add to save the item on your map.

  7. Click on the Map tab, give a Title to your map and save it.

  8. After saving the map, the map gets a unique URL on MapHub.net, you can see it in the browser's location bar. Using this link, later you will be able to share your map if you decide to set the visibility to "public".

  9. You can access all your saved maps by clicking the My Maps button in the top bar.

Congratulations, you've created your first map!

Adding interactive maps to a Wix website

MapHub allows you to create interactive maps, which you can then embed on a Wix website. Here is a short tutorial for it.

  1. First, create a MapHub map. If you haven't already, you can easily do it on this link: https://maphub.net/map

  2. Once you've saved your map, you'll see the the "Embed on Website" button on the right side.

    embed
  3. On Wix.com, click "Add Elements".

    addelements
  4. Select Embed code / Popular Embeds / Embed HTML.

    wix-embed
  5. Select code, and paste the "iframe" code which was generated in MapHub.

    wix-iframe
  6. For the best results on Wix.com, edit the width and height values and change them to "100%". This allows the Wix editor to set the sizes correctly.

    100percent
  7. You are done, you have embedded an interactive MapHub map into Wix.com: final website

Drawing tools in MapHub

This tutorial will introduce you to the different drawing tools in MapHub.

It starts where "Creating your first map" tutorial finished. If you haven't done it yet, we recommend you to do it first.

  1. Click My Maps and load the map you've saved previously, by clicking on it.

  2. Once the map loads, you can see the drawing tools on the left side of the map.

Point tool

The point tool allows you to create new points (or markers).

  1. Select the point tool and click somewhere on the map. Once added, these points are shown with a blue icon by default.

  2. You'll also see a popup appearing.

  3. Have a look at the right side Item menu. Using the Title and Description fields, you can customize the display of the popup. Scroll down, and you can customize the Color and Icon as well.

  4. You can also upload a custom PNG file for the icon. Make sure to use one with a transparent background.

  5. If you would like to move a point, click the move icon.

  6. If you would like to delete a point, click the delete icon or press the Del / Backspace key.

Line tool

The line tool allows you to create simple or complex lines.

  1. Select the line tool and click somewhere on the map to start drawing a new line. The map goes in a "line drawing" mode.

  2. You can finish drawing by clicking on the last point, or by pressing the Enter or Esc key.

  3. In the right-side panel, you can change the color of the line and see the Length, calculated across all segments.

Editing existing lines

By clicking on an existing line, you can go to Edit mode by clicking on the following button:

  1. Editing existing points of a line can be done by dragging the white circles.

  2. Adding new points between existing points can be done by clicking on the smaller blue circles and dragging them.

  3. You can add points at the ends of the line, by Ctrl / Cmd clicking on the endpoints. In this mode, you can finish editing by clicking on the last point twice, or by pressing the Enter or Esc key.

  4. To delete points within a line, you need to click on a white circle (it displays as a green outline), and then press the Del / Backspace key, or the Delete icon in the right-side panel.

You can exit the line editing mode by clicking on the Edit mode button, or pressing the Enter or Esc key.

Converting street addresses to lat-lon coordinates using Google Earth

  1. First step, you'll need the Desktop version of Google Earth Pro app. Go to this link and click "Download Earth Pro on desktop". Download and install it.

    google1

    google2

  2. If your table is in XLSX format, you need to save it as CSV first.

  3. Open Google Earth Pro and select File / Import. Select your CSV file.

  4. On the first screen, the defaults are usually OK. If not, adjust until the columns are nicely separated. Click Next.

  5. On the next screen, select "This dataset does not contain lat/lon information...". Click Next.

    import

  6. On the next screen, choose which option describes your address format better.

    import2

  7. On the last screen, you can keep the defaults and click Finish.

  8. If there is any mistake, it'll ask you to fix the results.

  9. When asked about style template, click No:

style
  1. Right click on the csv file in Temporary Places and select Save Place As. You can use the default KMZ option.
save_place_as
  1. Go to MapHub and import the KMZ file into a map.

  2. The addresses will now display correctly, with coordinates.

    map

Congratulations for converting your addresses to coordinates.

XLSX / CSV import

MapHub supports importing data from CSV or XLSX files. We recommend using the XLSX format.

When uploading a table file, MapHub tries to guess the right file format. The only requirements is to have the following 2 columns present:

  • lat or latitude, as a number. For example New York is 40.71
  • lon, long, lng or longitude, as a number. For example New York is -74.00

If your data does not have these columns, follow the tutorial which explains how to convert street addresses to lat-lon coordinate pairs:

Converting addresses to lat-lon coordinates

Other columns

(all of these are optional)

  • title or name - the title of the item

  • description or desc - the description of the item, Markdown supported

  • group - the name of the item's group

  • url - a link URL

  • color - hex code for the item's color, for example #CC1B15

  • visible - true/false - if the item is visible (true) or hidden (false). Also accepts 1/0.

  • media_url - a media URL, for example a YouTube video.

  • icon - a MapHub icon id

  • maphub_image_url - allows you to set an image for an item. You have to previously upload that image onto a map and export that map as a CSV or XLSX file to get these values.

Sample data

On the following map, you can click Download / Excel XLSX or CSV to get a sample file:

XLSX / CSV sample