meteortools.rmsutils.multiEventGroundMap

  1# Copyright (C) 2018-2023 Mark McIntyre
  2
  3import datetime
  4import pandas as pd
  5import argparse
  6import os
  7import matplotlib.pyplot as plt
  8from meteortools.utils import greatCircleDistance
  9try:
 10    from wmpl.Utils.PlotMap_OSM import OSMMap
 11except:
 12    print('WMPL not available')
 13
 14RAD2DEG=57.2958
 15
 16
 17def multiEventGroundMap(startdt, enddt, statid=None, shwr=None, outdir=None, minmag=999, fireballsonly=False,
 18                        obslat=None, obslon=None, evtdist=None):
 19    """
 20    Plots a ground track diagram of all events between two dates, with filters by station and shower  
 21
 22    Arguments:  
 23        start:      [string] start date in YYYYMMDD format  
 24        end:        [string] end date in YYYYMMDD format  
 25        statid:     [string] station to filter for. Default all stations.  
 26        shwr:       [string] Filter by shower eg PER. Default All showers.  
 27        outdir:     [string] where to save the file to. if this parameter is omitted, the image will be displayed not saved  
 28        shwr:       [float] Min mag to include.  
 29        fbonly:     [bool] True if only to plot fireballs.
 30        obslat:     [float] Observers latitude: if this is set, obslon and evtdist must be set too
 31        obslon:     [float] Observers longitude
 32        evtdist:    [float] Event distance from observer
 33
 34    Output:  
 35        A jpg map of the detections.   
 36
 37    Note:  
 38        This function reads directly from the UKMON public dataset.  
 39        If obslat is set, then obslon and evtdist must be set, and only events within evtdist of the 
 40        observer will be plotted. 
 41
 42    """
 43    yr = startdt[:4]
 44
 45    cols=['_lat1', '_lng1','_lat2','_lng2','_stream','dtstamp', 'stations', '_amag', 'isfb']
 46    matchfile = f'https://archive.ukmeteors.co.uk/browse/parquet/matches-full-{yr}.parquet.snap'
 47
 48    dta = pd.read_parquet(matchfile, columns=cols)
 49    dta = dta[dta._amag < minmag]
 50    if fireballsonly:
 51        dta = dta[dta.isfb==1]
 52    # filter the data down to just the cols we want
 53    sd = datetime.datetime.strptime(startdt, '%Y%m%d')
 54    sd = sd+datetime.timedelta(hours=12)
 55    if startdt == enddt:
 56        ed = sd + datetime.timedelta(days=1)
 57    else:
 58        ed = datetime.datetime.strptime(enddt, '%Y%m%d')
 59        ed = ed+datetime.timedelta(hours=12)
 60    dta = dta[dta.dtstamp >= sd.timestamp()]
 61    dta = dta[dta.dtstamp <= ed.timestamp()]
 62    
 63    if shwr is not None:
 64        dta = dta[dta._stream==shwr.upper()]
 65    if statid is not None:
 66        dta = dta[dta.stations.str.contains(statid.upper())]
 67    if obslat:
 68        obslat = float(obslat)
 69        obslon = float(obslon)
 70        evtdist = float(evtdist)
 71        dta['evtdist'] = [greatCircleDistance(obslat/RAD2DEG, obslon/RAD2DEG, x/RAD2DEG,y/RAD2DEG) for x,y in zip(dta._lat2, dta._lng2)]
 72        dta = dta[dta.evtdist <= evtdist]
 73
 74    if len(dta) > 1:
 75        plt.clf()
 76        fig = plt.gcf()
 77        fig.set_size_inches(11.6, 8.26)
 78        lat_list = [min(min(dta._lat1), min(dta._lat2))/RAD2DEG, max(max(dta._lat1), max(dta._lat2))/RAD2DEG]
 79        lon_list = [min(min(dta._lng1), min(dta._lng2))/RAD2DEG, max(max(dta._lng1), max(dta._lng2))/RAD2DEG]
 80        # Init the map
 81        #print(lat_list, lon_list)
 82        m = OSMMap(lat_list, lon_list, border_size=50, color_scheme='dark')
 83        lat1s=list(dta._lat1)
 84        lat2s=list(dta._lat2)
 85        lng1s=list(dta._lng1)
 86        lng2s=list(dta._lng2)
 87        for l1, l2, g1, g2 in zip(lat1s, lat2s, lng1s, lng2s):
 88            lats = [l1/RAD2DEG, l2/RAD2DEG]
 89            lons = [g1/RAD2DEG, g2/RAD2DEG]
 90            m.plot(lats, lons, c='r')
 91            m.scatter(l2/RAD2DEG, g2/RAD2DEG, c='k', marker='+', s=50, alpha=0.75)
 92        if outdir is not None:
 93            plt.savefig(os.path.join(outdir, f'{startdt}-{enddt}-{shwr}-{statid}.jpg'))
 94        else:
 95            plt.show()
 96        plt.close()
 97    return 
 98
 99
100if __name__ == '__main__':
101    arg_parser = argparse.ArgumentParser(description="""Plot a ground map of many detections.""",
102        formatter_class=argparse.RawTextHelpFormatter)
103
104    arg_parser.add_argument('start_date', type=str, help='start date in yyyymmdd format')
105    arg_parser.add_argument('end_date', type=str, help='end date in yyyymmdd format')
106    arg_parser.add_argument('-s', '--shower', metavar='SHOWER', type=str,
107        help="Map just this single shower given its code (e.g. PER, ORI, ETA).")
108
109    arg_parser.add_argument('-i', '--stationid', metavar='STATID', help='Station id eg UK0006')
110    arg_parser.add_argument('-o', '--outdir', metavar='OUTDIR', help='Location to save jpg into')
111    arg_parser.add_argument('-m', '--minmag', metavar='MINMAG', type=float, help='Minimum magnitude to filter for')
112    arg_parser.add_argument('-f', '--fbonly', action='store_true', help='Plot only fireballs')
113    arg_parser.add_argument('-l', '--obs_lat', metavar='OBSLAT', help='Observer latitude (degrees')
114    arg_parser.add_argument('-g', '--obs_lon', metavar='OBSLON', help='Observer longitude (degrees)')
115    arg_parser.add_argument('-d', '--event_distance', metavar='EVTDIST', help='Distance from observer (km)')
116
117    cml_args = arg_parser.parse_args()
118    minmag = cml_args.minmag
119    if not minmag:
120        minmag = 999
121    obslat = cml_args.obs_lat
122    if not obslat:
123        obslat = None
124        obslon = None
125        evtdist = None
126    else:
127        if not cml_args.obs_lon or not cml_args.event_distance:
128            print('if providing an observer latitude, must also supply longitude and distance')
129            exit(0)
130        else:
131            obslon = cml_args.obs_lon
132            evtdist = cml_args.event_distance
133    multiEventGroundMap(cml_args.start_date, cml_args.end_date, 
134        cml_args.stationid, cml_args.shower, cml_args.outdir, minmag, cml_args.fbonly, 
135        obslat, obslon, evtdist)
RAD2DEG = 57.2958
def multiEventGroundMap( startdt, enddt, statid=None, shwr=None, outdir=None, minmag=999, fireballsonly=False, obslat=None, obslon=None, evtdist=None):
18def multiEventGroundMap(startdt, enddt, statid=None, shwr=None, outdir=None, minmag=999, fireballsonly=False,
19                        obslat=None, obslon=None, evtdist=None):
20    """
21    Plots a ground track diagram of all events between two dates, with filters by station and shower  
22
23    Arguments:  
24        start:      [string] start date in YYYYMMDD format  
25        end:        [string] end date in YYYYMMDD format  
26        statid:     [string] station to filter for. Default all stations.  
27        shwr:       [string] Filter by shower eg PER. Default All showers.  
28        outdir:     [string] where to save the file to. if this parameter is omitted, the image will be displayed not saved  
29        shwr:       [float] Min mag to include.  
30        fbonly:     [bool] True if only to plot fireballs.
31        obslat:     [float] Observers latitude: if this is set, obslon and evtdist must be set too
32        obslon:     [float] Observers longitude
33        evtdist:    [float] Event distance from observer
34
35    Output:  
36        A jpg map of the detections.   
37
38    Note:  
39        This function reads directly from the UKMON public dataset.  
40        If obslat is set, then obslon and evtdist must be set, and only events within evtdist of the 
41        observer will be plotted. 
42
43    """
44    yr = startdt[:4]
45
46    cols=['_lat1', '_lng1','_lat2','_lng2','_stream','dtstamp', 'stations', '_amag', 'isfb']
47    matchfile = f'https://archive.ukmeteors.co.uk/browse/parquet/matches-full-{yr}.parquet.snap'
48
49    dta = pd.read_parquet(matchfile, columns=cols)
50    dta = dta[dta._amag < minmag]
51    if fireballsonly:
52        dta = dta[dta.isfb==1]
53    # filter the data down to just the cols we want
54    sd = datetime.datetime.strptime(startdt, '%Y%m%d')
55    sd = sd+datetime.timedelta(hours=12)
56    if startdt == enddt:
57        ed = sd + datetime.timedelta(days=1)
58    else:
59        ed = datetime.datetime.strptime(enddt, '%Y%m%d')
60        ed = ed+datetime.timedelta(hours=12)
61    dta = dta[dta.dtstamp >= sd.timestamp()]
62    dta = dta[dta.dtstamp <= ed.timestamp()]
63    
64    if shwr is not None:
65        dta = dta[dta._stream==shwr.upper()]
66    if statid is not None:
67        dta = dta[dta.stations.str.contains(statid.upper())]
68    if obslat:
69        obslat = float(obslat)
70        obslon = float(obslon)
71        evtdist = float(evtdist)
72        dta['evtdist'] = [greatCircleDistance(obslat/RAD2DEG, obslon/RAD2DEG, x/RAD2DEG,y/RAD2DEG) for x,y in zip(dta._lat2, dta._lng2)]
73        dta = dta[dta.evtdist <= evtdist]
74
75    if len(dta) > 1:
76        plt.clf()
77        fig = plt.gcf()
78        fig.set_size_inches(11.6, 8.26)
79        lat_list = [min(min(dta._lat1), min(dta._lat2))/RAD2DEG, max(max(dta._lat1), max(dta._lat2))/RAD2DEG]
80        lon_list = [min(min(dta._lng1), min(dta._lng2))/RAD2DEG, max(max(dta._lng1), max(dta._lng2))/RAD2DEG]
81        # Init the map
82        #print(lat_list, lon_list)
83        m = OSMMap(lat_list, lon_list, border_size=50, color_scheme='dark')
84        lat1s=list(dta._lat1)
85        lat2s=list(dta._lat2)
86        lng1s=list(dta._lng1)
87        lng2s=list(dta._lng2)
88        for l1, l2, g1, g2 in zip(lat1s, lat2s, lng1s, lng2s):
89            lats = [l1/RAD2DEG, l2/RAD2DEG]
90            lons = [g1/RAD2DEG, g2/RAD2DEG]
91            m.plot(lats, lons, c='r')
92            m.scatter(l2/RAD2DEG, g2/RAD2DEG, c='k', marker='+', s=50, alpha=0.75)
93        if outdir is not None:
94            plt.savefig(os.path.join(outdir, f'{startdt}-{enddt}-{shwr}-{statid}.jpg'))
95        else:
96            plt.show()
97        plt.close()
98    return 

Plots a ground track diagram of all events between two dates, with filters by station and shower

Arguments:
start: [string] start date in YYYYMMDD format
end: [string] end date in YYYYMMDD format
statid: [string] station to filter for. Default all stations.
shwr: [string] Filter by shower eg PER. Default All showers.
outdir: [string] where to save the file to. if this parameter is omitted, the image will be displayed not saved
shwr: [float] Min mag to include.
fbonly: [bool] True if only to plot fireballs. obslat: [float] Observers latitude: if this is set, obslon and evtdist must be set too obslon: [float] Observers longitude evtdist: [float] Event distance from observer

Output:
A jpg map of the detections.

Note:
This function reads directly from the UKMON public dataset.
If obslat is set, then obslon and evtdist must be set, and only events within evtdist of the observer will be plotted.