Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GeoJSON support #876

Merged
merged 1 commit into from
Jan 26, 2021
Merged

Add GeoJSON support #876

merged 1 commit into from
Jan 26, 2021

Conversation

dracos
Copy link
Contributor

@dracos dracos commented Jan 24, 2021

This PR hopefully adds GeoJSON support, in much the same way as Shapefiles.

I had to add another save-sheet command to the canvas so that you could save from it, that didn't appear to work on Shapefiles previously.

https://github.com/martinjc/UK-GeoJSON/blob/master/json/administrative/wal/lad.json opened with vd -f geojson lad.json and selecting the English name column as a key column gives:
image

And pressing g. with the English name column highlighted gives:
image

Hope that's useful.

@anjakefala anjakefala changed the base branch from stable to develop January 24, 2021 20:51
Copy link
Owner

@saulpw saulpw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @dracos, thanks for putting this together! Overall it looks good, just a few changes and questions.

@@ -18,7 +18,7 @@
{"filetype": "ttf", "filetype_url": "#ttf", "aliases": "otf", "requirements": "fonttools", "format": "TrueType Font", "VisiData loader": "yes", "VisiData saver": "", "version_added": "1.1", "created": "1991", "creator": "Apple", "description": "", "open format": "yes", "nestable": "", "plottable": "plottable", "format_url": "https://en.wikipedia.org/wiki/TrueType"}
{"filetype": "dot", "filetype_url": "#pcap", "aliases": "", "requirements": "", "format": "Graphviz diagram", "VisiData loader": " ", "VisiData saver": "from pcap", "version_added": "1.2", "created": "1991", "creator": "", "description": "output for pcap only", "open format": "yes", "nestable": "", "plottable": "", "format_url": "https://graphviz.gitlab.io/_pages/doc/info/lang.html"}
{"filetype": "dta", "aliases": "", "requirements": "pandas", "format": "Stata", "VisiData loader": "yes", "VisiData saver": "", "version_added": "1.2", "created": "1985", "creator": "StataCorp", "description": "", "open format": "no", "nestable": "", "plottable": "", "format_url": "https://www.loc.gov/preservation/digital/formats/fdd/fdd000471.shtml"}
{"filetype": "geojson", "filetype_url": "#shp", "aliases": "", "requirements": "", "format": "Geographic JSON", "VisiData loader": " ", "VisiData saver": "from shp", "version_added": "1.2", "created": "2008", "creator": "", "description": "derivative of JSON", "open format": "yes", "nestable": "", "plottable": "plottable", "format_url": "http://geojson.org/"}
{"filetype": "geojson", "filetype_url": "#shp", "aliases": "", "requirements": "", "format": "Geographic JSON", "VisiData loader": "yes", "VisiData saver": "", "version_added": "1.2", "created": "2008", "creator": "", "description": "derivative of JSON", "open format": "yes", "nestable": "", "plottable": "plottable", "format_url": "http://geojson.org/"}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for remembering this! Let's also change the version_added to 2.2 (which is the next release).

self.colnames[prop] = c
self.addColumn(c)

yield from Progress(features)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's yield feature in the first pass instead of doing two passes over features (and move the Progress into that for loop).

for feature in features:
for prop in feature.get('properties', {}).keys():
if prop not in self.colnames:
c = Column(name=prop, getter=getter_factory(prop))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to use ItemColumn with a nested name: "properties."+prop.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AttrColumn handles nested properties, but these are normal dicts, and ItemColumn does not handle that.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right! It really seems like it should, sorry to give you the runaround. This again tempts me to make it nestable, even at the cost of having it not work with dict keys that have . in them. But that's not for tonight, so we can keep the getter_factory for now.

self.reset()

for row in Progress(self.sourceRows):
k = tuple(col.getValue(row) for col in self.source.keyCols)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use self.source.rowkey(row).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll update the shp loader as well, presumably?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, please! Thanks for helping to keep it clean.

if (isinstance(vs, ShapeMap)):
return save_shp_geojson(vd, p, vs)

isinstance(vs, Canvas) or vd.fail("must save GeoJSON from map sheet")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only works for GeoJSONMap (not all Canvas). With the change in decorators we can remove this.

@@ -71,8 +73,7 @@ def reload(self):

self.refresh()

@VisiData.api
def save_geojson(vd, p, vs):
def save_shp_geojson(vd, p, vs):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should actually be save_geojson with @ShapeMap.api decorator.

@@ -83,7 +84,7 @@ def save_geojson(vd, p, vs):
'coordinates': [[x, y] for x, y in coords],
},
'properties': {
col.name: col.getTypedValue(row) for col in vs.source.visibleCols
col.name: col.getTypedValue(row) for col in vs.source.keyCols
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the one change I'm not sure of...don't we want all the visibleCols as saved properties? Does some other GeoJSON tool balk at unneeded columns?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what I thought here, I guess I confused key with visible. Will revert


@VisiData.api
def save_geojson(vd, p, vs):
if (isinstance(vs, ShapeMap)):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't needed if we use the @GeoJSONMap.api decorator (instead of @VisiData.api`). Then we'd also change the original save_geojson (noted below).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made this change (and similar shp one), but I now get "no function to save as type geojson" on both maps.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, that should have worked. Unfortunately I'm out of steam for tonight. I'll take a look at this tomorrow and we'll hopefully get this merged just in time for 2.2!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dracos Please update your visidata fork, it should work now with this change! 5849b88

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Yes, that seems to have worked.

fp.write(chunk)

GeoJSONSheet.addCommand('.', 'plot-row', 'vd.push(GeoJSONMap(name+"_map", sheet, sourceRows=[cursorRow], textCol=cursorCol, source=sheet))', 'plot geospatial vector in current row')
GeoJSONSheet.addCommand('g.', 'plot-rows', 'vd.push(GeoJSONMap(name+"_map", sheet, sourceRows=rows, textCol=cursorCol, source=sheet))', 'plot all geospatial vectors in current sheet')
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about changing g. to be plot-selected and have them use someSelectedRows?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, g. to me implies global-plot. I'd say if anything . on its own should plot current row if no selection, or selected rows if some selected.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean. To be honest, plotting only the current row has never been very useful, so I wonder if . itself should be someSelectedRows, and g. should always be "all rows". That wouldn't be consistent with most of the TableSheet g bindings though. Thoughts for another PR 🧷


GeoJSONSheet.addCommand('.', 'plot-row', 'vd.push(GeoJSONMap(name+"_map", sheet, sourceRows=[cursorRow], textCol=cursorCol, source=sheet))', 'plot geospatial vector in current row')
GeoJSONSheet.addCommand('g.', 'plot-rows', 'vd.push(GeoJSONMap(name+"_map", sheet, sourceRows=rows, textCol=cursorCol, source=sheet))', 'plot all geospatial vectors in current sheet')
InvertedCanvas.addCommand('^S', 'save-sheet', 'vd.saveSheets(inputPath("save to: ", value=getDefaultSaveName(sheet)), sheet, confirm_overwrite=options.confirm_overwrite)', 'save current sheet to filename in format determined by extension (default .tsv)')
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe ultimately this should go on BaseSheet, but for now I think this should be on GeoJSONSheet specifically and not all InvertedCanvas.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GeoJSONSheet already has a save-sheet on it, do you mean GeoJSONMap?

@dracos dracos requested a review from saulpw January 25, 2021 08:17
This adds loading and saving support for GeoJSON files, and fixes
the Shapefile GeoJSON saving.
Copy link
Owner

@saulpw saulpw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again @dracos!

@saulpw saulpw merged commit b201946 into saulpw:develop Jan 26, 2021
@aborruso
Copy link
Contributor

@dracos thank you very much!

How view a geojson in vd?

@anjakefala
Copy link
Collaborator

@aborruso Update your installed VisiData to the most recent develop! There will be a release sometime this week. =)

@aborruso
Copy link
Contributor

I know it and I have already updated it.

When I open a geojson I see this. Do I must use only point layer?

Thank you

image

@dracos
Copy link
Contributor Author

dracos commented Jan 26, 2021

How did you open it, and what is its filename? Its filename needs to end with .geojson or you open it with -f geojson as in my description in the PR body.

@aborruso
Copy link
Contributor

Hi @dracos thank you again. I have opened it using vd aree.geojson.

And it's the same if I use -f geojson.

I have saul.pw/VisiData v2.2dev

@anjakefala
Copy link
Collaborator

@aborruso I think you are likely referencing an earlier commit of VisiData 2.2dev in your environment. =(

@aborruso
Copy link
Contributor

@anjakefala I'm installing it using pip3 install --no-warn-script-location git+https://github.com/saulpw/visidata.git@develop

@anjakefala
Copy link
Collaborator

anjakefala commented Jan 26, 2021

@aborruso I would try to completely uninstall all versions of VisiData (pip3 uninstall visidata), and use a search to hunt for any stray files in your computer, and then install. If you are still having trouble after doing that, I will take a look!

@aborruso
Copy link
Contributor

I have it, I have added --upgrade

Now that I have a table, how to render the geoms?

Thank you

image

@aborruso
Copy link
Contributor

Using g ., it's great!!!

@dracos
Copy link
Contributor Author

dracos commented Jan 26, 2021

As per the instructions I gave in the PR body, (. for a single row, or) g. for all rows (though see discussion above about how that may change in future). Glad to hear it.

@anjakefala
Copy link
Collaborator

Yay @aborruso 💜!! I am so glad.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants