All Projects → kylebarron → suncalc-py

kylebarron / suncalc-py

Licence: MIT license
A Python port of suncalc.js for calculating sun position and sunlight phases

Programming Languages

python
139335 projects - #7 most used programming language

Projects that are alternatives of or similar to suncalc-py

astro
自用天文算法,公历农历转换、八大行星位置、日出日落月出月落时间、节气物候时间等
Stars: ✭ 33 (+6.45%)
Mutual labels:  sunrise, sunset, sun
rust-sun
A Rust library for calculating sun positions
Stars: ✭ 31 (+0%)
Mutual labels:  sunrise, sunset, sun
sunrisesunset
🌅 Go package that provides the sunrise and sunset equation
Stars: ✭ 75 (+141.94%)
Mutual labels:  sunrise, sunset
Solar-Calculator
Calculates the sunrise and sunset for a given date and location (using GEO coordinates). This library uses the method outlined NOAA Solar Calculations Day spreadsheet found at http://www.esrl.noaa.gov/gmd/grad/solcalc/calcdetails.html.
Stars: ✭ 36 (+16.13%)
Mutual labels:  sunrise, sunset
astral
☀️ Go calculations for the position of the sun and moon.
Stars: ✭ 23 (-25.81%)
Mutual labels:  sunrise, sunset
KosherCocoa
My Objective-C port of KosherJava. KosherCocoa enables you to perform sunrise-based and sunset-based calculations for Jewish prayer and calendar.
Stars: ✭ 49 (+58.06%)
Mutual labels:  sunrise, sunset
go-sunrise
Go package for calculating the sunrise and sunset times for a given location
Stars: ✭ 42 (+35.48%)
Mutual labels:  sunrise, sunset
Daylight-Calendar-ICS
Daylight Calendar is a dynamically generated .ics calendar that you can host and subscribe to in Google Calendar, iCal, or other calendar software.
Stars: ✭ 22 (-29.03%)
Mutual labels:  sunrise, sunset
sun
Simple library and application that shows sunset and sunrise based on your latitude,longitude
Stars: ✭ 23 (-25.81%)
Mutual labels:  sunrise, sunset
Sunscreen
🌅 A macOS app that sets your wallpaper based on sunrise and sunset.
Stars: ✭ 52 (+67.74%)
Mutual labels:  sunrise, sunset
Solar-System-Unity3D
Solar System Simulator
Stars: ✭ 20 (-35.48%)
Mutual labels:  sun
sunrise-electron-vue
SunRise项目-前端 sunrise-electron-vue。该项目是一个后台前端解决方案,它基于 vue.js 开发堆栈和 electron 并使用 element-ui 实现。它使用了最新的前端技术栈,内置了 i18n 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。
Stars: ✭ 48 (+54.84%)
Mutual labels:  sunrise
mobileid
Mobile ID Sample Scripts
Stars: ✭ 13 (-58.06%)
Mutual labels:  sunrise
sunraster
A SunPy-affiliated package which provides tools to analyze data from spectral data from any solar mission.
Stars: ✭ 19 (-38.71%)
Mutual labels:  sunrise
homebridge-eosstb
A homebridge plugin for the EOS set-top box as used by Sunrise, Telenet, Ziggo, Magenta, Virgin Media and maybe more in various countries on the Horizon Go (HGO) platform
Stars: ✭ 25 (-19.35%)
Mutual labels:  sunrise
kirby3-suncyclepages
kirby3 plugin to embargo pages until sunrise date and withdraw at sunset date
Stars: ✭ 17 (-45.16%)
Mutual labels:  sunset
sun
Get information on the position of the sun
Stars: ✭ 64 (+106.45%)
Mutual labels:  sun
home-assistant-sun-card
Home assistant sun card based on Google weather design
Stars: ✭ 279 (+800%)
Mutual labels:  sun
self-propelled-satellites
The system is formed by self-propelled satellites influenced by the Sun whose objective is not to leave the domain maintaining the maximum possible speed.
Stars: ✭ 18 (-41.94%)
Mutual labels:  sun

suncalc-py

Test Package version Downloads

A fast, vectorized Python implementation of suncalc.js for calculating sun position and sunlight phases (times for sunrise, sunset, dusk, etc.) for the given location and time.

While other similar libraries exist, I didn't originally encounter any that met my requirements of being openly-licensed, vectorized, and simple to use 1.

Install

pip install suncalc

Using

Example

suncalc is designed to work both with single values and with arrays of values.

First, import the module:

from suncalc import get_position, get_times
from datetime import datetime

There are currently two methods: get_position, to get the sun azimuth and altitude for a given date and position, and get_times, to get sunlight phases for a given date and position.

date = datetime.now()
lon = 20
lat = 45
get_position(date, lon, lat)
# {'azimuth': -0.8619668996997687, 'altitude': 0.5586446727994595}

get_times(date, lon, lat)
# {'solar_noon': Timestamp('2020-11-20 08:47:08.410863770'),
#  'nadir': Timestamp('2020-11-19 20:47:08.410863770'),
#  'sunrise': Timestamp('2020-11-20 03:13:22.645455322'),
#  'sunset': Timestamp('2020-11-20 14:20:54.176272461'),
#  'sunrise_end': Timestamp('2020-11-20 03:15:48.318936035'),
#  'sunset_start': Timestamp('2020-11-20 14:18:28.502791748'),
#  'dawn': Timestamp('2020-11-20 02:50:00.045539551'),
#  'dusk': Timestamp('2020-11-20 14:44:16.776188232'),
#  'nautical_dawn': Timestamp('2020-11-20 02:23:10.019832520'),
#  'nautical_dusk': Timestamp('2020-11-20 15:11:06.801895264'),
#  'night_end': Timestamp('2020-11-20 01:56:36.144269287'),
#  'night': Timestamp('2020-11-20 15:37:40.677458252'),
#  'golden_hour_end': Timestamp('2020-11-20 03:44:46.795967773'),
#  'golden_hour': Timestamp('2020-11-20 13:49:30.025760010')}

These methods also work for arrays of data, and since the implementation is vectorized it's much faster than a for loop in Python.

import pandas as pd

df = pd.DataFrame({
    'date': [date] * 10,
    'lon': [lon] * 10,
    'lat': [lat] * 10
})
pd.DataFrame(get_position(df['date'], df['lon'], df['lat']))
# azimuth	altitude
# 0	-1.485509	-1.048223
# 1	-1.485509	-1.048223
# ...

pd.DataFrame(get_times(df['date'], df['lon'], df['lat']))['solar_noon']
# 0   2020-11-20 08:47:08.410863872+00:00
# 1   2020-11-20 08:47:08.410863872+00:00
# ...
# Name: solar_noon, dtype: datetime64[ns, UTC]

If you want to join this data back to your DataFrame, you can use pd.concat:

times = pd.DataFrame(get_times(df['date'], df['lon'], df['lat']))
pd.concat([df, times], axis=1)

API

get_position

Calculate sun position (azimuth and altitude) for a given date and latitude/longitude

  • date (datetime or a pandas series of datetimes): date and time to find sun position of. Datetime must be in UTC.
  • lng (float or numpy array of float): longitude to find sun position of
  • lat (float or numpy array of float): latitude to find sun position of

Returns a dict with two keys: azimuth and altitude. If the input values were singletons, the dict's values will be floats. Otherwise they'll be numpy arrays of floats.

get_times

  • date (datetime or a pandas series of datetimes): date and time to find sunlight phases of. Datetime must be in UTC.

  • lng (float or numpy array of float): longitude to find sunlight phases of

  • lat (float or numpy array of float): latitude to find sunlight phases of

  • height (float or numpy array of float, default 0): observer height in meters

  • times (Iterable[Tuple[float, str, str]]): an iterable defining the angle above the horizon and strings for custom sunlight phases. The default is:

    # (angle, morning name, evening name)
    DEFAULT_TIMES = [
        (-0.833, 'sunrise', 'sunset'),
        (-0.3, 'sunrise_end', 'sunset_start'),
        (-6, 'dawn', 'dusk'),
        (-12, 'nautical_dawn', 'nautical_dusk'),
        (-18, 'night_end', 'night'),
        (6, 'golden_hour_end', 'golden_hour')
    ]

Returns a dict where the keys are solar_noon, nadir, plus any keys passed in the times argument. If the input values were singletons, the dict's values will be of type datetime.datetime (or pd.Timestamp if you have pandas installed, which is a subclass of and therefore compatible with datetime.datetime). Otherwise they'll be pandas DateTime series. The returned times will be in UTC.

Benchmark

This benchmark is to show that the vectorized implementation is nearly 100x faster than a for loop in Python.

First set up a DataFrame with random data. Here I create 100,000 rows.

from suncalc import get_position, get_times
import pandas as pd

def random_dates(start, end, n=10):
    """Create an array of random dates"""
    start_u = start.value//10**9
    end_u = end.value//10**9
    return pd.to_datetime(np.random.randint(start_u, end_u, n), unit='s')

start = pd.to_datetime('2015-01-01')
end = pd.to_datetime('2018-01-01')
dates = random_dates(start, end, n=100_000)

lons = np.random.uniform(low=-179, high=179, size=(100_000,))
lats = np.random.uniform(low=-89, high=89, size=(100_000,))

df = pd.DataFrame({'date': dates, 'lat': lats, 'lon': lons})

Then compute SunCalc.get_position two ways: the first using the vectorized implementation and the second using df.apply, which is equivalent to a for loop. The first is more than 100x faster than the second.

%timeit get_position(df['date'], df['lon'], df['lat'])
# 41.4 ms ± 437 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit df.apply(lambda row: get_position(row['date'], row['lon'], row['lat']), axis=1)
# 4.89 s ± 184 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Likewise, compute SunCalc.get_times the same two ways: first using the vectorized implementation and the second using df.apply. The first is 2800x faster than the second! Some of the difference here is that under the hood the non-vectorized approach uses pd.to_datetime while the vectorized implementation uses np.astype('datetime64[ns, UTC]'). pd.to_datetime is really slow!!

%timeit get_times(df['date'], df['lon'], df['lat'])
# 55.3 ms ± 1.91 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%time df.apply(lambda row: get_times(row['date'], row['lon'], row['lat']), axis=1)
# CPU times: user 2min 33s, sys: 288 ms, total: 2min 34s
# Wall time: 2min 34s

1: pyorbital looks great but is GPL3-licensed; pysolar is also GPL3-licensed; pyEphem is LGPL3-licensed. suncalcPy is another port of suncalc.js, and is MIT-licensed, but doesn't use Numpy and thus isn't vectorized. I recently discovered sunpy and astropy, both of which probably would've worked but I didn't see them at first and they look quite complex for this simple task...

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].