Skip to content

Commit

Permalink
Merge pull request #105 from aimclub/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
vasilstar97 committed Jul 26, 2024
2 parents e23f326 + 827580c commit fda0de8
Show file tree
Hide file tree
Showing 51 changed files with 1,834 additions and 2,752 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ on:
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop

permissions:
contents: write
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ dmypy.json

cache/
/examples/data
/tests/data/_*

# PyCharm env
.idea
39 changes: 22 additions & 17 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ Installation

::

pip install git+https://github.com/iduprojects/blocksnet
pip install blocksnet

.. installation-end
Expand All @@ -103,8 +103,8 @@ Next, use the necessary classes and modules:
::

city = City(
blocks_gdf=blocks,
adjacency_matrix=adj_mx
blocks=blocks_gdf,
adj_mx=adj_mx,
)
city.plot()

Expand All @@ -115,11 +115,11 @@ For more detailed use case see our `examples <#examples>`__.
Data
----

Before running the examples, you must download the `input
Before running the examples, one should download the `input
data <https://drive.google.com/drive/folders/1xrLzJ2mcA0Qn7FG0ul8mTkfzKolvUoiP>`__
and place it in the ``examples/data`` directory. You can use your own
data, but it must follow the structure described in the
`API documentation <https://blocknet.readthedocs.io/en/latest/index.html>`__.
`API documentation <https://aimclub.github.io/blocksnet/>`__.

Examples
--------
Expand All @@ -146,7 +146,7 @@ Documentation
-------------

Detailed information and description of BlocksNet is available in
`documentation <https://blocknet.readthedocs.io/en/latest/>`__.
`documentation <https://aimclub.github.io/blocksnet/>`__.

Project Structure
-----------------
Expand All @@ -168,7 +168,7 @@ The repository includes the following directories and modules:
- `examples <https://github.com/iduprojects/blocksnet/tree/main/examples>`__
examples of how methods work
- `docs <https://github.com/iduprojects/blocksnet/tree/main/docs>`__ -
ReadTheDocs documentation
documentation sources

Developing
----------
Expand All @@ -185,9 +185,12 @@ To start developing the library, one must perform following actions:
2. (Optional) Create a virtual environment as the library demands exact package versions:
::

$ python -m venv venv
$ make venv

Activate the virtual environment if you created one.
Activate the virtual environment if you created one:
::

$ source .venv/bin/activate

3. Install the library in editable mode with development dependencies:
::
Expand Down Expand Up @@ -229,18 +232,18 @@ To start developing the library, one must perform following actions:
$ git add modified_files
$ git commit

to record your changes in Git, then push them to GitHub with:
to record your changes in Git, then push them to GitHub with:

::
::

$ git push -u origin my-contribution
$ git push -u origin my-contribution

Finally, go to the web page of your fork of the BlocksNet repo, and click
'Pull Request' (PR) to send your changes to the maintainers for review.
Finally, go to the web page of your fork of the BlocksNet repo, and click
'Pull Request' (PR) to send your changes to the maintainers for review.

.. developing-end
Check out the Contributing on ReadTheDocs for more information.
Check out the `Contributing <https://aimclub.github.io/blocksnet/blocksnet/contributing.html>`__ for more information.

License
-------
Expand Down Expand Up @@ -273,6 +276,8 @@ You can contact us:
- `Tatiana Churiakova <https://t.me/tanya_chk>`__ - project manager
- `Vasilii Starikov <https://t.me/vasilstar>`__ - lead software engineer

Also, you are welcomed to our `issues <https://github.com/aimclub/blocksnet/issues>`__ section!

.. contacts-end
Publications
Expand Down Expand Up @@ -311,8 +316,8 @@ Published:

.. publications-end
.. |Documentation Status| image:: https://readthedocs.org/projects/blocknet/badge/?version=latest
:target: https://blocknet.readthedocs.io/en/latest/?badge=latest
.. |Documentation Status| image:: https://github.com/aimclub/blocksnet/actions/workflows/documentation.yml/badge.svg?branch=main
:target: https://aimclub.github.io/blocksnet/
.. |PythonVersion| image:: https://img.shields.io/badge/python-3.10-blue
:target: https://pypi.org/project/blocksnet/
.. |Black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
Expand Down
81 changes: 55 additions & 26 deletions blocksnet/method/accessibility/accessibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,79 @@
from matplotlib.gridspec import GridSpec
import matplotlib.pyplot as plt

from ...models import Block, ServiceType
from ...models import Block
from ..base_method import BaseMethod

ACCESSIBILITY_TO_COLUMN = "accessibility_to"
ACCESSIBILITY_FROM_COLUMN = "accessibility_from"


class Accessibility(BaseMethod):
"""Class provides methods for block accessibility assessment"""
"""
Provides methods for block accessibility assessment.
def plot(self, gdf: gpd.GeoDataFrame, figsize: tuple[int] = (10, 10)):
# service_type = self.city_model[service_type]
Methods
-------
plot(gdf, vmax, figsize=(10, 10))
Plots accessibility data on a map.
calculate(block)
Calculates accessibility to and from a given block.
"""

@staticmethod
def plot(gdf: gpd.GeoDataFrame, vmax: float = 60, linewidth: float = 0.1, figsize: tuple[int, int] = (10, 10)):
"""
Plots accessibility data for blocks on a map.
Parameters
----------
gdf : geopandas.GeoDataFrame
GeoDataFrame containing block geometries and accessibility data.
vmax : float
Limits the upper value of the legend, by default 60.
linewidth : float
Size of polygons' borders, by default 0.1.
figsize : tuple of int, optional
Size of the figure to plot, by default (10, 10).
Returns
-------
None
"""
fig = plt.figure(figsize=figsize)
grid = GridSpec(1, 2)

ax_to = fig.add_subplot(grid[0, 0])
gdf.plot(ax=ax_to, column=ACCESSIBILITY_TO_COLUMN, cmap="Greens", vmax=60, legend=True).set_axis_off()
gdf.plot(
ax=ax_to, column=ACCESSIBILITY_TO_COLUMN, cmap="Greens", linewidth=linewidth, vmax=vmax, legend=True
).set_axis_off()
ax_to.set_title("To other blocks")
ax_to.set_axis_off()

ax_from = fig.add_subplot(grid[0, 1])
gdf.plot(ax=ax_from, column=ACCESSIBILITY_FROM_COLUMN, cmap="Blues", vmax=60, legend=True).set_axis_off()
gdf.plot(
ax=ax_from, column=ACCESSIBILITY_FROM_COLUMN, cmap="Blues", linewidth=linewidth, vmax=vmax, legend=True
).set_axis_off()
ax_from.set_title("From other blocks")
ax_from.set_axis_off()

def get_context(
self, selected_blocks: list[Block] | list[int], service_type: ServiceType | str
) -> gpd.GeoDataFrame:
service_type = self.city_model[service_type]
accessibility = service_type.accessibility
context_blocks_ids = set()
for selected_block in selected_blocks:
accessible_blocks_gdf = self.calculate(selected_block)
accessible_blocks_gdf = accessible_blocks_gdf.query(
f"accessibility_to<={accessibility} | accessibility_from<={accessibility}"
)
context_blocks_ids.update(accessible_blocks_gdf.index)
context_blocks_gdf = self.city_model.get_blocks_gdf(simplify=True)
context_blocks_gdf = context_blocks_gdf.loc[list(context_blocks_ids)]
return context_blocks_gdf[["geometry"]]

def calculate(self, block: Block | int) -> gpd.GeoDataFrame:
blocks_list = map(lambda b: {"id": b.id, "geometry": b.geometry}, self.city_model.blocks)
blocks_gdf = gpd.GeoDataFrame(blocks_list).set_crs(epsg=self.city_model.epsg)
blocks_gdf[ACCESSIBILITY_TO_COLUMN] = blocks_gdf["id"].apply(lambda b: self.city_model[block, b])
blocks_gdf[ACCESSIBILITY_FROM_COLUMN] = blocks_gdf["id"].apply(lambda b: self.city_model[b, block])
"""
Calculates accessibility to and from a given block.
Parameters
----------
block : Block or int
The block for which accessibility is calculated. It can be an instance
of Block or an integer representing the block ID.
Returns
-------
geopandas.GeoDataFrame
GeoDataFrame containing blocks with calculated accessibility to and from
the specified block.
"""
blocks_gdf = self.city_model.get_blocks_gdf(True)[["geometry"]]
blocks_gdf[ACCESSIBILITY_TO_COLUMN] = blocks_gdf.apply(lambda s: self.city_model[block, int(s.name)], axis=1)
blocks_gdf[ACCESSIBILITY_FROM_COLUMN] = blocks_gdf.apply(lambda s: self.city_model[int(s.name), block], axis=1)
return blocks_gdf
70 changes: 57 additions & 13 deletions blocksnet/method/centrality/centrality.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,59 @@

class Centrality(BaseMethod):
"""
This class allows us to analyse the distribution and diversity of points of interest in urban areas,
measure connectivity and compute centrality indices based on various geometric and network properties.
Provides methods to analyze the distribution and diversity of points of interest in urban areas,
measure connectivity, and compute centrality indices based on various geometric and network properties.
Methods
-------
plot(gdf, linewidth=0.1, figsize=(10, 10))
Plots centrality data on a map.
diversity : gpd.GeoDataFrame
Calculates diversity for the city model.
connectivity : gpd.GeoDataFrame
Calculates connectivity for the city model.
calculate(connectivity_weight=1, density_weight=1, diversity_weight=1) -> gpd.GeoDataFrame
Calculates centrality metrics for polygons based on point data and connectivity.
"""

@staticmethod
def plot(gdf: gpd.GeoDataFrame, figsize=(10, 10)):
ax = gdf.plot(color="#ddd", figsize=(10, 10))
gdf.plot(ax=ax, **PLOT_KWARGS)
def plot(gdf: gpd.GeoDataFrame, linewidth: float = 0.1, figsize: tuple[int, int] = (10, 10)):
"""
Plots centrality data for blocks on a map.
Parameters
----------
gdf : geopandas.GeoDataFrame
GeoDataFrame containing block geometries and centrality data.
linewidth : float, optional
Line width for plotting the geometries, by default 0.1.
figsize : tuple of int, optional
Size of the figure to plot, by default (10, 10).
Returns
-------
None
"""
ax = gdf.plot(color="#ddd", linewidth=linewidth, figsize=figsize)
gdf.plot(ax=ax, linewidth=linewidth, **PLOT_KWARGS)
ax.set_axis_off()

@property
def diversity(self) -> gpd.GeoDataFrame:
"""
Calculates diversity for the city model.
Returns
-------
geopandas.GeoDataFrame
GeoDataFrame containing blocks with calculated diversity of services.
"""
div = Diversity(city_model=self.city_model)
return div.calculate()

@property
def connectivity(self) -> gpd.GeoDataFrame:

"""
Calculate connectivity for the city model.
Expand All @@ -43,16 +79,24 @@ def calculate(
self, connectivity_weight: float = 1, density_weight: float = 1, diversity_weight: float = 1
) -> gpd.GeoDataFrame:
"""
Calculate centrality metrics for polygons based on point data and connectivity.
Parameters:
- points: A GeoDataFrame of point geometries.
Returns:
- A GeoDataFrame of polygons with added centrality metrics.
Calculates centrality metrics for polygons based on point data and connectivity.
Parameters
----------
connectivity_weight : float, optional
Weight for the connectivity metric, by default 1.
density_weight : float, optional
Weight for the density metric, by default 1.
diversity_weight : float, optional
Weight for the diversity metric, by default 1.
Returns
-------
geopandas.GeoDataFrame
GeoDataFrame containing blocks with calculated centrality metrics.
"""
# get blocks diversity and connectivity indices
blocks = self.city_model.get_blocks_gdf()
blocks = self.city_model.get_blocks_gdf(True)
blocks[DIVERSITY_COLUMN] = self.diversity[DIVERSITY_COLUMN]
blocks[CONNECTIVITY_COLUMN] = self.connectivity[CONNECTIVITY_COLUMN]

Expand Down
Loading

0 comments on commit fda0de8

Please sign in to comment.