topojson / topojson-client

Manipulate TopoJSON, such as to merge shapes, and convert it back to GeoJSON.
ISC License
213 stars 63 forks source link

suggestion: format topojson neighbors the same way as a force links object #15

Closed katossky closed 7 years ago

katossky commented 7 years ago

Because I am working with both right now, I am wondering why links objects (from d3.force) and neighbors objects (from d3.geo) are structured differently, whereas they are substantially equivalent.

Since neighbors are, to my knowledge, not used directly in any subsequent functions, I would suggest to structure them as links objects.

Fil commented 7 years ago

The most prominent example of topojson.neighbors (the map coloring) uses this structure as a lookup table, something which is not easy to do with a list of links. (IOW, adjacency matrix vs adjacency list.)

It's a bit painful to switch from one representation to the other, in both directions. Here's my method (maybe not the best):

converting neighbors to links is relatively straightforward:

neighbors2links = (neighbors, objects) => d3.merge(
  neighbors
    .map((n,i) => n.map(j => j > i ? { source: objects[i], target: objects[j] } : null)
  .filter(link => !!link))
);

to convert links to neighbors we need the nodes to have an index, or create it on the fly:

   links2neighbors = (links, objects) => {
    var neigh = [];
    objects.forEach((d,i) => d.index = i); // create the index
    links.forEach(d => {
      neigh[d.source.index] = (neigh[d.source.index] || []).concat([d.target.index]);
      neigh[d.target.index] = (neigh[d.target.index] || []).concat([d.source.index]);
    });
    return neigh.map((d,i) => neigh[i].sort()); 
  }

both algorithms are linear (in O(V) and O(V+E)).

Maybe the question is not so much about changing topojson-client than wanting a d3-graph library.

mbostock commented 7 years ago

Thanks for the suggestion. As @Fil suggests both representations can be useful in different contexts, so I don’t plan on changing from an adjacency matrix to an adjacency list. Though it might be neat to think about a more fleshed-out topology (or network) API…