camfi.datamodel.weather module¶
Provides utilities for working with weather data, and for calculating the movement of the sun from the persepcitve of specific locations.
Constants defined in this module¶
These can all be overwritten by setting environment variables with the same name.
SKYFIELD_DATA_DIR. Path to directory to save skyfield ephemeris data. By default,~/skyfield-datawill be used.CAMFI_EPHEMERIS. Name of ephemeris file to use for calculating sunset and twilight. By default,de440s.bspwill be used. See the choosing an ephemeris in the Skyfield documentation for possible other ephemeris files to use. Note that the ephemeris file will be loaded when this module is imported. The first time this happens, the ephemeris file will be downloaded (def4402.bsp is about 37 mb).
Note: For testing purposes, a tiny abbreviated ephemeris file is included in the Camfi git repository. Without this, CI testing wouldn’t work. The included ephemeris limits the date range to a few days in 2021, so it should not be used when running Camfi normally. To use the included ephemeris (for testing purposes only), set the following environment variables (assuming you are running the tests from the camfi repo root directory):
SKYFIELD_DATA_DIR="camfi/test/data"
CAMFI_EPHEMERIS="test_ephem.bsp"
- class camfi.datamodel.weather.Location(*, name: str, lat: float, lon: float, elevation_m: pydantic.types.NonNegativeFloat, tz: camfi.util.Timezone)¶
Bases:
pydantic.main.BaseModelProvides methods for working with locations.
- Parameters
name (str) – Name of location.
lat (float) – Decimal latitude.
lon (float) – Decimal longitude.
elevation_m (NonNegativeFloat) – Elevation in metres.
tz (timezone) – Timezone offset. Can be given as ISO8601 timezone offset str (e.g. ‘Z’ or ‘+10:00’ or simply ‘+10’).
Examples
>>> Location( ... name="canberra", ... lat=-35.293056, ... lon=149.126944, ... elevation_m=578, ... tz="+10:00", ... ) Location(name='canberra', lat=-35.293056, lon=149.126944, elevation_m=578.0, tz=Timezone(datetime.timezone(datetime.timedelta(seconds=36000)))) >>> Location( ... name="greenwich", ... lat=51.48, ... lon=0, ... elevation_m=47, ... tz="Z", ... ) Location(name='greenwich', lat=51.48, lon=0.0, elevation_m=47.0, tz=Timezone(datetime.timezone.utc)) >>> Location( ... name="nyc", ... lat=40.712778, ... lon=-74.006111, ... elevation_m=10, ... tz="-05", ... ) Location(name='nyc', lat=40.712778, lon=-74.006111, elevation_m=10.0, tz=Timezone(datetime.timezone(datetime.timedelta(days=-1, seconds=68400))))
- get_sun_time_dataframe(days: Sequence[datetime.date]) pandas.core.frame.DataFrame¶
Calls self.search_sun_times on each day in days, and builds a DataFrame of sun times.
- Parameters
days (Sequence[date]) – Dates which will become index for dataframe.
- Returns
sun_df – DataFrame indexed by location and date, with columns “astronomical_twilight_start”, “nautical_twilight_start”, “civil_twilight_start”, “sunrise”, “sunset”, “nautical_twilight_end”, “civil_twilight_end”, “astronomical_twilight_end”.
- Return type
pd.DataFrame
Examples
>>> location = Location( ... name="canberra", ... lat=-35.293056, ... lon=149.126944, ... elevation_m=578, ... tz=timezone(timedelta(hours=10)), ... ) >>> days = [date(2021, 7, 23), date(2021, 7, 24), date(2021, 7, 25)] >>> sun_df = location.get_sun_time_dataframe(days) >>> np.all(sun_df["sunset"] > sun_df["sunrise"]) True >>> sun_df astronomical_twilight_start ... astronomical_twilight_end location date ... canberra 2021-07-23 2021-07-23 05:36:52.178788+10:00 ... 2021-07-23 18:43:25.223475+10:00 2021-07-24 2021-07-24 05:36:20.903963+10:00 ... 2021-07-24 18:43:59.629041+10:00 2021-07-25 2021-07-25 05:35:48.170485+10:00 ... 2021-07-25 18:44:34.315154+10:00 [3 rows x 8 columns]
- search_sun_times(day: datetime.date) dict¶
Gets sunrise, sunset, and twilight times for a given date.
- Parameters
day (date) – Day to get times from.
- Returns
twilight_times – dictionary with keys “astronomical_twilight_start”, “nautical_twilight_start”, “civil_twilight_start”, “sunrise”, “sunset”, “nautical_twilight_end”, “civil_twilight_end”, “astronomical_twilight_end”.
- Return type
dict[str, datetime]
Examples
>>> location = Location( ... name="canberra", ... lat=-35.293056, ... lon=149.126944, ... elevation_m=578, ... tz=timezone(timedelta(hours=10)), ... ) >>> day = date(2021, 7, 28) >>> tt = location.search_sun_times(day)
The ordering of the transitions is as expected.
>>> tt["astronomical_twilight_start"] < tt["nautical_twilight_start"] True >>> tt["nautical_twilight_start"] < tt["civil_twilight_start"] True >>> tt["civil_twilight_start"] < tt["sunrise"] True >>> tt["sunrise"] < tt["sunset"] True >>> tt["sunset"] < tt["civil_twilight_end"] True >>> tt["civil_twilight_end"] < tt["nautical_twilight_end"] True >>> tt["nautical_twilight_end"] < tt["astronomical_twilight_end"] True
And all of the datetimes are on the correct day.
>>> all(d.date() == day for d in tt.values()) True
- twilight_state(dt: datetime.datetime) int¶
Gets the twilight state for the location at the specified time(s).
The meanings of the returned integer values are
Dark of night.
Astronomical twilight.
Nautical twilight.
Civil twilight.
Daytime.
- Parameters
dt (datetime) – datetime to evaluate. If timezone-naive, timezone will be taken from self.tz.
- Returns
ts – Twilight value.
- Return type
int
Examples
>>> location = Location( ... name="canberra", ... lat=-35.293056, ... lon=149.126944, ... elevation_m=578, ... tz="+10:00", ... ) >>> location.twilight_state(datetime.fromisoformat("2021-07-28T12:00:00+10:00")) 4 >>> location.twilight_state(datetime.fromisoformat("2021-07-28T23:00:00+11:00")) 0
Timezone will be taken from self.tz if dt is timezone-naive.
>>> location.twilight_state(datetime.fromisoformat("2021-07-28T12:00:00")) 4
Skyfield provides mapping from these numbers to strings.
>>> almanac.TWILIGHTS[0] 'Night' >>> almanac.TWILIGHTS[1] 'Astronomical twilight' >>> almanac.TWILIGHTS[2] 'Nautical twilight' >>> almanac.TWILIGHTS[3] 'Civil twilight' >>> almanac.TWILIGHTS[4] 'Day'
- twilight_states(datetimes: Sequence[datetime.datetime]) numpy.ndarray¶
Like Location.twilight_state but operates on sequence of datetimes.
- Parameters
datetimes (Sequence[datetime]) – datetimes to evaluate. If timezone-naive, timezone will be taken from self.tz.
- Returns
ts – Twilight values.
- Return type
np.ndarray
Examples
>>> location = Location( ... name="canberra", ... lat=-35.293056, ... lon=149.126944, ... elevation_m=578, ... tz=timezone(timedelta(hours=10)), ... ) >>> datetimes = [ ... datetime.fromisoformat("2021-07-28T12:00:00+10:00"), ... datetime.fromisoformat("2021-07-28T23:00:00+11:00"), ... datetime.fromisoformat("2021-07-28T12:00:00"), ... ] >>> location.twilight_states(datetimes) array([4, 0, 4])
- class camfi.datamodel.weather.LocationWeatherStationCollector(*, locations: list, weather_stations: list, location_weather_station_mapping: dict)¶
Bases:
pydantic.main.BaseModelContains lists of Locations and Weather stations, and a mapping between them.
- Parameters
locations (list[Location]) – list of locations where cameras have been placed.
weather_stations (list[WeatherStation]) – list of weather stations.
location_weather_station_mapping (dict[str, str]) – A mapping between location names and weather_station names.
- get_sun_time_dataframe(days: dict) pandas.core.frame.DataFrame¶
Calls .get_sun_time_dataframe on each location in self.locations, and builds a DataFrame of sun times.
- Parameters
days (dict[str, Sequence[date]]) – Mapping from location name to sequences of dates which will become index for the dataframe.
- Returns
sun_df – DataFrame indexed by location and date, with columns “astronomical_twilight_start”, “nautical_twilight_start”, “civil_twilight_start”, “sunrise”, “sunset”, “nautical_twilight_end”, “civil_twilight_end”, “astronomical_twilight_end”.
- Return type
pd.DataFrame
- get_weather_dataframe() pandas.core.frame.DataFrame¶
Calls .load_dataframe() on each WeatherStation in self.weather_stations, and builds a DataFrame of weather data.
- Returns
weather_df – DataFrame with daily weather data, indexed by “weather_station” and “date”.
- Return type
pd.DataFrame
- get_weather_sun_dataframe(days: Optional[dict] = None) pandas.core.frame.DataFrame¶
Calls self.get_weather_dataframe and self.get_sun_time_dataframe, and merges the results into a single DataFrame.
- Parameters
days (Optional[dict[str, Sequence[date]]]) – Mapping from location name to sequences of dates which will become index for the dataframe. If None (default), this will be inferred from the weather dataframe.
- Returns
weather_sun_df – Merged weather and sun time DataFrame.
- Return type
pd.DataFrame
- class camfi.datamodel.weather.WeatherStation(*, location: camfi.datamodel.weather.Location, data_file: pydantic.types.FilePath)¶
Bases:
pydantic.main.BaseModelContains information on a weather station.
- Parameters
location (Location) – Location of weather station.
data_file (FilePath) – Path to csv file containing weather data from weather station.
- load_dataframe()¶
Loads weather data from self.data_file into a pd.DataFrame
- Returns
weather_df – DataFrame with daily weather data, indexed by “weather_station” and “date”.
- Return type
pd.DataFrame