def tracks2point(tracks, outputFile): """ Writes tracks to a shapefile as a collection of point features. :type tracks: list of :class:`Track` objects :param tracks: :class:`Track` features to store in a shape file :param str outputFile: Path to output file destination :raises: :mod:`shapefile.ShapefileException` if there is an error when attempting to save the file. """ LOG.info("Writing point shape file: {0}".format(outputFile)) sf = shapefile.Writer(shapefile.POINT) sf.fields = OBSFIELDS LOG.debug("Processing {0} tracks".format(len(tracks))) for track in tracks: track.data = recdropfields(track.data, ['Datetime']) for lon, lat, rec in zip(track.Longitude, track.Latitude, track.data): sf.point(lon, lat) sf.record(*rec) try: sf.save(outputFile) except shapefile.ShapefileException: LOG.exception("Cannot save shape file: {0}".format(outputFile)) raise return
def tracks2line(tracks, outputFile, dissolve=False, netcdf_format=False): """ Writes tracks to a shapefile as a collection of line features If dissolve==True, then each track feature is written as a single polyline feature, otherwise each track segment is stored as a separate feature. :type tracks: list of :class:`Track` objects :param tracks: :class:`Track` features to store in a shape file :type outputFile: str :param outputFile: Path to output file destination :type dissolve: boolean :param dissolve: Store track features or track segments. :param bool netcdf_format: Whether tracks are in TCRM format :raises: :mod:`shapefile.ShapefileException` if there is an error when attempting to save the file. """ LOG.info("Writing line shape file: {0}".format(outputFile)) sf = shapefile.Writer(shapefile.POLYLINE) if netcdf_format: sf.fields = TCRM_FIELDS elif dissolve: sf.fields = EVENTFIELDS else: sf.fields = OBSFIELDS LOG.debug("Processing {0} tracks".format(len(tracks))) for track in tracks: track.data = recdropfields(track.data, ['Datetime']) if dissolve: if len(track.data) > 1: dlon = np.diff(track.Longitude) if dlon.min() < -180: # Track crosses 0E longitude - split track # into multiple parts: idx = np.argmin(dlon) parts = [] lines = zip(track.Longitude[:idx], track.Latitude[:idx]) parts.append(lines) lines = zip(track.Longitude[idx + 1:], track.Latitude[idx + 1:]) parts.append(lines) sf.line(parts) else: lines = zip(track.Longitude, track.Latitude) sf.line([lines]) else: lines = zip(track.Longitude, track.Latitude) sf.line([lines]) if netcdf_format: sf.record(*track.data[0]) else: minPressure = track.trackMinPressure maxWind = track.trackMaxWind age = track.TimeElapsed.max() startYear = track.Year[0] startMonth = track.Month[0] startDay = track.Day[0] startHour = track.Hour[0] startMin = track.Minute[0] record = [ track.CycloneNumber[0], startYear, startMonth, startDay, startHour, startMin, age, minPressure, maxWind ] sf.record(*record) else: if len(track.data) == 1: line = [[[track.Longitude, track.Latitude], [track.Longitude, track.Latitude]]] sf.line(line) sf.record(*track.data[0]) else: for n in range(len(track.data) - 1): dlon = track.Longitude[n + 1] - track.Longitude[n] if dlon < -180.: # case where the track crosses 0E: segment = [[[track.Longitude[n], track.Latitude[n]], [track.Longitude[n], track.Latitude[n]]]] else: segment = [[[track.Longitude[n], track.Latitude[n]], [ track.Longitude[n + 1], track.Latitude[n + 1] ]]] sf.line(segment) sf.record(*track.data[n]) # Last point in the track: sf.line([[[track.Longitude[n + 1], track.Latitude[n + 1]], [track.Longitude[n + 1], track.Latitude[n + 1]]]]) sf.record(*track.data[n + 1]) try: sf.save(outputFile) except shapefile.ShapefileException: LOG.exception("Cannot save shape file: {0}".format(outputFile)) raise