{"url":"https://api.github.com/gists/5323061","forks_url":"https://api.github.com/gists/5323061/forks","commits_url":"https://api.github.com/gists/5323061/commits","id":"5323061","node_id":"MDQ6R2lzdDUzMjMwNjE=","git_pull_url":"https://gist.github.com/5323061.git","git_push_url":"https://gist.github.com/5323061.git","html_url":"https://gist.github.com/mbostock/5323061","files":{".block":{"filename":".block","type":"text/plain","language":null,"raw_url":"https://gist.githubusercontent.com/mbostock/5323061/raw/703d310b399098a243a76a50bc209167e924cfd2/.block","size":17,"truncated":false,"content":"license: gpl-3.0\n","encoding":"utf-8"},"README.md":{"filename":"README.md","type":"text/markdown","language":"Markdown","raw_url":"https://gist.githubusercontent.com/mbostock/5323061/raw/6be49e1f0ba1303272cee0241c9053d77581df10/README.md","size":154,"truncated":false,"content":"A simple script for joining a GeoJSON file with external properties in a CSV or TSV file; extracted from [TopoJSON](https://github.com/mbostock/topojson).","encoding":"utf-8"},"geojoin":{"filename":"geojoin","type":"text/plain","language":"JavaScript","raw_url":"https://gist.githubusercontent.com/mbostock/5323061/raw/be4611b6de6f53fd10c58f1e3b28f49422acabd5/geojoin","size":4189,"truncated":false,"content":"#!/usr/bin/env node\n\nvar fs = require(\"fs\"),\n    optimist = require(\"optimist\"),\n    dsv = require(\"dsv\");\n\nvar argv = optimist\n    .usage(\"Usage: \\033[1mgeojoin\\033[0m [options] [file]\\n\\n\"\n\n+ \"Joins a GeoJSON file with one or more CSV or TSV properties.\")\n\n    .options(\"o\", {\n      alias: \"out\",\n      describe: \"output GeoJSON file name\",\n      default: \"/dev/stdout\",\n    })\n    .options(\"id-property\", {\n      describe: \"name of feature property to use as id\",\n      default: null\n    })\n    .options(\"p\", {\n      alias: \"properties\",\n      describe: \"names of properties to join; no name joins all properties\",\n      default: true\n    })\n    .options(\"e\", {\n      alias: \"external-properties\",\n      describe: \"CSV or TSV file to join properties (by id) to output features\"\n    })\n    .options(\"help\", {\n      describe: \"display this helpful message\",\n      default: false\n    })\n    .check(function(argv) {\n      if (argv._.length !== 1) throw new Error(\"single input GeoJSON file required\");\n      if (typeof argv.e === \"string\") argv.e = [argv.e];\n      if (!argv.e) throw new Error(\"one or more external properties required\");\n      if (typeof argv.p === \"string\") argv.p = argv.p.split(\",\");\n    })\n    .argv;\n\nif (argv.help) return optimist.showHelp();\n\n// Create a property-to-identifier function.\nvar id = argv[\"id-property\"];\nid = id == null\n    ? function(d) { return d.id; }\n    : parsePropertyId(typeof id === \"string\" ? id.split(\",\") : id);\n\n// Create the property transform function.\nvar propertyTransform = argv.p === true ? function(o, k, v) { o[k] = v; return true; }\n    : argv.p === false ? function() {}\n    : parsePropertyTransform(argv.p);\n\n// Load any external properties.\nvar externalProperties = {};\nargv.e.forEach(readExternalProperties);\n\n// Load the GeoJSON file.\nvar collection = JSON.parse(fs.readFileSync(argv._[0], \"utf8\"));\nif (collection.type !== \"FeatureCollection\") throw new Error(\"unsupported input type: \" + collection.type);\ncollection.features.forEach(function(feature) {\n  var properties0 = feature.properties,\n      properties1 = externalProperties[id(feature)],\n      properties = feature.properties = {};\n  if (properties0) for (var k in properties0) propertyTransform(properties, k, properties0[k]);\n  if (properties1) for (var k in properties1) properties[k] = properties1[k];\n});\n\n// Output JSON.\nvar json = JSON.stringify(collection);\nif (argv.o === \"/dev/stdout\") console.log(json);\nelse fs.writeFileSync(argv.o, json, \"utf8\");\n\nfunction parsePropertyId(properties) {\n  return function(d) {\n    if (d = d.properties) {\n      var id;\n      properties.some(function(p) {\n        id = /^\\+/.test(p) ? +d[p.substring(1)] : d[p];\n        if (id == null) return;\n        else if (typeof id === \"number\") isNaN(id) && (id = null);\n        else if (typeof id !== \"string\") id = id + \"\";\n        return id;\n      });\n      return id;\n    }\n  };\n}\n\nfunction parsePropertyTransform(properties) {\n  var transforms = {};\n  properties.forEach(function(target) {\n    var i = target.indexOf(\"=\"),\n        source = target,\n        number;\n\n    if (i >= 0) {\n      source = target.substring(i + 1);\n      target = target.substring(0, i);\n    }\n\n    if (number = /^\\+/.test(source)) {\n      source = source.substring(1);\n      if (i < 0) target = source;\n    }\n\n    transforms[source] = number\n        ? function(properties, value) { properties[target] = +value; }\n        : function(properties, value) { properties[target] = value; };\n  });\n  return function(properties, key, value) {\n    var transform = transforms[key];\n    return transform && value != null && (transform(properties, value), true);\n  };\n}\n\nfunction readExternalProperties(file) {\n\n  // Infer the file type from the name.\n  // If that doesn't work, look for a tab and hope for the best!\n  var type = /\\.tsv$/i.test(file) ? dsv.tsv\n        : /\\.csv$/i.test(file) ? dsv.csv\n        : text.indexOf(\"\\t\") ? dsv.tsv\n        : dsv.csv;\n\n  type.parse(fs.readFileSync(file, \"utf-8\")).forEach(function(row) {\n    var properties = externalProperties[row.id] || (externalProperties[row.id] = {});\n    for (var key in row) if (key != \"id\") propertyTransform(properties, key, row[key]);\n  });\n}\n","encoding":"utf-8"}},"public":true,"created_at":"2013-04-05T22:11:05Z","updated_at":"2016-02-09T02:07:04Z","description":"GeoJOIN","comments":0,"user":null,"comments_enabled":true,"comments_url":"https://api.github.com/gists/5323061/comments","owner":{"login":"mbostock","id":230541,"node_id":"MDQ6VXNlcjIzMDU0MQ==","avatar_url":"https://avatars.githubusercontent.com/u/230541?v=4","gravatar_id":"","url":"https://api.github.com/users/mbostock","html_url":"https://github.com/mbostock","followers_url":"https://api.github.com/users/mbostock/followers","following_url":"https://api.github.com/users/mbostock/following{/other_user}","gists_url":"https://api.github.com/users/mbostock/gists{/gist_id}","starred_url":"https://api.github.com/users/mbostock/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mbostock/subscriptions","organizations_url":"https://api.github.com/users/mbostock/orgs","repos_url":"https://api.github.com/users/mbostock/repos","events_url":"https://api.github.com/users/mbostock/events{/privacy}","received_events_url":"https://api.github.com/users/mbostock/received_events","type":"User","user_view_type":"public","site_admin":false},"forks":[{"url":"https://api.github.com/gists/5761205","user":{"login":"mpmckenna8","id":1895795,"node_id":"MDQ6VXNlcjE4OTU3OTU=","avatar_url":"https://avatars.githubusercontent.com/u/1895795?v=4","gravatar_id":"","url":"https://api.github.com/users/mpmckenna8","html_url":"https://github.com/mpmckenna8","followers_url":"https://api.github.com/users/mpmckenna8/followers","following_url":"https://api.github.com/users/mpmckenna8/following{/other_user}","gists_url":"https://api.github.com/users/mpmckenna8/gists{/gist_id}","starred_url":"https://api.github.com/users/mpmckenna8/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mpmckenna8/subscriptions","organizations_url":"https://api.github.com/users/mpmckenna8/orgs","repos_url":"https://api.github.com/users/mpmckenna8/repos","events_url":"https://api.github.com/users/mpmckenna8/events{/privacy}","received_events_url":"https://api.github.com/users/mpmckenna8/received_events","type":"User","user_view_type":"public","site_admin":false,"name":"Matthew McKenna","company":null,"blog":"mpmckenna8.github.io","location":"San Francisco","email":"mpmckenna8@me.com","hireable":true,"bio":null,"twitter_username":null,"public_repos":139,"public_gists":148,"followers":78,"following":183,"created_at":"2012-06-26T20:38:16Z","updated_at":"2022-01-12T22:05:47Z"},"id":"5761205","created_at":"2013-06-11T22:10:40Z","updated_at":"2015-12-18T09:28:59Z"}],"history":[{"user":{"login":"mbostock","id":230541,"node_id":"MDQ6VXNlcjIzMDU0MQ==","avatar_url":"https://avatars.githubusercontent.com/u/230541?v=4","gravatar_id":"","url":"https://api.github.com/users/mbostock","html_url":"https://github.com/mbostock","followers_url":"https://api.github.com/users/mbostock/followers","following_url":"https://api.github.com/users/mbostock/following{/other_user}","gists_url":"https://api.github.com/users/mbostock/gists{/gist_id}","starred_url":"https://api.github.com/users/mbostock/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mbostock/subscriptions","organizations_url":"https://api.github.com/users/mbostock/orgs","repos_url":"https://api.github.com/users/mbostock/repos","events_url":"https://api.github.com/users/mbostock/events{/privacy}","received_events_url":"https://api.github.com/users/mbostock/received_events","type":"User","user_view_type":"public","site_admin":false},"version":"57209c9c16e6285f0e57ed37d29383cd0a323d78","committed_at":"2016-02-09T02:07:01Z","change_status":{"total":1,"additions":1,"deletions":0},"url":"https://api.github.com/gists/5323061/57209c9c16e6285f0e57ed37d29383cd0a323d78"},{"user":{"login":"mbostock","id":230541,"node_id":"MDQ6VXNlcjIzMDU0MQ==","avatar_url":"https://avatars.githubusercontent.com/u/230541?v=4","gravatar_id":"","url":"https://api.github.com/users/mbostock","html_url":"https://github.com/mbostock","followers_url":"https://api.github.com/users/mbostock/followers","following_url":"https://api.github.com/users/mbostock/following{/other_user}","gists_url":"https://api.github.com/users/mbostock/gists{/gist_id}","starred_url":"https://api.github.com/users/mbostock/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mbostock/subscriptions","organizations_url":"https://api.github.com/users/mbostock/orgs","repos_url":"https://api.github.com/users/mbostock/repos","events_url":"https://api.github.com/users/mbostock/events{/privacy}","received_events_url":"https://api.github.com/users/mbostock/received_events","type":"User","user_view_type":"public","site_admin":false},"version":"6d91483d8cc8b2485372c9031ba297f1c1dd92ef","committed_at":"2013-04-05T22:11:05Z","change_status":{"total":132,"additions":132,"deletions":0},"url":"https://api.github.com/gists/5323061/6d91483d8cc8b2485372c9031ba297f1c1dd92ef"}],"truncated":false}