Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add timeseries_activity_min_span filter argument & floating storage example. #162

Merged
merged 3 commits into from
Mar 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
51 changes: 51 additions & 0 deletions docs/examples/6_medium_sour_floating_storage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
Let's see how much Medium-Sour Crude is in long term floating storage.

The below script returns:

| | key | value | count |
|----:|:-------------------------|---------:|--------:|
| 0 | 2019-01-01T00:00:00.000Z | 7381 | 9 |
| 1 | 2019-01-02T00:00:00.000Z | 8127 | 23 |
| 2 | 2019-01-03T00:00:00.000Z | 2333 | 32 |
| 3 | 2019-01-04T00:00:00.000Z | 447759 | 43 |
| 4 | 2019-01-05T00:00:00.000Z | 7777144 | 4 |
...

"""
from datetime import datetime

from docs.utils import to_markdown
from vortexasdk import CargoTimeSeries, Geographies, Products

if __name__ == "__main__":
# Find Medium Sour ID
medium_sour = [
p.id
for p in Products().search(term="Medium-Sour").to_list()
if p.name == "Medium-Sour"
]
# Check we've only got one ID
assert len(medium_sour) == 1

# Query API
search_result = CargoTimeSeries().search(
# We're looking at daily storage levels
timeseries_frequency="day",
# We want 'b' for barrels here
timeseries_unit="b",
# We're only interested in storage of Medium-Sour Crude
filter_products=medium_sour,
# We're only included in cargo's that were in floating storage
filter_activity="storing_state",
# We're only interested in floating storage that lasted longer than 24 days
timeseries_activity_time_span_min=1000 * 60 * 60 * 24,
# Let's limit the search to 2019 storage events
filter_time_min=datetime(2019, 1, 1),
filter_time_max=datetime(2019, 12, 31),
)

# Convert search result to dataframe
df = search_result.to_df()

print(to_markdown(df.head()))
1 change: 1 addition & 0 deletions pydocmd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pages:
3 Crude movements from Saudi Arabia to India: examples/3_crude_from_saudi_arabia_to_india.md
4 Ballast Movements: examples/4_ballast_movements.md
5 Chinese Daily Crude Imports: examples/5_chinese_daily_imports.md
6 Floating Storage Medium Sour Crude: examples/6_medium_sour_floating_storage.md
theme:
name: readthedocs
collapse_navigation: true
Expand Down
16 changes: 16 additions & 0 deletions tests/endpoints/test_cargo_movements_real.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,22 @@ def test_search_single_filter_origin_name(self):

assert len(df) == 2

def test_search_filters_on_timeseries_max_activity(self):
df = (
CargoMovements()
.search(
filter_activity="storing_state",
filter_time_min=datetime(2019, 8, 29),
filter_time_max=datetime(2019, 8, 29, 0, 10),
timeseries_activity_time_span_min=1000 * 60 * 60 * 24 * 14,
timeseries_activity_time_span_max=1000 * 60 * 60 * 24 * 60,
)
.to_df()
.head(2)
)

assert len(df) == 2

def test_search_single_filter_owner_name(self):
df = (
CargoMovements()
Expand Down
16 changes: 16 additions & 0 deletions tests/endpoints/test_cargo_time_series_real.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,19 @@ def test_filter_geographies_and_products(self):
)

print(rotterdam_crude_timeseries.head())

def test_search_filters_on_timeseries_max_activity(self):
df = (
CargoTimeSeries()
.search(
filter_activity="storing_state",
filter_time_min=datetime(2019, 8, 1),
filter_time_max=datetime(2019, 8, 31),
timeseries_activity_time_span_min=1000 * 60 * 60 * 24 * 14,
timeseries_activity_time_span_max=1000 * 60 * 60 * 24 * 60,
)
.to_df()
.head(2)
)

assert len(df) == 2
16 changes: 16 additions & 0 deletions vortexasdk/endpoints/cargo_movements.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ def search(
filter_ship_to_ship_locations: Union[ID, List[ID]] = None,
filter_waypoints: Union[ID, List[ID]] = None,
disable_geographic_exclusion_rules: bool = None,
timeseries_activity_time_span_min: int = None,
timeseries_activity_time_span_max: int = None,
) -> CargoMovementsResult:
"""

Expand Down Expand Up @@ -79,6 +81,18 @@ def search(
disable_geographic_exclusion_rules: This controls a popular industry term "intra-movements" and determines
the filter behaviour for cargo leaving then entering the same geographic area.

timeseries_activity_time_span_min: The minimum amount of time in milliseconds accounted for in a time series
activity. Can be used to request long-term floating storage. For example, to only return floating storage
movements that occured for _more_ than 14 days enter
`timeseries_activity_time_span_min=1000 * 60 * 60 * 24 * 14` in conjunction with
`filter_activity='storing_state'`.

timeseries_activity_time_span_max: The maximum amount of time in milliseconds accounted for in a time series
activity. Can be used to request short-term floating storage. For example, to only return floating storage
movements that occured for _less_ than 14 days enter
`timeseries_activity_time_span_max=1000 * 60 * 60 * 24 * 14`
in conjunction with `filter_activity='storing_state'`.

# Returns
`CargoMovementsResult`, containing all the cargo movements matching the given search terms.

Expand Down Expand Up @@ -164,6 +178,8 @@ def search(
),
"filter_waypoints": convert_to_list(filter_waypoints),
"disable_geographic_exclusion_rules": disable_geographic_exclusion_rules,
"timeseries_activity_time_span_min": timeseries_activity_time_span_min,
"timeseries_activity_time_span_max": timeseries_activity_time_span_max,
}

return CargoMovementsResult(super().search(**params))
17 changes: 17 additions & 0 deletions vortexasdk/endpoints/cargo_timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ def search(
filter_ship_to_ship_locations: Union[str, List[str]] = None,
filter_waypoints: Union[str, List[str]] = None,
disable_geographic_exclusion_rules: bool = None,
timeseries_activity_time_span_min: int = None,
timeseries_activity_time_span_max: int = None,
) -> TimeSeriesResult:
"""

Expand All @@ -41,6 +43,7 @@ def search(

* _How many Crude/Condensate barrels have been imported into China each day over the last year?_
* _How many tonnes of Fuel Oil has company X exported from the United States each week over the last 2 years?_
* _How have long-term Medium-Sour floating storage levels changed over time?_

# Arguments
filter_activity: Movement activity on which to base the time filter. Must be one of ['loading_state',
Expand Down Expand Up @@ -85,6 +88,18 @@ def search(
disable_geographic_exclusion_rules: This controls a popular industry term "intra-movements" and determines
the filter behaviour for cargo leaving then entering the same geographic area.

timeseries_activity_time_span_min: The minimum amount of time in milliseconds accounted for in a time series
activity. Can be used to request long-term floating storage. For example, to only return floating storage
movements that occured for _more_ than 14 days enter
`timeseries_activity_time_span_min=1000 * 60 * 60 * 24 * 14` in conjunction with
`filter_activity='storing_state'`.

timeseries_activity_time_span_max: The maximum amount of time in milliseconds accounted for in a time series
activity. Can be used to request short-term floating storage. For example, to only return floating storage
movements that occured for _less_ than 14 days enter
`timeseries_activity_time_span_max=1000 * 60 * 60 * 24 * 14`
in conjunction with `filter_activity='storing_state'`.

# Returns
`TimeSeriesResult`

Expand Down Expand Up @@ -149,6 +164,8 @@ def search(
),
"filter_waypoints": convert_to_list(filter_waypoints),
"disable_geographic_exclusion_rules": disable_geographic_exclusion_rules,
"timeseries_activity_time_span_min": timeseries_activity_time_span_min,
"timeseries_activity_time_span_max": timeseries_activity_time_span_max,
}

return TimeSeriesResult(super().search(**params))
8 changes: 4 additions & 4 deletions vortexasdk/retry_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

# Inspired by https://www.peterbe.com/plog/best-practice-with-retries-with-requests
def _requests_retry_session(
retries=6,
backoff_factor=1,
status_forcelist=(500, 502, 504),
session=None,
retries=6,
backoff_factor=1,
status_forcelist=(500, 502, 504),
session=None,
) -> Session:
"""Instantiate a session with Retry backoff."""
session = session or Session()
Expand Down