Skip to content

Commit

Permalink
Merge pull request #7 from ni1o1/0.3.1
Browse files Browse the repository at this point in the history
0.3.1
  • Loading branch information
ni1o1 authored May 4, 2022
2 parents 574b637 + 113f4a9 commit 0e38745
Show file tree
Hide file tree
Showing 7 changed files with 261 additions and 100 deletions.
27 changes: 27 additions & 0 deletions docs/source/analysis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,33 @@ Shadow coverage
Shadow coverage
--------------------------------------

.. function:: pybdshadow.cal_sunshine(buildings, day='2022-01-01', roof=False,grids = gpd.GeoDataFrame(), accuracy=1, precision=3600, padding=0)

Calculate the sunshine time in given date.

**Parameters**

buildings : GeoDataFrame
Buildings. coordinate system should be WGS84
day : str
the day to calculate the sunshine
roof : bool
whether to calculate roof shadow.
grids : GeoDataFrame
grids generated by TransBigData in study area
precision : number
time precision(s)
padding : number
padding time before and after sunrise and sunset
accuracy : number
size of grids.

**Return**

grids : GeoDataFrame
grids generated by TransBigData in study area, each grids have a `time` column store the sunshine time


.. function:: pybdshadow.cal_sunshadows(buildings, cityname='somecity', dates=['2022-01-01'], gap=3600,roof=True, include_building=True,save_shadows=False,printlog=False)

Calculate the sunlight shadow in different date with given time gap.
Expand Down
4 changes: 2 additions & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
author = 'Qing Yu'

# The full version, including alpha/beta/rc tags
release = '0.3.0'
version = '0.3.0'
release = '0.3.1'
version = '0.3.1'
html_logo = "_static/logo-wordmark-light.png"
html_favicon = '_static/logo.ico'
# -- General configuration ---------------------------------------------------
Expand Down
187 changes: 132 additions & 55 deletions example/example-analysis.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="pybdshadow",
version="0.3.0",
version="0.3.1",
author="Qing Yu",
author_email="[email protected]",
description="Python package to generate building shadow geometry",
Expand Down
4 changes: 3 additions & 1 deletion src/pybdshadow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""

__version__ = '0.3.0'
__version__ = '0.3.1'
__author__ = 'Qing Yu <[email protected]>'

# module level doc-string
Expand All @@ -51,6 +51,7 @@
show_bdshadow,
)
from .analysis import (
cal_sunshine,
cal_sunshadows,
cal_shadowcoverage
)
Expand All @@ -59,6 +60,7 @@
'bdshadow_pointlight',
'bd_preprocess',
'show_bdshadow',
'cal_sunshine',
'cal_sunshadows',
'cal_shadowcoverage',
]
128 changes: 90 additions & 38 deletions src/pybdshadow/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
from .preprocess import bd_preprocess


def get_timetable(lon, lat, dates=['2022-01-01'], gap=3600, padding=1800):
def get_timetable(lon, lat, dates=['2022-01-01'], precision=3600, padding=1800):
# generate timetable
def get_timeSeries(day, lon, lat, gap=3600, padding=1800):
def get_timeSeries(day, lon, lat, precision=3600, padding=1800):
date = pd.to_datetime(day+' 12:45:33.959797119')
times = get_times(date, lon, lat)
date_sunrise = times['sunrise']
Expand All @@ -21,18 +21,66 @@ def get_timeSeries(day, lon, lat, gap=3600, padding=1800):
times = pd.to_datetime(pd.Series(range(
timestamp_sunrise.iloc[0]+padding*1000000000,
timestamp_sunset.iloc[0]-padding*1000000000,
gap*1000000000)))
precision*1000000000)))
return times
dates = pd.DataFrame(pd.concat(
[get_timeSeries(date, lon, lat, gap,padding) for date in dates]), columns=['datetime'])
[get_timeSeries(date, lon, lat, precision,padding) for date in dates]), columns=['datetime'])
dates['date'] = dates['datetime'].apply(lambda r: str(r)[:19])
return dates


def cal_sunshadows(buildings, cityname='somecity', dates=['2022-01-01'], gap=3600,
roof=True, include_building=True,save_shadows=False,printlog=False):
def cal_sunshine(buildings, day='2022-01-01', roof=False,grids = gpd.GeoDataFrame(), accuracy=1, precision=3600, padding=0):
'''
Calculate the sunlight shadow in different date with given time gap.
Calculate the sunshine time in given date.
**Parameters**
buildings : GeoDataFrame
Buildings. coordinate system should be WGS84
day : str
the day to calculate the sunshine
roof : bool
whether to calculate roof shadow.
grids : GeoDataFrame
grids generated by TransBigData in study area
precision : number
time precision(s)
padding : number
padding time before and after sunrise and sunset
accuracy : number
size of grids.
**Return**
grids : GeoDataFrame
grids generated by TransBigData in study area, each grids have a `time` column store the sunshine time
'''
# 计算白天时间
lon, lat = buildings['geometry'].iloc[0].bounds[:2]
date = pd.to_datetime(day+' 12:45:33.959797119')
times = get_times(date, lon, lat)
date_sunrise = times['sunrise']
data_sunset = times['sunset']
timestamp_sunrise = pd.Series(date_sunrise).astype('int')
timestamp_sunset = pd.Series(data_sunset).astype('int')
sunlighthour = (
timestamp_sunset.iloc[0]-timestamp_sunrise.iloc[0])/(1000000000*3600)

# Generate shadow every 1800 s
shadows = cal_sunshadows(buildings, dates=[day], precision=precision, padding=padding)
# Grid analysis of shadow cover duration(ground).
grids = cal_shadowcoverage(
shadows, buildings, grids = grids,roof=roof, precision=precision, accuracy=accuracy)

grids['Hour'] = sunlighthour-grids['time']/3600
return grids


def cal_sunshadows(buildings, cityname='somecity', dates=['2022-01-01'], precision=3600, padding=0,
roof=True, include_building=True, save_shadows=False, printlog=False):
'''
Calculate the sunlight shadow in different date with given time precision.
**Parameters**
Expand All @@ -42,8 +90,10 @@ def cal_sunshadows(buildings, cityname='somecity', dates=['2022-01-01'], gap=360
Cityname. If save_shadows, this function will create `result/cityname` folder to save the shadows
dates : list
list of dates
gap : number
time gap(s)
precision : number
time precision(s)
padding : number
padding time before and after sunrise and sunset
roof : bool
whether to calculate roof shadow.
include_building : bool
Expand All @@ -60,7 +110,7 @@ def cal_sunshadows(buildings, cityname='somecity', dates=['2022-01-01'], gap=360
'''
# 获取城市位置
lon, lat = buildings['geometry'].iloc[0].bounds[:2]
timetable = get_timetable(lon, lat, dates, gap)
timetable = get_timetable(lon, lat, dates, precision, padding)
import os
if save_shadows:
if not os.path.exists('result'):
Expand All @@ -82,18 +132,18 @@ def cal_sunshadows(buildings, cityname='somecity', dates=['2022-01-01'], gap=360
ground_shaodws = shadows[shadows['type'] == 'ground']

if save_shadows:
if len(roof_shaodws)>0:
if len(roof_shaodws) > 0:
roof_shaodws.to_file(
'result/'+cityname+'/roof_'+name+'.json', driver='GeoJSON')
if len(ground_shaodws)>0:
if len(ground_shaodws) > 0:
ground_shaodws.to_file(
'result/'+cityname+'/ground_'+name+'.json', driver='GeoJSON')
'result/'+cityname+'/ground_'+name+'.json', driver='GeoJSON')
allshadow.append(shadows)
allshadow = pd.concat(allshadow)
return allshadow


def cal_shadowcoverage(shadows_input,buildings,roof=True,gap = 3600,accuracy=1):
def cal_shadowcoverage(shadows_input, buildings, grids = gpd.GeoDataFrame(),roof=True, precision=3600, accuracy=1):
'''
Calculate the sunlight shadow coverage time for given area.
Expand All @@ -103,44 +153,46 @@ def cal_shadowcoverage(shadows_input,buildings,roof=True,gap = 3600,accuracy=1):
All building shadows calculated
buildings : GeoDataFrame
Buildings. coordinate system should be WGS84
grids : GeoDataFrame
grids generated by TransBigData in study area
roof : bool
If true roof shadow, false then ground shadow
gap : number
time gap(s), which is for calculation of coverage time
precision : number
time precision(s), which is for calculation of coverage time
accuracy : number
size of grids.
**Return**
bdgrids : GeoDataFrame
grids : GeoDataFrame
grids generated by TransBigData in study area, each grids have a `time` column store the shadow coverage time
'''
shadows = bd_preprocess(shadows_input)

# 研究区域
bounds = buildings.unary_union.bounds
if len(grids)==0:
grids, params = tbd.area_to_grid(bounds, accuracy)

if roof:
ground_shadows = shadows[shadows['type']=='roof'].groupby(['date'])['geometry'].apply(
lambda df: MultiPolygon(list(df)).buffer(0)).reset_index()
#研究区域
bounds = buildings.unary_union.bounds

bdgrids,params = tbd.area_to_grid(bounds,accuracy)
ground_shadows = shadows[shadows['type'] == 'roof'].groupby(['date'])['geometry'].apply(
lambda df: MultiPolygon(list(df)).buffer(0)).reset_index()

buildings.crs = None
bdgrids = gpd.sjoin(bdgrids,buildings)
grids = gpd.sjoin(grids, buildings)
else:
ground_shadows = shadows[shadows['type']=='ground'].groupby(['date'])['geometry'].apply(
lambda df: MultiPolygon(list(df)).buffer(0)).reset_index()

#研究区域
bounds = buildings.unary_union.bounds
bdgrids,params = tbd.area_to_grid(bounds,accuracy)
ground_shadows = shadows[shadows['type'] == 'ground'].groupby(['date'])['geometry'].apply(
lambda df: MultiPolygon(list(df)).buffer(0)).reset_index()

buildings.crs = None
bdgrids = gpd.sjoin(bdgrids,buildings,how='left')
bdgrids = bdgrids[bdgrids['index_right'].isnull()]
grids = gpd.sjoin(grids, buildings, how='left')
grids = grids[grids['index_right'].isnull()]

gridcount = gpd.sjoin(bdgrids[['LONCOL','LATCOL','geometry']],ground_shadows[['geometry']]).\
groupby(['LONCOL','LATCOL'])['geometry'].count().rename('count').reset_index()
bdgrids = pd.merge(bdgrids,gridcount,how='left')
bdgrids['time'] = bdgrids['count'].fillna(0)*gap
gridcount = gpd.sjoin(grids[['LONCOL', 'LATCOL', 'geometry']], ground_shadows[['geometry','date']]).\
drop_duplicates(subset=['LONCOL', 'LATCOL','date']).groupby(['LONCOL', 'LATCOL'])['geometry'].\
count().rename('count').reset_index()
grids = pd.merge(grids, gridcount, how='left')
grids['time'] = grids['count'].fillna(0)*precision

return bdgrids
return grids
9 changes: 6 additions & 3 deletions src/pybdshadow/tests/test_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ def test_analysis(self):
buildings = pybdshadow.bd_preprocess(buildings)
#分析
date = '2022-01-01'
shadows = pybdshadow.cal_sunshadows(buildings,dates = [date],gap=3600)
bdgrids = pybdshadow.cal_shadowcoverage(shadows,buildings,gap = 3600,accuracy=2)
assert len(bdgrids)==1185
shadows = pybdshadow.cal_sunshadows(buildings,dates = [date],precision=3600)
bdgrids = pybdshadow.cal_shadowcoverage(shadows,buildings,precision = 3600,accuracy=2)
assert len(bdgrids)==1185

grids = pybdshadow.cal_sunshine(buildings)
assert len(grids)==1882

0 comments on commit 0e38745

Please sign in to comment.