siavash-saki / tesspy Goto Github PK
View Code? Open in Web Editor NEWLicense: BSD 3-Clause "New" or "Revised" License
License: BSD 3-Clause "New" or "Revised" License
xref openjournals/joss-reviews#4620
Rename master
to main
. See the article for an explanation of significance.
xref openjournals/joss-reviews#4620
The first code cell in 01_Getting_Started fails due to the following, which should be importing from tesspy
:
from tessellation import Tessellation
Both the notebook in Examples and the docs should be updated.
xref openjournals/joss-reviews#4620 #12
esda
package and libpysal
package.scikit-learn
bleiglas
xref openjournals/joss-reviews#4620
I ran tests with pytest
locally twice, each time failed with different output.The test suite fails with the following output:
========================================================================= test session starts =========================================================================
platform darwin -- Python 3.10.5, pytest-7.1.2, pluggy-1.0.0 -- /Users/user/miniconda3/envs/py310_tesspy/bin/python
cachedir: .pytest_cache
rootdir: /Users/user/tesspy
plugins: cov-3.0.0
collected 25 items
tests/test_poi_data.py::test_osm_primary_features PASSED [ 4%]
tests/test_poi_data.py::test_create_overpass_query_string PASSED [ 8%]
tests/test_poi_data.py::test_get_poi_data PASSED [ 12%]
tests/test_poi_data.py::test_osm_highway_types PASSED [ 16%]
tests/test_poi_data.py::test_create_custom_filter PASSED [ 20%]
tests/test_poi_data.py::test_get_road_network FAILED [ 24%]
tests/test_tessellation.py::test_squares PASSED [ 28%]
tests/test_tessellation.py::test_hexagons PASSED [ 32%]
tests/test_tessellation.py::test_adaptive_squares PASSED [ 36%]
tests/test_tessellation.py::test_voronoi FAILED [ 40%]
tests/test_tessellation.py::test_city_blocks Fatal Python error: Segmentation fault
Current thread 0x00000001169ff600 (most recent call first):
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/shapely/ops.py", line 160 in unary_union
File "/Users/user/tesspy/tesspy/tessellation_functions.py", line 422 in get_rest_polygon
File "/Users/user/tesspy/tesspy/tessellation.py", line 615 in city_blocks
File "/Users/user/tesspy/tests/test_tessellation.py", line 84 in test_city_blocks
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/python.py", line 192 in pytest_pyfunc_call
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_callers.py", line 39 in _multicall
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_manager.py", line 80 in _hookexec
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_hooks.py", line 265 in __call__
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/python.py", line 1761 in runtest
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/runner.py", line 166 in pytest_runtest_call
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_callers.py", line 39 in _multicall
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_manager.py", line 80 in _hookexec
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_hooks.py", line 265 in __call__
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/runner.py", line 259 in <lambda>
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/runner.py", line 338 in from_call
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/runner.py", line 258 in call_runtest_hook
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/runner.py", line 219 in call_and_report
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/runner.py", line 130 in runtestprotocol
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/runner.py", line 111 in pytest_runtest_protocol
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_callers.py", line 39 in _multicall
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_manager.py", line 80 in _hookexec
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_hooks.py", line 265 in __call__
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/main.py", line 347 in pytest_runtestloop
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_callers.py", line 39 in _multicall
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_manager.py", line 80 in _hookexec
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_hooks.py", line 265 in __call__
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/main.py", line 322 in _main
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/main.py", line 268 in wrap_session
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/main.py", line 315 in pytest_cmdline_main
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_callers.py", line 39 in _multicall
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_manager.py", line 80 in _hookexec
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pluggy/_hooks.py", line 265 in __call__
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/config/__init__.py", line 164 in main
File "/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/_pytest/config/__init__.py", line 187 in console_main
File "/Users/user/miniconda3/envs/py310_tesspy/bin/pytest", line 11 in <module>
Extension modules: numpy.core._multiarray_umath, numpy.core._multiarray_tests, numpy.linalg._umath_linalg, numpy.fft._pocketfft_internal, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._mt19937, numpy.random.mtrand, numpy.random._philox, numpy.random._pcg64, numpy.random._sfc64, numpy.random._generator, pandas._libs.tslibs.dtypes, pandas._libs.tslibs.base, pandas._libs.tslibs.np_datetime, pandas._libs.tslibs.nattype, pandas._libs.tslibs.timezones, pandas._libs.tslibs.ccalendar, pandas._libs.tslibs.tzconversion, pandas._libs.tslibs.strptime, pandas._libs.tslibs.fields, pandas._libs.tslibs.timedeltas, pandas._libs.tslibs.timestamps, pandas._libs.properties, pandas._libs.tslibs.offsets, pandas._libs.tslibs.parsing, pandas._libs.tslibs.conversion, pandas._libs.tslibs.period, pandas._libs.tslibs.vectorized, pandas._libs.ops_dispatch, pandas._libs.missing, pandas._libs.hashtable, pandas._libs.algos, pandas._libs.interval, pandas._libs.tslib, pandas._libs.lib, pandas._libs.hashing, pandas._libs.ops, pandas._libs.arrays, pandas._libs.index, pandas._libs.join, pandas._libs.sparse, pandas._libs.reduction, pandas._libs.indexing, pandas._libs.internals, pandas._libs.writers, pandas._libs.window.aggregations, pandas._libs.window.indexers, pandas._libs.reshape, pandas._libs.groupby, pandas._libs.testing, pandas._libs.parsers, pandas._libs.json, pyproj._compat, pyproj._datadir, pyproj._network, pyproj._geod, pyproj.list, pyproj._crs, pyproj._transformer, pyproj.database, pyproj._sync, pygeos.lib, pygeos._geos, pygeos._geometry, shapely.speedups._speedups, sklearn.__check_build._check_build, scipy._lib._ccallback_c, scipy.sparse._sparsetools, scipy.sparse._csparsetools, scipy.sparse.linalg._isolve._iterative, scipy.linalg._fblas, scipy.linalg._flapack, scipy.linalg._cythonized_array_utils, scipy.linalg._flinalg, scipy.linalg._solve_toeplitz, scipy.linalg._matfuncs_sqrtm_triu, scipy.linalg.cython_lapack, scipy.linalg.cython_blas, scipy.linalg._matfuncs_expm, scipy.linalg._decomp_update, scipy.sparse.linalg._dsolve._superlu, scipy.sparse.linalg._eigen.arpack._arpack, scipy.sparse.csgraph._tools, scipy.sparse.csgraph._shortest_path, scipy.sparse.csgraph._traversal, scipy.sparse.csgraph._min_spanning_tree, scipy.sparse.csgraph._flow, scipy.sparse.csgraph._matching, scipy.sparse.csgraph._reordering, sklearn.utils.murmurhash, psutil._psutil_osx, psutil._psutil_posix, numpy.linalg.lapack_lite, scipy.spatial._ckdtree, scipy._lib.messagestream, scipy.spatial._qhull, scipy.spatial._voronoi, scipy.spatial._distance_wrap, scipy.spatial._hausdorff, scipy.special._ufuncs_cxx, scipy.special._ufuncs, scipy.special._specfun, scipy.special._comb, scipy.special._ellip_harm_2, scipy.spatial.transform._rotation, scipy.ndimage._nd_image, _ni_label, scipy.ndimage._ni_label, scipy.optimize._minpack2, scipy.optimize._group_columns, scipy.optimize._trlib._trlib, scipy.optimize._lbfgsb, _moduleTNC, scipy.optimize._moduleTNC, scipy.optimize._cobyla, scipy.optimize._slsqp, scipy.optimize._minpack, scipy.optimize._lsq.givens_elimination, scipy.optimize._zeros, scipy.optimize.__nnls, scipy.optimize._highs.cython.src._highs_wrapper, scipy.optimize._highs._highs_wrapper, scipy.optimize._highs.cython.src._highs_constants, scipy.optimize._highs._highs_constants, scipy.linalg._interpolative, scipy.optimize._bglu_dense, scipy.optimize._lsap, scipy.optimize._direct, scipy.integrate._odepack, scipy.integrate._quadpack, scipy.integrate._vode, scipy.integrate._dop, scipy.integrate._lsoda, scipy.special.cython_special, scipy.stats._stats, beta_ufunc, scipy.stats._boost.beta_ufunc, binom_ufunc, scipy.stats._boost.binom_ufunc, nbinom_ufunc, scipy.stats._boost.nbinom_ufunc, hypergeom_ufunc, scipy.stats._boost.hypergeom_ufunc, ncf_ufunc, scipy.stats._boost.ncf_ufunc, scipy.interpolate._fitpack, scipy.interpolate.dfitpack, scipy.interpolate._bspl, scipy.interpolate._ppoly, scipy.interpolate.interpnd, scipy.interpolate._rbfinterp_pythran, scipy.stats._biasedurn, scipy.stats._levy_stable.levyst, scipy._lib._uarray._uarray, scipy.stats._hypotests_pythran, scipy.stats._statlib, scipy.stats._mvn, scipy.stats._sobol, scipy.stats._qmc_cy, scipy.stats._unuran.unuran_wrapper, sklearn.utils._openmp_helpers, sklearn.utils._logistic_sigmoid, sklearn.utils.sparsefuncs_fast, sklearn.preprocessing._csr_polynomial_expansion, sklearn.utils._typedefs, sklearn.utils._readonly_array_wrapper, sklearn.metrics._dist_metrics, sklearn.metrics.cluster._expected_mutual_info_fast, sklearn.utils._cython_blas, sklearn.utils._heap, sklearn.utils._sorting, sklearn.utils._vector_sentinel, sklearn.metrics._pairwise_distances_reduction, sklearn.metrics._pairwise_fast, sklearn.neighbors._partition_nodes, sklearn.neighbors._ball_tree, sklearn.neighbors._kd_tree, sklearn.decomposition._cdnmf_fast, sklearn.utils._random, sklearn.utils._seq_dataset, sklearn.utils.arrayfuncs, sklearn.linear_model._cd_fast, sklearn._loss._loss, sklearn.utils._weight_vector, sklearn.linear_model._sgd_fast, sklearn.linear_model._sag_fast, sklearn.svm._libsvm, sklearn.svm._liblinear, sklearn.svm._libsvm_sparse, sklearn.decomposition._online_lda_fast, sklearn._isotonic, sklearn.manifold._utils, sklearn.tree._utils, sklearn.tree._tree, sklearn.tree._splitter, sklearn.tree._criterion, sklearn.neighbors._quad_tree, sklearn.manifold._barnes_hut_tsne, sklearn.cluster._k_means_common, sklearn.cluster._k_means_minibatch, sklearn.cluster._k_means_lloyd, sklearn.cluster._k_means_elkan, sklearn.utils._fast_dict, sklearn.cluster._hierarchical_fast, sklearn.cluster._dbscan_inner, hdbscan.dist_metrics, hdbscan._hdbscan_linkage, hdbscan._hdbscan_tree, hdbscan._hdbscan_reachability, hdbscan._hdbscan_boruvka, scipy.cluster._vq, scipy.cluster._hierarchy, scipy.cluster._optimal_leaf_ordering, hdbscan._prediction_utils, h3._cy.util, h3._cy.cells, h3._cy.edges, h3._cy.geo, h3._cy.to_multipoly, matplotlib._c_internal_utils, PIL._imaging, matplotlib._path, kiwisolver._cext, matplotlib._image, _cffi_backend, unicodedata2, rasterio._version, rasterio._err, rasterio._filepath, rasterio._env, rasterio._transform, rasterio._base, rasterio.crs, rasterio._features, rasterio._warp, rasterio._io, osgeo._gdal, osgeo._gdalconst, osgeo._ogr, osgeo._osr, markupsafe._speedups (total: 243)
Segmentation fault: 11
========================================================================= test session starts =========================================================================
platform darwin -- Python 3.10.5, pytest-7.1.2, pluggy-1.0.0 -- /Users/user/miniconda3/envs/py_tesspy/bin/python
cachedir: .pytest_cache
rootdir: /Users/user/tesspy
plugins: cov-3.0.0
collected 25 items
tests/test_poi_data.py::test_osm_primary_features PASSED [ 4%]
tests/test_poi_data.py::test_create_overpass_query_string PASSED [ 8%]
tests/test_poi_data.py::test_get_poi_data PASSED [ 12%]
tests/test_poi_data.py::test_osm_highway_types PASSED [ 16%]
tests/test_poi_data.py::test_create_custom_filter PASSED [ 20%]
tests/test_poi_data.py::test_get_road_network FAILED [ 24%]
tests/test_tessellation.py::test_squares PASSED [ 28%]
tests/test_tessellation.py::test_hexagons PASSED [ 32%]
tests/test_tessellation.py::test_adaptive_squares PASSED [ 36%]
tests/test_tessellation.py::test_voronoi FAILED [ 40%]
tests/test_tessellation.py::test_city_blocks PASSED [ 44%]
tests/test_tessellation.py::test_new_shapely PASSED [ 48%]
tests/test_tessellation.py::test_index_methods PASSED [ 52%]
tests/test_tessellation.py::test_count_lgu_function_short_version FAILED [ 56%]
tests/test_tessellation.py::test_count_lgu_function_different_city_inputs FAILED [ 60%]
tests/test_tessellation.py::test_count_lgu_function_invalid_inputs_city PASSED [ 64%]
tests/test_tessellation.py::test_count_lgu_function_invalid_inputs_gdf PASSED [ 68%]
tests/test_tessellation.py::test_count_lgu_function_invalid_inputs_method PASSED [ 72%]
tests/test_tessellation.py::test_count_lgu_function_invalid_inputs_poi PASSED [ 76%]
tests/test_tessellation.py::test_count_lgu_function_different_poi FAILED [ 80%]
tests/test_tessellation.py::test_count_lgu_function FAILED [ 84%]
tests/test_tessellation.py::test_poi_collection FAILED [ 88%]
tests/test_tessellation_functions.py::test_count_poi FAILED [ 92%]
tests/test_tessellation_functions.py::test_get_adaptive_squares FAILED [ 96%]
tests/test_tessellation_functions.py::test_split_linestring FAILED [100%]
============================================================================== FAILURES ===============================================================================
________________________________________________________________________ test_get_road_network ________________________________________________________________________
def test_get_road_network():
city = Tessellation("Johannesburg").get_polygon()
split_road_data = RoadData(city, split_roads=True, verbose=True).get_road_network()
road_data = RoadData(city, split_roads=False, verbose=True).get_road_network()
assert len(split_road_data) > 0
assert len(road_data) > 0
> assert len(split_road_data) > len(road_data)
E assert 170 > 170
E + where 170 = len( osmid ref ... lanes maxspeed\nu v key ... \n87962180 88830454 0 10429208 CR 391 ... NaN NaN\n 89202585 0 10429208 CR 391 ... NaN NaN\n 5762605634 0 608171338 NaN ... NaN NaN\n88830454 88845187 0 80565315 CR 391 ... NaN NaN\n 564390667 0 10408441 NaN ... NaN NaN\n... ... ... ... ... ...\n5764378908 5764378910 0 608431386 NaN ... NaN NaN\n 5764378921 0 [608431390, 608431391] NaN ... NaN NaN\n5764378922 5764378921 0 608431391 NaN ... NaN NaN\n 5764378925 0 608431397 NaN ... NaN NaN\n5764378921 5764378925 0 608431393 NaN ... NaN NaN\n\n[170 rows x 10 columns])
E + and 170 = len( osmid ref ... lanes maxspeed\nu v key ... \n87962180 88830454 0 10429208 CR 391 ... NaN NaN\n 89202585 0 10429208 CR 391 ... NaN NaN\n 5762605634 0 608171338 NaN ... NaN NaN\n88830454 88845187 0 80565315 CR 391 ... NaN NaN\n 564390667 0 10408441 NaN ... NaN NaN\n... ... ... ... ... ...\n5764378908 5764378910 0 608431386 NaN ... NaN NaN\n 5764378921 0 [608431390, 608431391] NaN ... NaN NaN\n5764378922 5764378921 0 608431391 NaN ... NaN NaN\n 5764378925 0 608431397 NaN ... NaN NaN\n5764378921 5764378925 0 608431393 NaN ... NaN NaN\n\n[170 rows x 10 columns])
tests/test_poi_data.py:90: AssertionError
------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------
Selected highway type(s) are ['highway'~'motorway|trunk|primary|secondary|tertiary|residential|unclassified|motorway_link|trunk_link|primary_link|secondary_link|living_street|pedestrian|track|bus_guideway|footway|path|service|cycleway']
Collecting road network data...
Collected data has 170 street segments.
Selected highway type(s) are ['highway'~'motorway|trunk|primary|secondary|tertiary|residential|unclassified|motorway_link|trunk_link|primary_link|secondary_link|living_street|pedestrian|track|bus_guideway|footway|path|service|cycleway']
Collecting road network data...
Collected data has 170 street segments.
____________________________________________________________________________ test_voronoi _____________________________________________________________________________
def test_voronoi():
city = Tessellation("Buenos Aires")
city_km = city.voronoi(cluster_algo="k-means",
poi_categories=["amenity"],
timeout=60,
n_polygons=300,
verbose=False)
> assert len(city_km) <= 300
E assert 311 <= 300
E + where 311 = len( voronoi_id geometry\n0 voronoiID0 POLYGON ((-58.39767 -34.65513, -58.39347 -34.6...\n1 voronoiID1 POLYGON ((-58.46076 -34.56834, -58.45698 -34.5...\n2 voronoiID2 POLYGON ((-58.52287 -34.64816, -58.52391 -34.6...\n3 voronoiID3 POLYGON ((-58.39650 -34.58418, -58.39398 -34.5...\n4 voronoiID4 POLYGON ((-58.46027 -34.63412, -58.45995 -34.6...\n.. ... ...\n306 voronoiID306 POLYGON ((-58.36622 -34.59270, -58.36704 -34.5...\n307 voronoiID307 POLYGON ((-58.36935 -34.57830, -58.36795 -34.5...\n308 voronoiID308 POLYGON ((-58.41963 -34.59848, -58.41803 -34.6...\n309 voronoiID309 POLYGON ((-58.39687 -34.63459, -58.39851 -34.6...\n310 voronoiID310 POLYGON ((-58.38743 -34.58682, -58.38620 -34.5...\n\n[311 rows x 2 columns])
tests/test_tessellation.py:68: AssertionError
------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------
MultiPolygon found. Splitting it up...
________________________________________________________________ test_count_lgu_function_short_version ________________________________________________________________
def test_count_lgu_function_short_version():
city = Tessellation("Paris")
poi_categories2 = ["amenity", "building"]
df_squares = city.squares(resolution=14)
> df_squares = count_poi_per_tile(city, df_squares, method="squares", poi_categories=poi_categories2)
tests/test_tessellation.py:118:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
city = <tesspy.tessellation.Tessellation object at 0x16c46b100>
gdf = geometry quadkey
0 POLYGON ((2.24121 48.86471, 2.24121 48.87917...83580, ... 12022001110220
61 POLYGON ((2.48291 48.80686, 2.48291 48.82133, ... 12022001110222
[62 rows x 2 columns]
method = 'squares', poi_categories = ['amenity', 'building'], timeout = 120
def count_poi_per_tile(city,
gdf,
method,
poi_categories=['amenity', 'building'],
timeout=120):
"""
Counts different POI-categories per tile. For each POI-categories an additional column is added to the Tessellation
GeoDataFrame (gdf). After counting each POI-category the final Tessellation GeoDataFrame with the additional count-
columns is returned.
Parameters
----------
city: Tessellation object or string of the underlying city
gdf : GeoDataFrame of the Tessellation for the underlying city
method: method used to tessellate the city polygon. It's used to create the index, the POI and Tessellation-datasets
will be joined on
poi_categories: POI which will be count per tile. These POI may differ from the POI used to create the tessellation
timeout: time to wait for OSM to return POI data
Returns
--------
gdf : GeoDataFrame - Tessellation GeoDataFrame with additional columns (count_poi-columns are added)
"""
if type(city) == str:
city = Tessellation(city)
# Only str input for now
# elif type(city) == Tessellation:
# city = city
# elif type(city) == tesspy.tessellation.Tessellation:
# city = city
else:
> raise ValueError('Please insert a valid city-type. Valid types are: tesspy.Tessellation Obejct or String')
E ValueError: Please insert a valid city-type. Valid types are: tesspy.Tessellation Obejct or String
tesspy/tessellation.py:135: ValueError
____________________________________________________________ test_count_lgu_function_different_city_inputs ____________________________________________________________
def test_count_lgu_function_different_city_inputs():
city = Tessellation("Paris")
city_2 = "Paris"
poi_categories2 = ["amenity", "building"]
df_squares = city.squares(resolution=14)
> df_squares = count_poi_per_tile(city, df_squares, method="squares", poi_categories=poi_categories2)
tests/test_tessellation.py:131:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
city = <tesspy.tessellation.Tessellation object at 0x16dbc5ed0>
gdf = geometry quadkey
0 POLYGON ((2.24121 48.86471, 2.24121 48.87917...83580, ... 12022001110220
61 POLYGON ((2.48291 48.80686, 2.48291 48.82133, ... 12022001110222
[62 rows x 2 columns]
method = 'squares', poi_categories = ['amenity', 'building'], timeout = 120
def count_poi_per_tile(city,
gdf,
method,
poi_categories=['amenity', 'building'],
timeout=120):
"""
Counts different POI-categories per tile. For each POI-categories an additional column is added to the Tessellation
GeoDataFrame (gdf). After counting each POI-category the final Tessellation GeoDataFrame with the additional count-
columns is returned.
Parameters
----------
city: Tessellation object or string of the underlying city
gdf : GeoDataFrame of the Tessellation for the underlying city
method: method used to tessellate the city polygon. It's used to create the index, the POI and Tessellation-datasets
will be joined on
poi_categories: POI which will be count per tile. These POI may differ from the POI used to create the tessellation
timeout: time to wait for OSM to return POI data
Returns
--------
gdf : GeoDataFrame - Tessellation GeoDataFrame with additional columns (count_poi-columns are added)
"""
if type(city) == str:
city = Tessellation(city)
# Only str input for now
# elif type(city) == Tessellation:
# city = city
# elif type(city) == tesspy.tessellation.Tessellation:
# city = city
else:
> raise ValueError('Please insert a valid city-type. Valid types are: tesspy.Tessellation Obejct or String')
E ValueError: Please insert a valid city-type. Valid types are: tesspy.Tessellation Obejct or String
tesspy/tessellation.py:135: ValueError
________________________________________________________________ test_count_lgu_function_different_poi ________________________________________________________________
def test_count_lgu_function_different_poi():
city = Tessellation("Paris")
poi_categories1 = "amenity"
poi_categories2 = ["amenity"]
poi_categories3 = ["amenity", "building"]
df_squares1 = city.squares(resolution=14)
df_squares2 = city.squares(resolution=14)
df_squares3 = city.squares(resolution=14)
> df_squares1 = count_poi_per_tile(city, df_squares1, method="squares", poi_categories=poi_categories1)
tests/test_tessellation.py:208:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
city = <tesspy.tessellation.Tessellation object at 0x165244c40>
gdf = geometry quadkey
0 POLYGON ((2.24121 48.86471, 2.24121 48.87917...83580, ... 12022001110220
61 POLYGON ((2.48291 48.80686, 2.48291 48.82133, ... 12022001110222
[62 rows x 2 columns]
method = 'squares', poi_categories = 'amenity', timeout = 120
def count_poi_per_tile(city,
gdf,
method,
poi_categories=['amenity', 'building'],
timeout=120):
"""
Counts different POI-categories per tile. For each POI-categories an additional column is added to the Tessellation
GeoDataFrame (gdf). After counting each POI-category the final Tessellation GeoDataFrame with the additional count-
columns is returned.
Parameters
----------
city: Tessellation object or string of the underlying city
gdf : GeoDataFrame of the Tessellation for the underlying city
method: method used to tessellate the city polygon. It's used to create the index, the POI and Tessellation-datasets
will be joined on
poi_categories: POI which will be count per tile. These POI may differ from the POI used to create the tessellation
timeout: time to wait for OSM to return POI data
Returns
--------
gdf : GeoDataFrame - Tessellation GeoDataFrame with additional columns (count_poi-columns are added)
"""
if type(city) == str:
city = Tessellation(city)
# Only str input for now
# elif type(city) == Tessellation:
# city = city
# elif type(city) == tesspy.tessellation.Tessellation:
# city = city
else:
> raise ValueError('Please insert a valid city-type. Valid types are: tesspy.Tessellation Obejct or String')
E ValueError: Please insert a valid city-type. Valid types are: tesspy.Tessellation Obejct or String
tesspy/tessellation.py:135: ValueError
_______________________________________________________________________ test_count_lgu_function _______________________________________________________________________
def test_count_lgu_function():
city = Tessellation("Paris")
poi_categories1 = ["amenity"]
poi_categories2 = ["amenity", "building"]
df_squares = city.squares(resolution=14)
> df_squares = count_poi_per_tile(city, df_squares, method="squares", poi_categories=poi_categories1)
tests/test_tessellation.py:226:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
city = <tesspy.tessellation.Tessellation object at 0x16fcd8250>
gdf = geometry quadkey
0 POLYGON ((2.24121 48.86471, 2.24121 48.87917...83580, ... 12022001110220
61 POLYGON ((2.48291 48.80686, 2.48291 48.82133, ... 12022001110222
[62 rows x 2 columns]
method = 'squares', poi_categories = ['amenity'], timeout = 120
def count_poi_per_tile(city,
gdf,
method,
poi_categories=['amenity', 'building'],
timeout=120):
"""
Counts different POI-categories per tile. For each POI-categories an additional column is added to the Tessellation
GeoDataFrame (gdf). After counting each POI-category the final Tessellation GeoDataFrame with the additional count-
columns is returned.
Parameters
----------
city: Tessellation object or string of the underlying city
gdf : GeoDataFrame of the Tessellation for the underlying city
method: method used to tessellate the city polygon. It's used to create the index, the POI and Tessellation-datasets
will be joined on
poi_categories: POI which will be count per tile. These POI may differ from the POI used to create the tessellation
timeout: time to wait for OSM to return POI data
Returns
--------
gdf : GeoDataFrame - Tessellation GeoDataFrame with additional columns (count_poi-columns are added)
"""
if type(city) == str:
city = Tessellation(city)
# Only str input for now
# elif type(city) == Tessellation:
# city = city
# elif type(city) == tesspy.tessellation.Tessellation:
# city = city
else:
> raise ValueError('Please insert a valid city-type. Valid types are: tesspy.Tessellation Obejct or String')
E ValueError: Please insert a valid city-type. Valid types are: tesspy.Tessellation Obejct or String
tesspy/tessellation.py:135: ValueError
_________________________________________________________________________ test_poi_collection _________________________________________________________________________
def test_poi_collection():
city = Tessellation("Frankfurt")
poi_data_1 = POIdata(city.get_polygon(),
poi_categories=["aerialway"],
timeout=60,
> verbose=True).get_poi_data()
tests/test_tessellation.py:263:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <tesspy.poi_data.POIdata object at 0x181d24eb0>
def get_poi_data(self):
"""
sends the query to osm using the overpass API and gets the data
Returns
--------
poi_df : pandas.DataFrame
A dataframe containing the POI, POI type, and coordinates
"""
query_string = self.create_overpass_query_string()
request_header = "https://overpass-api.de/api/interpreter?data="
if self.verbose:
print('Getting data from OSM...')
# sending the request
# todo: polygon instead bbox??
# resp = requests.get("https://overpass-api.de/api/interpreter", data=query_string)
resp = requests.get(url=request_header + query_string)
if resp.status_code == 429:
raise RuntimeError("429 Too Many Requests:\n"
"You have sent multiple requests from the same "
"IP and passed the passed the fair use policy. "
"Please wait a couple of minutes and then try again.")
elif resp.status_code == 504:
raise RuntimeError("504 Gateway Timeout:\n"
"the server has already so much load that"
" the request cannot be executed."
"Please try again later")
elif resp.status_code != 200:
raise RuntimeError("Bad Request!")
else:
resp = json.loads(resp.text)
if self.verbose:
print('Creating POI DataFrame...')
lst_nodes = []
lst_ways = []
generator = resp['elements']
for item in generator:
for cat in self.poi_categories:
if cat in item['tags'].keys():
item[cat] = True
if item['type'] == 'node':
lst_nodes.append(item)
elif item['type'] == 'way':
item['center_latitude'] = np.mean([point['lat'] for point in item['geometry']])
item['center_longitude'] = np.mean([point['lon'] for point in item['geometry']])
lst_ways.append(item)
else:
continue
if self.verbose:
print('Cleaning POI DataFrame...')
nodes_df = pd.DataFrame(lst_nodes)
ways_df = pd.DataFrame(lst_ways)
if len(nodes_df) > 0 and len(ways_df) > 0:
if self.verbose:
print("Joining nodes and ways")
nodes_df['geometry'] = nodes_df[['lon', 'lat']].apply(lambda p: [{'lat': p['lat'],
'lon': p['lon']}],
axis=1)
nodes_df = nodes_df.rename(columns={'lat': 'center_latitude',
'lon': 'center_longitude'})
nodes_df = nodes_df.drop(columns=['id'])
ways_df = ways_df.drop(columns=['id',
'bounds',
'nodes'])
poi_df = pd.concat([ways_df, nodes_df]).fillna(False)
elif len(nodes_df) == 0 and len(ways_df) > 0:
if self.verbose:
print("No nodes found. Return ways only.")
ways_df = ways_df.drop(columns=['id',
'bounds',
'nodes'])
poi_df = ways_df.fillna(False)
elif len(nodes_df) > 0 and len(ways_df) == 0:
if self.verbose:
print("No ways found returning nodes only")
nodes_df['geometry'] = nodes_df[['lon', 'lat']]\
.apply(lambda p: [{'lat': p['lat'],
'lon': p['lon']}],
axis=1)
nodes_df = nodes_df.rename(columns={'lat': 'center_latitude',
'lon': 'center_longitude'})
nodes_df = nodes_df.drop(columns=['id'])
poi_df = nodes_df.fillna(False)
else:
raise ValueError("No POI data for the inserted poi-category/categories and area.")
# add POI categories with no data to poi_df
for poi_category in self.poi_categories:
if not hasattr(poi_df, poi_category):
poi_df[poi_category] = False
# prettify poi_df by sorting columns
first_cols = ['type',
'geometry',
'tags',
'center_latitude',
'center_longitude']
second_cols = sorted(poi_df.columns.drop(first_cols))
poi_df = poi_df[first_cols + second_cols]
poi_df = poi_df.reset_index(drop=True)
# Keep only the POI within the area
geometry_column = [Point(coords) for coords in poi_df[['center_longitude', 'center_latitude']].values]
poi_geo_df = gpd.GeoDataFrame(geometry = geometry_column,
crs='EPSG:4326')
area_buffered_gdf = gpd.GeoDataFrame(geometry=self.area_buffered, crs='epsg:4326')
idx_to_keep = gpd.sjoin(poi_geo_df,
area_buffered_gdf,
predicate='within').index
poi_df = poi_df.loc[idx_to_keep]
if len(poi_df) == 0:
> raise ValueError("No poi data found that is within the area.")
E ValueError: No poi data found that is within the area.
tesspy/poi_data.py:286: ValueError
------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------
Getting data from OSM...
Creating POI DataFrame...
Cleaning POI DataFrame...
No nodes found. Return ways only.
___________________________________________________________________________ test_count_poi ____________________________________________________________________________
def test_count_poi():
city = Tessellation("Berlin")
city_polygon = city.get_polygon()
city_poi = POIdata(city_polygon, poi_categories=["leisure"], timeout=60, verbose=False).get_poi_data()
points_geom = city_poi[['center_longitude', 'center_latitude']]\
.apply(lambda p: Point(p['center_longitude'], p['center_latitude']), axis=1)
tess_data = gpd.GeoDataFrame(geometry=points_geom,
crs='EPSG:4326')
city_squares = city.squares(14)
> count1 = count_poi(city_squares, tess_data)
tests/test_tessellation_functions.py:15:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
tesspy/tessellation_functions.py:54: in count_poi
final_gdf = final_df[['quadkey',
../miniconda3/envs/py_tesspy/lib/python3.10/site-packages/pandas/core/frame.py:3511: in __getitem__
indexer = self.columns._get_indexer_strict(key, "columns")[1]
../miniconda3/envs/py_tesspy/lib/python3.10/site-packages/pandas/core/indexes/base.py:5782: in _get_indexer_strict
self._raise_if_missing(keyarr, indexer, axis_name)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Index(['quadkey', 'count', 'index', 'geometry'], dtype='object'), key = Index(['quadkey', 'count', 'geometry', 'children_id'], dtype='object')
indexer = array([ 0, 1, 3, -1]), axis_name = 'columns'
def _raise_if_missing(self, key, indexer, axis_name: str_t) -> None:
"""
Check that indexer can be used to return a result.
e.g. at least one element was found,
unless the list of keys was actually empty.
Parameters
----------
key : list-like
Targeted labels (only used to show correct error message).
indexer: array-like of booleans
Indices corresponding to the key,
(with -1 indicating not found).
axis_name : str
Raises
------
KeyError
If at least one key was requested but none was found.
"""
if len(key) == 0:
return
# Count missing values
missing_mask = indexer < 0
nmissing = missing_mask.sum()
if nmissing:
# TODO: remove special-case; this is just to keep exception
# message tests from raising while debugging
use_interval_msg = is_interval_dtype(self.dtype) or (
is_categorical_dtype(self.dtype)
# "Index" has no attribute "categories" [attr-defined]
and is_interval_dtype(
self.categories.dtype # type: ignore[attr-defined]
)
)
if nmissing == len(indexer):
if use_interval_msg:
key = list(key)
raise KeyError(f"None of [{key}] are in the [{axis_name}]")
not_found = list(ensure_index(key)[missing_mask.nonzero()[0]].unique())
> raise KeyError(f"{not_found} not in index")
E KeyError: "['children_id'] not in index"
../miniconda3/envs/py_tesspy/lib/python3.10/site-packages/pandas/core/indexes/base.py:5845: KeyError
______________________________________________________________________ test_get_adaptive_squares ______________________________________________________________________
def test_get_adaptive_squares():
city = Tessellation("San Diego")
city_poi = POIdata(city.get_polygon(), poi_categories=["leisure"], timeout=60, verbose=False).get_poi_data()
points_geom = city_poi[['center_longitude', 'center_latitude']] \
.apply(lambda p: Point(p['center_longitude'], p['center_latitude']), axis=1)
tess_data = gpd.GeoDataFrame(geometry=points_geom,
crs='EPSG:4326')
city_squares = city.squares(14)
> count1 = count_poi(city_squares, tess_data)
tests/test_tessellation_functions.py:28:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
tesspy/tessellation_functions.py:54: in count_poi
final_gdf = final_df[['quadkey',
../miniconda3/envs/py_tesspy/lib/python3.10/site-packages/pandas/core/frame.py:3511: in __getitem__
indexer = self.columns._get_indexer_strict(key, "columns")[1]
../miniconda3/envs/py_tesspy/lib/python3.10/site-packages/pandas/core/indexes/base.py:5782: in _get_indexer_strict
self._raise_if_missing(keyarr, indexer, axis_name)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Index(['quadkey', 'count', 'index', 'geometry'], dtype='object'), key = Index(['quadkey', 'count', 'geometry', 'children_id'], dtype='object')
indexer = array([ 0, 1, 3, -1]), axis_name = 'columns'
def _raise_if_missing(self, key, indexer, axis_name: str_t) -> None:
"""
Check that indexer can be used to return a result.
e.g. at least one element was found,
unless the list of keys was actually empty.
Parameters
----------
key : list-like
Targeted labels (only used to show correct error message).
indexer: array-like of booleans
Indices corresponding to the key,
(with -1 indicating not found).
axis_name : str
Raises
------
KeyError
If at least one key was requested but none was found.
"""
if len(key) == 0:
return
# Count missing values
missing_mask = indexer < 0
nmissing = missing_mask.sum()
if nmissing:
# TODO: remove special-case; this is just to keep exception
# message tests from raising while debugging
use_interval_msg = is_interval_dtype(self.dtype) or (
is_categorical_dtype(self.dtype)
# "Index" has no attribute "categories" [attr-defined]
and is_interval_dtype(
self.categories.dtype # type: ignore[attr-defined]
)
)
if nmissing == len(indexer):
if use_interval_msg:
key = list(key)
raise KeyError(f"None of [{key}] are in the [{axis_name}]")
not_found = list(ensure_index(key)[missing_mask.nonzero()[0]].unique())
> raise KeyError(f"{not_found} not in index")
E KeyError: "['children_id'] not in index"
../miniconda3/envs/py_tesspy/lib/python3.10/site-packages/pandas/core/indexes/base.py:5845: KeyError
________________________________________________________________________ test_split_linestring ________________________________________________________________________
def test_split_linestring():
city = Tessellation("Lille")
road_data = RoadData(city.get_polygon(), split_roads=False, verbose=True).get_road_network()
road_data2 = RoadData(city.get_polygon(), split_roads=True, verbose=False).get_road_network()
split_road_data = split_linestring(road_data)
assert len(split_road_data) > len(road_data)
> assert len(split_road_data) == road_data2
tests/test_tessellation_functions.py:40:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = osmid oneway lanes highway maxspeed reversed length geometry ref name bridge ...lse False False False False False False False False False False False
[28859 rows x 17 columns]
@final
def __nonzero__(self):
> raise ValueError(
f"The truth value of a {type(self).__name__} is ambiguous. "
"Use a.empty, a.bool(), a.item(), a.any() or a.all()."
)
E ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
../miniconda3/envs/py_tesspy/lib/python3.10/site-packages/pandas/core/generic.py:1527: ValueError
------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------
Selected highway type(s) are ['highway'~'motorway|trunk|primary|secondary|tertiary|residential|unclassified|motorway_link|trunk_link|primary_link|secondary_link|living_street|pedestrian|track|bus_guideway|footway|path|service|cycleway']
Collecting road network data...
Collected data has 28859 street segments.
========================================================================== warnings summary ===========================================================================
tests/test_tessellation.py::test_adaptive_squares
tests/test_tessellation.py::test_adaptive_squares
tests/test_tessellation.py::test_adaptive_squares
tests/test_tessellation.py::test_adaptive_squares
tests/test_tessellation.py::test_new_shapely
tests/test_tessellation_functions.py::test_count_poi
tests/test_tessellation_functions.py::test_get_adaptive_squares
/Users/user/miniconda3/envs/py_tesspy/lib/python3.10/site-packages/pandas/core/dtypes/cast.py:122: ShapelyDeprecationWarning: The array interface is deprecated and will no longer work in Shapely 2.0. Convert the '.coords' to a numpy array instead.
arr = construct_1d_object_array_from_listlike(values)
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
---------- coverage: platform darwin, python 3.10.5-final-0 ----------
Name Stmts Miss Cover Missing
--------------------------------------------------------------------------------------------------------------------------------
/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pytest/__init__.py 82 80 2% 2-159, 162-164
/Users/user/miniconda3/envs/py310_tesspy/lib/python3.10/site-packages/pytest/__main__.py 3 3 0% 2-5
/Users/user/miniconda3/envs/py_tesspy/lib/python3.10/site-packages/pytest/__init__.py 82 80 2% 2-159, 162-164
/Users/user/miniconda3/envs/py_tesspy/lib/python3.10/site-packages/pytest/__main__.py 3 3 0% 2-5
tesspy/__init__.py 8 8 0% 1-10
tesspy/poi_data.py 149 149 0% 1-403
tesspy/tessellation.py 252 252 0% 1-772
tesspy/tessellation_functions.py 158 158 0% 1-441
--------------------------------------------------------------------------------------------------------------------------------
TOTAL 737 733 1%
Coverage XML written to file coverage.xml
======================================================================= short test summary info =======================================================================
FAILED tests/test_poi_data.py::test_get_road_network - assert 170 > 170
FAILED tests/test_tessellation.py::test_voronoi - assert 311 <= 300
FAILED tests/test_tessellation.py::test_count_lgu_function_short_version - ValueError: Please insert a valid city-type. Valid types are: tesspy.Tessellation Obejct ...
FAILED tests/test_tessellation.py::test_count_lgu_function_different_city_inputs - ValueError: Please insert a valid city-type. Valid types are: tesspy.Tessellation...
FAILED tests/test_tessellation.py::test_count_lgu_function_different_poi - ValueError: Please insert a valid city-type. Valid types are: tesspy.Tessellation Obejct ...
FAILED tests/test_tessellation.py::test_count_lgu_function - ValueError: Please insert a valid city-type. Valid types are: tesspy.Tessellation Obejct or String
FAILED tests/test_tessellation.py::test_poi_collection - ValueError: No poi data found that is within the area.
FAILED tests/test_tessellation_functions.py::test_count_poi - KeyError: "['children_id'] not in index"
FAILED tests/test_tessellation_functions.py::test_get_adaptive_squares - KeyError: "['children_id'] not in index"
FAILED tests/test_tessellation_functions.py::test_split_linestring - ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any...
======================================================= 10 failed, 15 passed, 7 warnings in 1092.84s (0:18:12) ========================================================
The authors should invest some time into setting up a multi-{platform/version} CI. Two examples that may be beneficial that I am involved in can be found in pysal/spopt
and ipums/nhgisxwalk
.
For the returning single data method and specify the name of returning.
It will cause confusion because of missing context.
I got confused when I first saw the documentation.
What is df_qk_squares
, df_h3_hexagons
, and so on?
I suggest deleting the name of returning.
The user doesn't need to know them. They work for the developer.
Lines 264 to 267 in 2ed7c10
Returns
-------
- df_qk_squares : pandas.DataFrame
+ pandas.DataFrame
Dataframe containing squares
PS: the returning type of Tessellation.squares
should be GeoDataFrame
.
xref openjournals/joss-reviews#4620
Have you though about using black
? It is my personal go-to formatter. It is simple to use. And can be added with a pre-commit hook that gets run prior to a PR. This can be run on .py
files for entire repo in one go, including infrastructure files and notebooks.
xref openjournals/joss-reviews#4620
libpysal
xref openjournals/joss-reviews#4620 #12
Fig. 3 right: I don't understand what the 'spatial lag' analysis consists in. Can you say a word about it in the text? is it the result spatial autocorrelation of fig3 left?
xref #6 openjournals/joss-reviews#4620
Lines 23 to 28 in d3e662d
Currently there are no supported Python versions in setup.py
. Ideally, this should match the Python version that are being tested against in CI. As an example see setup.py
in pysal/momepy
.
Not necessarily an issue, but a request (if not already possible).
Instead of using the built in POIs dataset, it'd be useful if I was able to pass in my own GeoDataFrame of points to be used in the tessellations.
After the recent changes in the code (e.g., count_poi function), the new version v0.1.1 should be released on PyPi and conda-forge.
xref openjournals/joss-reviews#4620
During the installation of the requirements_tutorials.txt file using pip install -r requirements_tutorials.txt
:
You should also check this also for the tutorials_env.yaml
By the way there is a typo in the filename, replace tutiruals_env.yaml by tutorials_env
It is hard to work on large data.
The following code block is still running after running for more than 4 min.
import geopandas as gpd
from tesspy import Tessellation
df = (
gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
.query('continent == "Africa"')
.dissolve()
)
Tessellation(df).squares(15)
Basically, we could simplify get_squares_polyfill
method.
First of all, the input of Tessellation
only requires one polygon or multi-polygon.
So we could drop a for
loop to avoid iteratIng GeoDataFrame.
children_id
will be dropped at the latter. So don't generate it at first.
def get_squares_polyfill(polygon, resolution):
"""
Square tessellation based on the quadKeys concept
Parameters
----------
polygon : shapely.geometry.Polygon or shapely.geometry.MultiPolygon
resolution : int
Returns
--------
GeoDataFrame
"""
tiles = mercantile.tiles(*polygon.bounds, resolution)
rows = []
for tile in tiles:
square = box(*mercantile.bounds(tile))
if square.intersects(polygon):
rows.append(dict(geometry=square, quadkey=mercantile.quadkey(tile)))
# I thought Tessellation would create a new GeoDataFrame and it totally different
# to the original one. So we could use 'geometry' as the default name.
return gpd.GeoDataFrame(rows, crs=4326)
xref openjournals/joss-reviews#4620, #4
There is a good start on this in the docs/README, but I would like to see it more cleaned up and fleshed out. For example, the authors have a Contributing to tesspy section, but it states that contribution should be made from the main
branch. However, there is currently no main
, only master
.
xref openjournals/joss-reviews#4620
Docstrings are present (and pretty good for most part). I think another comb through for consistent formatting would a long way towards a positive user experience.
xref openjournals/joss-reviews#4620
There are packages used directly in tesspy
that are not included in the requirements. Also, There are a handful of packages that are necessary to run the tutorials. While I know they are critical to install tesspy
itself, the goal may be to provide a one-stop solution. Maybe adding a requirements_tutorials.txt
or requirements_plus.txt
files with these.
scikit-learn
scipy
contextlily
esda
libpysal
matplotlib
seaborn
statsmodels
Now tesspy
only support GeoDataFrame
.
Most of all tesspy
functions could accept both GeoDataFrame
and GeoSeries
.
And running without any error. Except count_poi
method, sjoin
require GeoDataFrame
.
xref openjournals/joss-reviews#4620 #12
I recommend adding instructions on how to install the development version using setup.py in the README directly (not only in the documentation)
xref openjournals/joss-reviews#4620
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.