Skip to content

Instantly share code, notes, and snippets.

Last active Apr 30, 2019
What would you like to do?
Perspective Maps with Citibikes
height: 650
border: no
license: apache-2.0

Perspective Maps with Citibikes

This example uses live and updating data from NYC Citibikes, as demostrated in Andrew Stein's blog article: NYC Citybike Analytics in Real-Time

Copyright (c) 2017, the Perspective Authors.
This file is part of the Perspective library, distributed under the terms of
the Apache License 2.0. The full license can be found in the LICENSE file.
<!DOCTYPE html>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<!-- include polyfills for custom event, Symbol and Custom Elements -->
<script src="//"></script>
<script src="//"></script>
<script src="//"></script>
use babel so that we can use arrow functions and other goodness in this block!
<script src="//"></script>
<script src=""></script>
<script src=""></script>
<script src=""></script>
<script src=""></script>
<script src=""></script>
<link rel='stylesheet' href="" is="custom-style">
perspective-viewer {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
--map-tile-url: "http://{a-c}{z}/{x}/{y}.png"
<perspective-viewer view="map_points" row-pivots='["name"]' columns='["lon","lat","num_bikes_available"]'
function get(url) {
return new Promise(resolve => {
const xhr = new XMLHttpRequest();"GET", url, true);
xhr.responseType = "json";
xhr.onload = () => resolve(xhr.response);
async function get_feed(feedname, callback) {
const url = `${feedname}.json`;
const {data: {stations}, ttl} = await get(url);
if (typeof callback === "function") {
setTimeout(() => get_feed(feedname, callback), ttl * 1000);
} else {
return stations;
const worker = perspective.worker();
async function get_schema(feed) {
const table = worker.table(feed);
const schema = await table.schema();
return schema;
async function merge_schemas(feeds) {
const schemas = await Promise.all(;
return Object.assign({}, ...schemas);
async function main() {
const feednames = ["station_status", "station_information"];
const feeds = await Promise.all(;
const schema = await merge_schemas(feeds);
const table = worker.table(schema, {index: "station_id"});
for (let feed of feeds) {
get_feed("station_status", table.update);
const viewers = document.getElementsByTagName("perspective-viewer");
for (viewer of viewers) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment