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

csvjson: Support types other than Point #867

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 48 additions & 10 deletions csvkit/utilities/csvjson.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,40 @@ def dump_json(data, newline=False):
)

features = []

global min_lon, min_lat, max_lon, max_lat

min_lon = None
min_lat = None
max_lon = None
max_lat = None

def update_boundary_lat(lat):
global min_lat, max_lat

if min_lat is None or lat < min_lat:
min_lat = lat
if max_lat is None or lat > max_lat:
max_lat = lat

def update_boundary_lon(lon):
global min_lon, max_lon

if min_lon is None or lon < min_lon:
min_lon = lon
if max_lon is None or lon > max_lon:
max_lon = lon

def update_boundary_coords(coords):
if (isinstance(coords, list) and len(coords) == 2 and
isinstance(coords[0], (float, int)) and
isinstance(coords[1], (float, int))):
update_boundary_lon(coords[0])
update_boundary_lat(coords[1])
else:
for coord in coords:
update_boundary_coords(coord)

lat_column = match_column_identifier(table.column_names, self.args.lat, self.args.zero_based)
lon_column = match_column_identifier(table.column_names, self.args.lon, self.args.zero_based)

Expand All @@ -110,39 +139,48 @@ def dump_json(data, newline=False):
feature['type'] = 'Feature'
properties = OrderedDict()
geoid = None
geo_type = 'Point'
lat = None
lon = None
coords = None

for i, c in enumerate(row):
if i == lat_column:
if c is None:
continue
try:
lat = float(c)
except ValueError:
lat = None
if min_lat is None or lat < min_lat:
min_lat = lat
if max_lat is None or lat > max_lat:
max_lat = lat
update_boundary_lat(lat)
elif i == lon_column:
if c is None:
continue
try:
lon = float(c)
except ValueError:
lon = None
if min_lon is None or lon < min_lon:
min_lon = lon
if max_lon is None or lon > max_lon:
max_lon = lon
update_boundary_lon(lon)
elif i == id_column:
geoid = c
elif table.column_names[i] == 'type':
geo_type = c
elif table.column_names[i] == 'geojson':
geojson = json.loads(c)
coords = geojson['coordinates']
update_boundary_coords(coords)
elif c is not None:
properties[table.column_names[i]] = c

if id_column is not None:
feature['id'] = geoid

if lon and lat:
coords = [lon, lat]

feature['geometry'] = OrderedDict([
('type', 'Point'),
('coordinates', [lon, lat])
('type', geo_type),
('coordinates', coords)
])
feature['properties'] = properties
features.append(feature)
Expand Down
32 changes: 31 additions & 1 deletion tests/test_utilities/test_csvjson.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def test_duplicate_keys(self):
self.assertRaisesRegex(ValueError, 'Value True is not unique in the key column.', utility.run)
output_file.close()

def test_geojson(self):
def test_geojson_point(self):
geojson = json.loads(self.get_output(['--lat', 'latitude', '--lon', 'longitude', 'examples/test_geo.csv']))

self.assertEqual(geojson['type'], 'FeatureCollection')
Expand All @@ -83,6 +83,36 @@ def test_geojson(self):
self.assertTrue(isinstance(geometry['coordinates'][0], float))
self.assertTrue(isinstance(geometry['coordinates'][1], float))

def test_geojson_shape(self):
geojson = json.loads(self.get_output(['--lat', 'latitude', '--lon', 'longitude', 'examples/test_geojson.csv']))

self.assertEqual(geojson['type'], 'FeatureCollection')
self.assertFalse('crs' in geojson)
self.assertEqual(geojson['bbox'], [100.0, 0.0, 105.0, 1.0])
self.assertEqual(len(geojson['features']), 3)

for feature in geojson['features']:
self.assertEqual(feature['type'], 'Feature')
self.assertFalse('id' in feature)
self.assertIn('properties', feature)
self.assertIsInstance(feature['properties'], dict)
self.assertIn('prop0', feature['properties'].keys())

geometry = feature['geometry']

self.assertIn('coordinates', geometry)
self.assertIsNotNone(geometry['coordinates'])

self.assertEqual(geojson['features'][0]['geometry']['type'], 'Point')
self.assertEqual(geojson['features'][1]['geometry']['type'], 'LineString')
self.assertEqual(geojson['features'][2]['geometry']['type'], 'Polygon')

self.assertEqual(geojson['features'][0]['geometry']['coordinates'], [102.0, 0.5])
self.assertEqual(geojson['features'][1]['geometry']['coordinates'],
[[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]])
self.assertEqual(geojson['features'][2]['geometry']['coordinates'],
[[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]])

def test_geojson_with_id(self):
geojson = json.loads(self.get_output(['--lat', 'latitude', '--lon', 'longitude', '-k', 'slug', 'examples/test_geo.csv']))

Expand Down