Skip to content

Commit

Permalink
Merge pull request #162 from VorTECHsa/timeseries-min
Browse files Browse the repository at this point in the history
Add timeseries_activity_min_span filter argument & floating storage example.
  • Loading branch information
KitBurgess committed Mar 9, 2020
2 parents f18bcf7 + 39a3e9b commit 404ab3a
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 4 deletions.
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

0 comments on commit 404ab3a

Please sign in to comment.