diff --git a/.github/workflows/main.yml b/.github/workflows/main.yaml similarity index 100% rename from .github/workflows/main.yml rename to .github/workflows/main.yaml diff --git a/README.md b/README.md index 5fac886..fc4477e 100644 --- a/README.md +++ b/README.md @@ -26,5 +26,5 @@ conda install -c conda-forge campo ## Build status -[![Build and deploy](https://github.com/computationalgeography/campo/workflows/Build%20and%20deploy/badge.svg)](https://github.com/computationalgeography/campo/actions) +[![Build and deploy](https://github.com/computationalgeography/campo/actions/workflows/main.yaml/badge.svg)](https://github.com/computationalgeography/campo/actions/main.yaml) diff --git a/source/campo/op_experimental/export.py b/source/campo/op_experimental/export.py index 3c01ff5..56db855 100644 --- a/source/campo/op_experimental/export.py +++ b/source/campo/op_experimental/export.py @@ -1,17 +1,126 @@ import math -import pandas as pd -from osgeo import gdal -from osgeo import osr import os import subprocess import tempfile import shutil +from osgeo import gdal, ogr, osr +import pandas as pd + from ..dataframe import * from ..utils import _color_message gdal.UseExceptions() + +def to_df(dataframe, timestep=None): + """ Exports point agent properties to a Pandas dataframe + + :param dataframe: Input dataframe from LUE dataset + :type dataframe: dataframe + :param crs: Coordinate Reference System, e.g. 'EPSG:4326' + :type crs: str + :param timestep: None for static data or timestep for dynamic data + :type timestep: int + """ + + phen_name = dataframe.keys() + + if not timestep: + + for phen_name in dataframe.keys(): + phen = dataframe[phen_name] + for pset_name in phen.keys(): + propset = dataframe[phen_name][pset_name] + + if propset['_campo_space_type'] == 'static_same_point': + dfObj = pd.DataFrame() + + property_names = list(propset.keys()) + property_names.remove('_campo_space_type') + + + for prop_name in property_names: + dfObj['CoordX'] = dataframe[phen_name][pset_name][prop_name]['coordinates'].data[:, 0] + dfObj['CoordY'] = dataframe[phen_name][pset_name][prop_name]['coordinates'].data[:, 1] + + for prop_name in property_names: + prop = dataframe[phen_name][pset_name][prop_name] + dfObj[prop_name] = prop['values'].data + + return dfObj + else: + msg = _color_message('Only for static point agents') + raise TypeError(msg) + + else: + + for phen_name in dataframe.keys(): + phen = dataframe[phen_name] + for pset_name in phen.keys(): + propset = dataframe[phen_name][pset_name] + + if not propset['_campo_space_type'] == 'dynamic_same_point': + raise NotImplementedError + + dfObj = pd.DataFrame() + + property_names = list(propset.keys()) + property_names.remove('_campo_space_type') + + + for prop_name in property_names: + dfObj['CoordX'] = dataframe[phen_name][pset_name][prop_name]['coordinates'].data[:, 0] + dfObj['CoordY'] = dataframe[phen_name][pset_name][prop_name]['coordinates'].data[:, 1] + + for prop_name in property_names: + p = dataframe[phen_name][pset_name][prop_name] + # User provided timestep to array index + ts = timestep - 1 + dfObj[prop_name] = p['values'].values[:,ts] + + return dfObj + + +def mobile_points_to_gpkg(coords, dataframe, filename, crs=""): + + # rewrite coordinates with ones from current timestep + dataframe["CoordX"] = coords[:,0] + dataframe["CoordY"] = coords[:,1] + + with tempfile.TemporaryDirectory() as tmpdir: + layername, tail = os.path.splitext(os.path.basename(filename)) + + csv_fname = os.path.join(tmpdir, f'{layername}.csv') + csvt_fname = os.path.join(tmpdir, f'{layername}.csvt') + + columns = [] + for c in dataframe: + if dataframe[c].dtype.kind == 'f': + columns.append('Real') + elif dataframe[c].dtype.kind == 'i': + columns.append('Integer') + else: + columns.append('String') + + columns = ','.join(map(str, columns)) + with open(csvt_fname, 'w') as content: + content.write(columns) + + dataframe.to_csv(csv_fname, index=False) + + s_srs = '' + t_srs = '' + if crs != '': + s_srs = f'-s_srs {crs}' + t_srs = f'-t_srs {crs}' + + + cmd = f'ogr2ogr {s_srs} {t_srs} -oo X_POSSIBLE_NAMES=CoordX -oo Y_POSSIBLE_NAMES=CoordY -f GPKG {filename} {csv_fname}' + subprocess.check_call(cmd, shell=True, stdout=subprocess.DEVNULL) + + + def to_gpkg(dataframe, filename, crs='', timestep=None): """ Exports point agent properties to a GeoPackage diff --git a/source/test/test_dataframe.py b/source/test/test_dataframe.py index cf83314..96ee300 100644 --- a/source/test/test_dataframe.py +++ b/source/test/test_dataframe.py @@ -29,3 +29,20 @@ def test_1(self): for timestep in range(1, 6): coords = campo.dataframe.coordinates(dataset, "a", "mobile_points", timestep) self.assertTrue(((arr + timestep) == coords).all()) + + def test_2(self): + """ Writing GeoPackage of mobile agents """ + + arr = np.empty((3, 2)) + arr[:,0] = np.array([1, 3, 5]) + arr[:,1] = np.array([2, 4, 6]) + + dataset = ldm.open_dataset("TestMobileAgents_test_1.lue", "r") + dataframe = campo.dataframe.select(dataset.a, property_names=['mp']) + + for timestep in range(1, 6): + coords = campo.dataframe.coordinates(dataset, "a", "mobile_points", timestep) + tmp_df = campo.to_df(dataframe, timestep) + campo.mobile_points_to_gpkg(coords, tmp_df, f"tmp_{timestep}.gpkg", 'EPSG:28992') + +