Time map: the world

A modern 3D map with time slider for visualising events

Updated 6 years ago by Flourish team

How to use this template

A template for creating fast and beautiful maps showing events over time. Useful for any data with timestamps and locations, such as website traffic or financial transactions. Events are shown as pulses on a three-dimensional WebGL map, optionally scaled and coloured based on the data.

Panning the map

Pan the map by dragging; hold down Alt while dragging to change the angle of view.

Data Requirements

At a minimum, you need a spreadsheet of data with columns for:

  • Latitude: the latitude of the event.
  • Longitude: the longitude of the event.
  • Timestamp: the start time of the event. Be sure to set the time format for your data in the settings panel!

In addition you set columns for:

  • End timestamp: the end time of the event in the same format as the main timestamp.
  • Scale: the scale at which to draw the event.
  • Colour: a column of categories to determine the color of the event. Colors are listed in the colours spreadsheet.

Colouring events

Colours for the events are listed in a separate spreadsheet with two columns:

  • Category: should contain categories matching those in the main data sheet.
  • Colour: the desired colour, in any standard format, such as “red” (i.e. named colours), “#ffeeaa”, ”rgb(255, 255, 255)”, “hsla(120, 50%, 20%, 0.4)”.

If a matching color isn't found in the spreadsheet, a fallback colour will be used. This can be set in the settings panel.

Counter

The event counter tracks the number of events of each category over time. This also doubles as a legend. In the settings panel you can decide whether the counter should measure just the number of events or the total value of those events as specified in the “Size” column. For example, if your dataset showed financial transactions, you could scale the dots by the value of the transactions and have the counter show the cumulative value of transactions in each category.

Tips

  • Try experimenting the “Terrain” and “Ocean” colour settings to change the look of the map
  • You can drag the time slider back and forward to quickly scan through the data
  • Try making a Flourish story to capture stunning animations between different views

Credits

Created by Hugh Kennedy, inspired by Kiln’s shipmap.org.

This section documents API usage specific to this template, so for an introduction we suggest you refer to the generic API documentation instead.

template: _194

version: _18

Template data

There are three different formats in which you can supply data to this template. The most convenient for you to use likely depends on the source of your data, as described below.

1. Array of arrays, and a bindings object

You can supply arrays of arrays to opts.data, which might look like:

{
    data: {
        events: [
            [ "EventsColumn1Value1", "EventsColumn2Value1",
            [ "EventsColumn1Value2", "EventsColumn2Value2",
            [ "EventsColumn1Value3", "EventsColumn2Value3",
            ...
        ],
        colors: [
            [ "ColorsColumn1Value1", "ColorsColumn2Value1",
            [ "ColorsColumn1Value2", "ColorsColumn2Value2",
            [ "ColorsColumn1Value3", "ColorsColumn2Value3",
            ...
        ]
    }
}

where each array of arrays represents the rows in a data sheet.

To tell the API how the values from each column should be associated with the keys that the template is expecting, you must also supply an object attached to opts.bindings. (The meanings of the keys in the bindings object are documented below.) The minimal bindings you can supply for this template are as shown in this example:

{
    template: "_194",
    version: "_18",
    bindings: {
        events: {
            lat: 0, // index of a column in your data
            lon: 1, // index of a column in your data
        },
        colors: {
            category: 0, // index of a column in your data
            color: 1, // index of a column in your data
        }
    },
    data: {
        events: [
            [ "EventsColumn1Value1", "EventsColumn2Value1",
            [ "EventsColumn1Value2", "EventsColumn2Value2",
            [ "EventsColumn1Value3", "EventsColumn2Value3",
            ...
        ],
        colors: [
            [ "ColorsColumn1Value1", "ColorsColumn2Value1",
            [ "ColorsColumn1Value2", "ColorsColumn2Value2",
            [ "ColorsColumn1Value3", "ColorsColumn2Value3",
            ...
        ]
    }
}

All possible bindings that you can supply are shown in this example:

{
    template: "_194",
    version: "_18",
    bindings: {
        events: {
            lat: 0, // index of a column in your data
            lon: 1, // index of a column in your data
            start_timestamp: 2, // index of a column in your data
            end_timestamp: 3, // index of a column in your data
            metadata: [4, 5, ...], // index(es) of column(s) in your data
            category: 6, // index of a column in your data
            scale: 7, // index of a column in your data
        },
        colors: {
            category: 0, // index of a column in your data
            color: 1, // index of a column in your data
        }
    },
    data: {
        events: [
            [ "EventsColumn1Value1", "EventsColumn2Value1",
            [ "EventsColumn1Value2", "EventsColumn2Value2",
            [ "EventsColumn1Value3", "EventsColumn2Value3",
            ...
        ],
        colors: [
            [ "ColorsColumn1Value1", "ColorsColumn2Value1",
            [ "ColorsColumn1Value2", "ColorsColumn2Value2",
            [ "ColorsColumn1Value3", "ColorsColumn2Value3",
            ...
        ]
    }
}

2. Array of objects with arbitrary keys, and a bindings object

This format is most likely useful when you have data from an external source, such as CSV data loaded from d3-dsv. You should supply this attached to the opts.data, which might look like:

{
        events: [
            { "EventsHeader1": ..., "EventsHeader2": ..., ... },
            { "EventsHeader1": ..., "EventsHeader2": ..., ... },
            { "EventsHeader1": ..., "EventsHeader2": ..., ... },
            ...
        ],
        colors: [
            { "ColorsHeader1": ..., "ColorsHeader2": ..., ... },
            { "ColorsHeader1": ..., "ColorsHeader2": ..., ... },
            { "ColorsHeader1": ..., "ColorsHeader2": ..., ... },
            ...
        ]
    }

... but with the keys being the column headers from your source data instead. You must also supply an object attached to opts.bindings. The minimal bindings you can supply for this template are as shown in this example:

{
    template: "_194",
    version: "_18",
    bindings: {
        events: {
            lat: "EventsHeader1",
            lon: "EventsHeader2",
        },
        colors: {
            category: "ColorsHeader1",
            color: "ColorsHeader2",
        }
    },
    data: {
        events: [
            { "EventsHeader1": ..., "EventsHeader2": ..., ... },
            { "EventsHeader1": ..., "EventsHeader2": ..., ... },
            { "EventsHeader1": ..., "EventsHeader2": ..., ... },
            ...
        ],
        colors: [
            { "ColorsHeader1": ..., "ColorsHeader2": ..., ... },
            { "ColorsHeader1": ..., "ColorsHeader2": ..., ... },
            { "ColorsHeader1": ..., "ColorsHeader2": ..., ... },
            ...
        ]
    }
}

All possible bindings that you can supply are shown in this example:

{
    template: "_194",
    version: "_18",
    bindings: {
        events: {
            lat: "EventsHeader1",
            lon: "EventsHeader2",
            start_timestamp: "EventsHeader3",
            end_timestamp: "EventsHeader4",
            metadata: ["EventsHeader5", "EventsHeader6", ...],
            category: "EventsHeader7",
            scale: "EventsHeader8",
        },
        colors: {
            category: "ColorsHeader1",
            color: "ColorsHeader2",
        }
    },
    data: {
        events: [
            { "EventsHeader1": ..., "EventsHeader2": ..., ... },
            { "EventsHeader1": ..., "EventsHeader2": ..., ... },
            { "EventsHeader1": ..., "EventsHeader2": ..., ... },
            ...
        ],
        colors: [
            { "ColorsHeader1": ..., "ColorsHeader2": ..., ... },
            { "ColorsHeader1": ..., "ColorsHeader2": ..., ... },
            { "ColorsHeader1": ..., "ColorsHeader2": ..., ... },
            ...
        ]
    }
}

(As before, the keys containing "Header" would be replaced by column names from your data source.)

3. Array of objects with template-defined keys

There is an alternative format you can use, which is likely to be easier to use if your data is not from a spreadsheet source. With this alternative format you supply your data to the template as an array of objects, attached to opts.data, where the keys must be those used by the template, as documented below. In this case there is no need to supply a bindings object, since the key names are already those expected by the template. The required properties in the data object are as follows (scroll down for a description of what each property is):

{
    template: "_194",
    version: "_18",
    data: {
    events: [
        {
            lat: ...,
            lon: ...,
            metadata: [...]
        },
        ...
    ],
    colors: [
        {
            category: ...,
            color: ...
        },
        ...
    ]
},
    ...
}

And the full list of all possible properties is as follows:

{
    template: "_194",
    version: "_18",
    data: {
    events: [
        {
            lat: ...,
            lon: ...,
            start_timestamp: ...,
            end_timestamp: ...,
            metadata: [...],
            category: ...,
            scale: ...
        },
        ...
    ],
    colors: [
        {
            category: ...,
            color: ...
        },
        ...
    ]
},
    ...
}

Meanings of the template data keys:

  • events.lat: lat
  • events.lon: lon
  • events.start_timestamp: Determines when the circles appear. If left blank all the events will appear at once. If selected, creates a time slider and shows dots over time. The date format must be specified in the settings panel.
  • events.end_timestamp: Determines when the circles disappear. If not specified the circle remains for the default duration specified in the settings panel.
  • events.metadata: One or more columns to show in the popups
  • events.category: Used to determine the colours of the circles, as configured in the separate data sheet
  • events.scale: Determines the size of the circles.
  • colors.category: The category of the event. Should match the categories specified in the main data sheet.
  • colors.color: Can be a hex value such as “#FF7E5D” or an HTML colour name such as “red”.

Template settings

Options for opts.state.

Events

events_pulse_enabled boolean

Show events.

events_pulse_simple boolean

Allowed values:

  • false (Pulses)
  • true (Circles)

events_pulse_fallback_color color

Default colour. Circle colour when no category colour specified

events_pulse_default_scale number

Default size. The size of the circle when the “Scale” column is not selected or contains an invalid number for the given event

events_pulse_min_scale number

Min size. The smallest circle size allowed; usually best left at zero so that the sizes of the circles are proportional to the values in the data

events_pulse_max_scale number

Max size. The size of the largest circle

events_pulse_on_ocean boolean

Show events over ocean.

Event counter and graph

counter_type string

Count events. Enables the events counter and graph. Use “By count” to display the number of events, or “By size” to display the number scaled by the “Scale” column.

Allowed values:

  • off (Off)
  • count (By count)
  • scale (By size)

counter_other boolean

Include.

counter_other_label string

Label.

counter_enabled boolean

Show counter.

counter_labels boolean

Category labels.

graph_enabled boolean

Show graph.

graph_height number

Graph height (%).

label_cumulative string

“Total” label.

label_sampled string

“Rate” label.

number_prefix string

Prefix.

number_multiplier number

Multiplier.

number_decimals number

Decimals.

number_suffix string

Suffix.

timeline_bg_opacity number

Opacity of shading behind graph.

Max: 1

controls_bg_opacity number

Opacity of shading behind counter.

Max: 1

Time

events_pulse_date_format string

Date/time format in data. The date/time format in your data sheet. If it isn’t in the list, you can enter a custom format using d3-time-format syntax. See npmjs.com/package/d3-time-format for details.

Predefined values:

  • %Y-%m-%dT%H:%M:%S.%LZ (1986-01-28T11:39:13.000Z)
  • %Y-%m-%d (1986-01-28)
  • %m/%d/%Y (01/28/1986)
  • %d/%m/%Y (28/01/1986)
  • %d-%b-%y (28-Jan-86)
  • %m/%Y (01/1986)
  • %b %Y (Jan 1986)
  • %B %d (January 28)
  • %d %b (28 Jan)
  • %Y (1986)
  • %B (January)
  • %b (Jan)
  • %A (Tuesday)
  • %a (Tue)
  • %H:%M:%S (11:39:13)
  • %I:%M %p (11:39 AM)
  • %H:%M (11:39)

events_pulse_date_format_display string

Date/time format on slider. The date/time format in your data sheet. If it isn’t in the list, you can enter a custom format using d3-time-format syntax. See npmjs.com/package/d3-time-format for details.

Predefined values:

  • (Auto)
  • %Y-%m-%d (1986-01-28)
  • %m/%d/%Y (01/28/1986)
  • %d/%m/%Y (28/01/1986)
  • %d-%b-%y (28-Jan-86)
  • %m/%Y (01/1986)
  • %b %Y (Jan 1986)
  • %B %d (January 28)
  • %d %b (28 Jan)
  • %Y (1986)
  • %B (January)
  • %b (Jan)
  • %A (Tuesday)
  • %a (Tue)
  • %H:%M:%S (11:39:13)
  • %I:%M %p (11:39 AM)
  • %H:%M (11:39)

timeline_playing boolean

Play on load.

events_pulse_transition_duration number

Pulse duration. Duration in seconds of the pulse animation

Max: 5

timeline_duration number

Timeline duration. How long in seconds it takes to play through the timeline

Min: 5

timeline_speed number

Time multiplier. Speeds up or slows down the time. Affects the animations as well as the timeline. Set to 1 for normal time.

camera_transition_speed number

Pan/zoom duration. How long to spend moving the camera when changing slides in story mode, in seconds.

Popups

events_pulse_tooltips boolean

Enable popups. Display tooltips when the user hovers over an event circle, based on the column assigned for Labels

events_pulse_tooltips_custom boolean

Custom popups content. Allows you to create bespoke popups using HTML

events_pulse_tooltips_content text

Enable popups. The text to appear in the popup. You can use {{column_name}} to add a value from any selected column. You can add extra columns to “Popups” if needed. Advanced users can include HTML to apply layouts, formatting, images, etc.

Terrain

mesh_terrain_color_ground color

Ground.

mesh_terrain_color_coast color

Coast.

mesh_terrain_color_cliff color

Cliffs.

mesh_terrain_color_peak color

Peaks.

mesh_terrain_enable_lighting boolean

Enable lighting.

mesh_terrain_enable_noise boolean

Enable noise.

Fog and background

fog_color color

Colour.

fog_density number

Density.

Light

lighting_light1_color color

Light #1: Colour.

lighting_light1_polar number

Polar angle.

Min: -90

Max: 90

lighting_light1_azimuth number

Azimuth angle.

Min: -180

Max: 180

lighting_light2_color color

Light #2: Colour.

lighting_light2_polar number

Polar angle.

Min: -90

Max: 90

lighting_light2_azimuth number

Azimuth angle.

Min: -180

Max: 180

Ocean

ocean_enabled boolean

Show ocean.

ocean_color color

Water.

border_color color

Border.

ocean_stripe_color color

Stripe.

ocean_specular number

Water shininess.

border_thickness number

Border thickness.

Min: -0.05

Max: 1

ocean_stripe_opacity number

Stripe opacity.

Max: 1

ocean_stripe_thickness number

Stripe thickness.