meteortools.fileformats.kmlHandlers

  1import xmltodict
  2from shapely.geometry import Polygon
  3import csv
  4import simplekml
  5import numpy as np
  6import pandas as pd
  7import os
  8
  9
 10def readCameraKML(kmlFilename, return_poly=False):
 11    """ Load a KML file and return either a list of lats and longs, or a Shapely polygon  
 12    
 13    Arguments:  
 14        kmlFilename:    [string] full path to the KML file to consume   
 15        return_poly:    [bool] return a Shapely polygon? Default False  
 16
 17    
 18    Returns:  
 19        if return_poly is false, returns a tuple of (cameraname, lats, longs) where lats and longs are lists of the 
 20        latitudes and longitudes in the KML file.  
 21
 22        If return_poly is true, returns a tuple of (cameranamem, shapely Polygon)  
 23    """
 24
 25    with open(kmlFilename) as fd:
 26        x = xmltodict.parse(fd.read())
 27        cname = x['kml']['Folder']['name']
 28        coords = x['kml']['Folder']['Placemark']['MultiGeometry']['Polygon']['outerBoundaryIs']['LinearRing']['coordinates']
 29        coords = coords.split('\n')
 30        if return_poly is False:
 31            lats = []
 32            lngs = []
 33            for lin in coords:
 34                s = lin.split(',')
 35                lngs.append(float(s[0]))
 36                lats.append(float(s[1]))
 37            return cname, lats, lngs
 38        else:
 39            ptsarr=[]
 40            for lin in coords:
 41                s = lin.split(',')
 42                ptsarr.append((float(s[0]), float(s[1])))
 43            polyg = Polygon(ptsarr)
 44            return cname, polyg 
 45
 46
 47def trackCsvtoKML(trackcsvfile, trackdata=None, saveOutput=True, outdir=None):
 48    """ 
 49    Either reads a CSV file containing lat, long, height of an event and 
 50    creates a 3d KML file from it or, if trackdata is populated, converts a Pandas dataframe containing 
 51    the same data. Output is written to disk unless saveOutput is false.  
 52    
 53    Arguments:  
 54        trackcsvfile:   [string] full path to the file to read from  
 55        trackdata:      [array] pandas dataframe containing the data. Default None  
 56        saveOutput:     [bool] write the KML file to disk. Default true  
 57        outdir:         [string] where to save the file. Default same folder as the source file
 58
 59    Returns:  
 60        the KML file as a tuple  
 61        """
 62    kml=simplekml.Kml()
 63    kml.document.name = trackcsvfile
 64    if trackdata is None:
 65        inputfile = csv.reader(open(trackcsvfile))
 66        for row in inputfile:
 67            #columns are lat, long, height, times
 68            kml.newpoint(name='', coords=[(row[1], row[0], row[2])])
 69    else:
 70        intvl = int(len(trackdata)/100)
 71        for i,r in trackdata.iterrows():
 72            if i % intvl == 0:
 73                kml.newpoint(name=f'{r[3]:.5f}', coords=[(r[1], r[0], r[2])], extrude=1, altitudemode='absolute')
 74        if len(trackdata) % intvl != 0:
 75            r = trackdata.iloc[[-1]]
 76            kml.newpoint(name=f'{r["times"].iloc[0]:.5f}', coords=[(r['lons'].iloc[0], r['lats'].iloc[0], r['alts'].iloc[0])], extrude=1, altitudemode='absolute')
 77    if 'csv' in trackcsvfile:
 78        outname = trackcsvfile.replace('.csv','.kml')
 79    else:
 80        outname = f'{trackcsvfile}.kml'
 81    if saveOutput:
 82        if outdir is None:
 83            outdir, _ = os.path.split(trackcsvfile)
 84        os.makedirs(outdir, exist_ok=True)
 85        outname = os.path.join(outdir, outname)
 86        kml.save(outname)
 87    return kml
 88
 89
 90def trackKMLtoCsv(kmlfile, kmldata = None, saveOutput=True, outdir=None):
 91    """ convert a track KML retrieved by ukmondb.trajectoryKML to a 3 dimensional CSV file
 92    containing coordinates of points on the trajectory.   
 93    
 94    Arguments:  
 95        kmlfile     [string] full path to the KML file to read from.  
 96        kmldata     [kml] the kml data if available.   
 97        saveOutput  [bool] Default True, save the output to file.  
 98        outdir      [string] where to save to if saveOutput is True.  
 99
100    Note: if kmldata is supplied, then kmlfile is ignored.  
101        
102    Returns:  
103        a Pandas dataframe containing the lat, long, alt and time of each 
104        point on the trajectory, sorted by time. 
105
106        """
107    with open(kmlfile) as fd:
108        x = xmltodict.parse(fd.read())
109        placemarks=x['kml']['Document']['Placemark']
110        lats = []
111        lons = []
112        alts = [] 
113        tims = []
114        for pm in placemarks:
115            tims.append(float(pm['name']))
116            coords = pm['Point']['coordinates'].split(',')
117            lons.append(float(coords[0]))
118            lats.append(float(coords[1]))
119            alts.append(float(coords[2]))
120    df = pd.DataFrame({"lats": lats, "lons": lons, "alts": alts, "times": tims})
121    df = df.sort_values(by=['times', 'lats'])
122    if saveOutput:
123        fname = kmlfile
124        if outdir is None:
125            outdir, fname = os.path.split(kmlfile)
126        outf = os.path.join(outdir, fname).replace('.kml', '.csv').replace('.KML','.csv')
127        df.to_csv(outf, index=False)
128    return df
129
130
131def getTrackDetails(traj):
132    """ Get track details from a WMPL trajectory object  
133    
134    Arguments:  
135        traj:       a WMPL trajectory object containing observations  
136
137    Returns:  
138        a Pandas dataframe containing the lat, long, alt and time of each point on the trajectory, sorted by time. 
139    """
140    lats = []
141    lons = []
142    alts = [] 
143    lens = []
144    # Go through observation from all stations
145    for obs in traj.observations:
146        # Go through all observed points
147        for i in range(obs.kmeas):
148            lats.append(np.degrees(obs.model_lat[i]))
149            lons.append(np.degrees(obs.model_lon[i]))
150            alts.append(obs.model_ht[i])
151            lens.append(obs.time_data[i])
152    df = pd.DataFrame({"lats": lats, "lons": lons, "alts": alts, "times": lens})
153    df = df.sort_values(by=['times', 'lats'])
154    return df
def readCameraKML(kmlFilename, return_poly=False):
11def readCameraKML(kmlFilename, return_poly=False):
12    """ Load a KML file and return either a list of lats and longs, or a Shapely polygon  
13    
14    Arguments:  
15        kmlFilename:    [string] full path to the KML file to consume   
16        return_poly:    [bool] return a Shapely polygon? Default False  
17
18    
19    Returns:  
20        if return_poly is false, returns a tuple of (cameraname, lats, longs) where lats and longs are lists of the 
21        latitudes and longitudes in the KML file.  
22
23        If return_poly is true, returns a tuple of (cameranamem, shapely Polygon)  
24    """
25
26    with open(kmlFilename) as fd:
27        x = xmltodict.parse(fd.read())
28        cname = x['kml']['Folder']['name']
29        coords = x['kml']['Folder']['Placemark']['MultiGeometry']['Polygon']['outerBoundaryIs']['LinearRing']['coordinates']
30        coords = coords.split('\n')
31        if return_poly is False:
32            lats = []
33            lngs = []
34            for lin in coords:
35                s = lin.split(',')
36                lngs.append(float(s[0]))
37                lats.append(float(s[1]))
38            return cname, lats, lngs
39        else:
40            ptsarr=[]
41            for lin in coords:
42                s = lin.split(',')
43                ptsarr.append((float(s[0]), float(s[1])))
44            polyg = Polygon(ptsarr)
45            return cname, polyg 

Load a KML file and return either a list of lats and longs, or a Shapely polygon

Arguments:
kmlFilename: [string] full path to the KML file to consume
return_poly: [bool] return a Shapely polygon? Default False

Returns:
if return_poly is false, returns a tuple of (cameraname, lats, longs) where lats and longs are lists of the latitudes and longitudes in the KML file.

If return_poly is true, returns a tuple of (cameranamem, shapely Polygon)
def trackCsvtoKML(trackcsvfile, trackdata=None, saveOutput=True, outdir=None):
48def trackCsvtoKML(trackcsvfile, trackdata=None, saveOutput=True, outdir=None):
49    """ 
50    Either reads a CSV file containing lat, long, height of an event and 
51    creates a 3d KML file from it or, if trackdata is populated, converts a Pandas dataframe containing 
52    the same data. Output is written to disk unless saveOutput is false.  
53    
54    Arguments:  
55        trackcsvfile:   [string] full path to the file to read from  
56        trackdata:      [array] pandas dataframe containing the data. Default None  
57        saveOutput:     [bool] write the KML file to disk. Default true  
58        outdir:         [string] where to save the file. Default same folder as the source file
59
60    Returns:  
61        the KML file as a tuple  
62        """
63    kml=simplekml.Kml()
64    kml.document.name = trackcsvfile
65    if trackdata is None:
66        inputfile = csv.reader(open(trackcsvfile))
67        for row in inputfile:
68            #columns are lat, long, height, times
69            kml.newpoint(name='', coords=[(row[1], row[0], row[2])])
70    else:
71        intvl = int(len(trackdata)/100)
72        for i,r in trackdata.iterrows():
73            if i % intvl == 0:
74                kml.newpoint(name=f'{r[3]:.5f}', coords=[(r[1], r[0], r[2])], extrude=1, altitudemode='absolute')
75        if len(trackdata) % intvl != 0:
76            r = trackdata.iloc[[-1]]
77            kml.newpoint(name=f'{r["times"].iloc[0]:.5f}', coords=[(r['lons'].iloc[0], r['lats'].iloc[0], r['alts'].iloc[0])], extrude=1, altitudemode='absolute')
78    if 'csv' in trackcsvfile:
79        outname = trackcsvfile.replace('.csv','.kml')
80    else:
81        outname = f'{trackcsvfile}.kml'
82    if saveOutput:
83        if outdir is None:
84            outdir, _ = os.path.split(trackcsvfile)
85        os.makedirs(outdir, exist_ok=True)
86        outname = os.path.join(outdir, outname)
87        kml.save(outname)
88    return kml

Either reads a CSV file containing lat, long, height of an event and creates a 3d KML file from it or, if trackdata is populated, converts a Pandas dataframe containing the same data. Output is written to disk unless saveOutput is false.

Arguments:
trackcsvfile: [string] full path to the file to read from
trackdata: [array] pandas dataframe containing the data. Default None
saveOutput: [bool] write the KML file to disk. Default true
outdir: [string] where to save the file. Default same folder as the source file

Returns:
the KML file as a tuple

def trackKMLtoCsv(kmlfile, kmldata=None, saveOutput=True, outdir=None):
 91def trackKMLtoCsv(kmlfile, kmldata = None, saveOutput=True, outdir=None):
 92    """ convert a track KML retrieved by ukmondb.trajectoryKML to a 3 dimensional CSV file
 93    containing coordinates of points on the trajectory.   
 94    
 95    Arguments:  
 96        kmlfile     [string] full path to the KML file to read from.  
 97        kmldata     [kml] the kml data if available.   
 98        saveOutput  [bool] Default True, save the output to file.  
 99        outdir      [string] where to save to if saveOutput is True.  
100
101    Note: if kmldata is supplied, then kmlfile is ignored.  
102        
103    Returns:  
104        a Pandas dataframe containing the lat, long, alt and time of each 
105        point on the trajectory, sorted by time. 
106
107        """
108    with open(kmlfile) as fd:
109        x = xmltodict.parse(fd.read())
110        placemarks=x['kml']['Document']['Placemark']
111        lats = []
112        lons = []
113        alts = [] 
114        tims = []
115        for pm in placemarks:
116            tims.append(float(pm['name']))
117            coords = pm['Point']['coordinates'].split(',')
118            lons.append(float(coords[0]))
119            lats.append(float(coords[1]))
120            alts.append(float(coords[2]))
121    df = pd.DataFrame({"lats": lats, "lons": lons, "alts": alts, "times": tims})
122    df = df.sort_values(by=['times', 'lats'])
123    if saveOutput:
124        fname = kmlfile
125        if outdir is None:
126            outdir, fname = os.path.split(kmlfile)
127        outf = os.path.join(outdir, fname).replace('.kml', '.csv').replace('.KML','.csv')
128        df.to_csv(outf, index=False)
129    return df

convert a track KML retrieved by ukmondb.trajectoryKML to a 3 dimensional CSV file containing coordinates of points on the trajectory.

Arguments:
kmlfile [string] full path to the KML file to read from.
kmldata [kml] the kml data if available.
saveOutput [bool] Default True, save the output to file.
outdir [string] where to save to if saveOutput is True.

Note: if kmldata is supplied, then kmlfile is ignored.

Returns:
a Pandas dataframe containing the lat, long, alt and time of each point on the trajectory, sorted by time.

def getTrackDetails(traj):
132def getTrackDetails(traj):
133    """ Get track details from a WMPL trajectory object  
134    
135    Arguments:  
136        traj:       a WMPL trajectory object containing observations  
137
138    Returns:  
139        a Pandas dataframe containing the lat, long, alt and time of each point on the trajectory, sorted by time. 
140    """
141    lats = []
142    lons = []
143    alts = [] 
144    lens = []
145    # Go through observation from all stations
146    for obs in traj.observations:
147        # Go through all observed points
148        for i in range(obs.kmeas):
149            lats.append(np.degrees(obs.model_lat[i]))
150            lons.append(np.degrees(obs.model_lon[i]))
151            alts.append(obs.model_ht[i])
152            lens.append(obs.time_data[i])
153    df = pd.DataFrame({"lats": lats, "lons": lons, "alts": alts, "times": lens})
154    df = df.sort_values(by=['times', 'lats'])
155    return df

Get track details from a WMPL trajectory object

Arguments:
traj: a WMPL trajectory object containing observations

Returns:
a Pandas dataframe containing the lat, long, alt and time of each point on the trajectory, sorted by time.