[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[python #MFJ-706941]: Regarding Geojson for LineStyle vice Point



Hello! Thanks for reaching out.

First, to address your questions about your GeoJSON data here:

We don't currently have any MetPy functionality or any examples for GeoJSON 
data. However, we do have a contributor working right now on enabling 
simplified plotting of GeoJSON data within MetPy using GeoPandas 
(https://geopandas.org/). Separate to that, we do plan to create a few examples 
of working with data like these in Python in the future.

For what you've provided today: as far as I can tell, the JSON you've created 
here is not a valid "FeatureCollection" and does not follow current GeoJSON 
specification. A "FeatureCollection" must have members of name "Feature", each 
containing a "Geometry" member, which your "LineString"s would fall under. 
Check out https://geojsonlint.com and the Feature > FeatureCollection demo at 
the top to see a valid representation of this. You can also double-check with 
the current GeoJSON specification document: 
https://datatracker.ietf.org/doc/html/rfc7946. So, your generated data here are 
close and are valid JSON, but are not valid GeoJSON. If you want your current 
code to do this in a valid way, you can add your LineStrings to a Feature 
first; here's a brief code example:

  import geojson

  lat_1 = [25.5, 25.8, 27.9]
  lat_2 = [26.5, 26.8, 28.9]

  lon_1 = [-85, -86, -87.5]
  lon_2 = [-84, -85, -86.5]

  my_linestring_1 = geojson.LineString(list(zip(lon_1, lat_1)))
  my_linestring_2 = geojson.LineString(list(zip(lon_2, lat_2)))

  my_feature_1 = geojson.Feature(geometry=my_linestring_1)
  my_feature_2 = geojson.Feature(geometry=my_linestring_2)

  my_collection = geojson.FeatureCollection([my_feature_1, my_feature_2])

  my_geojson = geojson.dumps(my_collection)

  with open(outfile, 'w') as f:
    f.write(my_geojson)

which results in the following valid GeoJSON,

{"type": "FeatureCollection", "features": [{"type": "Feature", "geometry": 
{"type": "LineString", "coordinates": [[-85, 25.5], [-86, 25.8], [-87.5, 
27.9]]}, "properties": {}}, {"type": "Feature", "geometry": {"type": 
"LineString", "coordinates": [[-84, 26.5], [-85, 26.8], [-86.5, 28.9]]}, 
"properties": {}}]}

This also highlights that you can do all of your GeoJSON specification with 
only what's built into the geojson package you've obtained from pypi. You don't 
have to try and construct the GeoJSON yourself. Similarly, if you are 
comfortable with the pandas DataFrame and Series interfaces, there is a package 
called GeoPandas (https://geopandas.org/index.html) that gives you this 
interface for common GIS data formats, including reading and writing GeoJSON. 
GeoPandas can also give you a much more friendly representation of these data 
within say a Jupyter Notebook.

Can it be better formatted? GeoJSON is a specific subset of JSON, and so has to 
follow its formatting specifications. It will be somewhat hard to read and has 
to be formatted this way if you stick with those files.

To answer your other question about persisting information between Python 
functions: there are a few ways you can do this. Variables are "scoped" within 
Python, which means they are accessed and referenced within various nested 
levels; further reading available here: 
https://realpython.com/python-scope-legb-rule/. You can declare a variable 
within a function to be global using the `global <var>` statement so that you 
can modify variables outside your function. However, this should be avoided! 
This can lead to potentially gross bugs, crossed streams, or multiple future 
headaches.

If the tools provided by the GeoJSON or GeoPandas packages aren't accomplishing 
what you're looking for on their own, then I'd suggest digging a bit deeper and 
learning how to create your own class. Classes can contain multiple separate 
functions, just the same as you've laid out your .py files here, but can share 
properties and information between the different functions without having to 
modify variables between scopes within Python. There are many different 
resources out there for learning how to write classes, e.g. the official Python 
documentation tutorial: https://docs.python.org/3/tutorial/classes.html, though 
we don't have any of our own thorough materials on this currently.

I hope this helps, and don't hesitate to reach back out if there's further ways 
we can help push this forward!


All the best,

Drew


> Looking at metpy I tried to write a Geojson file with a linestyle (no example 
> of this). I wanted to ask two major questions:
> 
> First, I produced the following geojson file which is supposed to be 3 line 
> tracks, like for a hurricane:
> 
> "{\"type\": \"FeatureCollection\", \"features\": [{\"type\": \"LineString\", 
> \"coordinates\": [[-85.0, 25.5], [-86.0, 25.8], [-87.5, 27.9], [-89, 29.5]]}, 
> {\"type\": \"LineString\", \"coordinates\": [[-86.0, 26.5], [-87.0, 26.8], 
> [-88.5, 28.9], [-90, 30.5]]}, {\"type\": \"LineString\", \"coordinates\": 
> [[-87.0, 27.5], [-88.0, 27.8], [-89.5, 29.9], [-91, 31.5]]}, {\"type\": 
> \"LineString\", \"coordinates\": [[-88.0, 28.5], [-89.0, 28.8], [-90.5, 
> 30.9], [-92, 32.5]]}, {\"type\": \"LineString\", \"coordinates\": [[-89.0, 
> 29.5], [-90.0, 29.8], [-91.5, 31.9], [-93, 33.5]]}]}"
> 
> Don't know if this looks right and its hard to read. Would like to have 
> better formatting in either case.
> 
> Question 1: Does the above look like a geojson file created via pypi geojson 
> and can it be better formatted?
> 
> 
> I used two test programs, my driver or main program follows:
> 
> --------------------------- test_geojson.py 
> ______________________________________________
> from datetime import datetime
> import geojson_save as traj
> 
> trajectory_format = "geojson"
> output_dir = "./trajectories/"
> traj.geojson_init(output_dir)
> 
> 
> for j in range(0, 5):
> 
> lat = [25.5+j, 25.8+j, 27.9+j, 29.5+j]
> lon = [-85.0-j, -86.0-j, -87.5-j, -89-j]
> pres_mb = [999.0-j, 998.0-j, 997.0-j, 996.0-j]
> print(lat)
> print(lon)
> print(pres_mb)
> traj.geojson_write(lat, lon, j)
> 
> print(lat)
> my_datetime = datetime.now().strftime("%Y-%m-%d_%H%M%S")
> traj.geojson_close(my_datetime)
> 
> ---------------------------- end test_geojson.py 
> ------------------------------------------------------
> 
> The above program creates three tracks, like for a fake hurricane. It has a 
> setup program which I should off removed. I stripped down to just the 
> following
> 
> 
> 
> Question 2: I wanted to have a function to create geojson tracks, I don't 
> know the best way in python to presist data between function calls.
> Like to have a global variable, or static or singleton instance. Can a better 
> way be done than I use to persist variables between function calls?
> 
> -------------------------- save_geojson.py 
> -----------------------------------------------------------
> 
> import os
> import geojson
> from geojson import Feature, Point, FeatureCollection
> import json
> 
> 
> def geojson_init(output_dir):
> print("geojson_initialize... with output to "+output_dir)
> geojson_init.write_dir = output_dir     # want to persist write_dir or make 
> static or global
> geojson_init.features = []              # want to persist write_dir or make 
> static or global
> 
> 
> def geojson_write(lat, lon, j):
> print("geojson_initialize...")
> 
> my_linestring = {
> 'type': 'LineString',
> 'coordinates': [[lon, lat] for lon, lat in zip(lon, lat)]
> }
> geojson_init.features.append(my_linestring)
> 
> 
> def geojson_close(file_date):
> 
> my_dir = geojson_init.write_dir
> output_file = my_dir + file_date + ".js"
> geometries = {
> 'type': 'FeatureCollection',
> 'features': geojson_init.features
> }
> 
> geo_str = json.dumps(geometries)
> 
> # write to a file
> with open(output_file, 'w') as f:
> f.write(geojson.dumps(geo_str))
> 
> print("wrote geojson to "+output_file)
> 
> 
> 
> ----------------------------------------- end geojson_save.py 
> -------------------------------
> 
> So looking for advise to move lat, lon, arrays or list to geojson LineString 
> features. Also, learn best method to presist data between function
> calls.
> 


Ticket Details
===================
Ticket ID: MFJ-706941
Department: Support Python
Priority: Low
Status: Closed
===================
NOTE: All email exchanges with Unidata User Support are recorded in the Unidata 
inquiry tracking system and then made publicly available through the web.  If 
you do not want to have your interactions made available in this way, you must 
let us know in each email you send to us.