-
Notifications
You must be signed in to change notification settings - Fork 366
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
New standalone example showing blueprint configuration of some stock #5603
Merged
Merged
Changes from 14 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
b63f954
New standalone example showing blueprint configuration of some stock …
jleibs 67c0b80
Support blueprint without a root container when using auto
jleibs eb3bbbb
More linting
jleibs 9ef108b
Fix readme
jleibs d8f420c
Make usage of *args optional for containers
jleibs 9b1d4e5
Don't use argument-unpacking for our container declarations
jleibs 05e6515
An introductory blueprint showing container usage
jleibs 75add53
Add to top-level requirements
jleibs 4563b48
Lint and vs code disagree on sort order
jleibs 295ba50
Make default Y axis plot area smaller
emilk cadd7cc
Make python script executable
emilk c0a91ba
Fixes from PR
jleibs f259c50
Merge branch 'main' into jleibs/blueprint_stocks
jleibs 72010f1
Merge remote-tracking branch 'origin/jleibs/blueprint_stocks' into jl…
jleibs 4ee7d32
one more stupid sort inconsistency
jleibs 588e1ab
1px thumbnail error
jleibs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<!--[metadata] | ||
title = "Stock Charts" | ||
description = "Uses stock data as an example of how to leverage Rerun blueprints to control the layout and presentation of the viewer." | ||
tags = ["time-series", "blueprint"] | ||
thumbnail = "https://static.rerun.io/blueprint_stocks/8bfe6f16963acdceb2debb9de9a206dc2eb9b280/480w.png" | ||
thumbnail_dimensions = [480, 271] | ||
--> | ||
|
||
<picture> | ||
<img src="https://static.rerun.io/blueprint_stocks/8bfe6f16963acdceb2debb9de9a206dc2eb9b280/full.png" alt=""> | ||
<source media="(max-width: 480px)" srcset="https://static.rerun.io/blueprint_stocks/8bfe6f16963acdceb2debb9de9a206dc2eb9b280/480w.png"> | ||
<source media="(max-width: 768px)" srcset="https://static.rerun.io/blueprint_stocks/8bfe6f16963acdceb2debb9de9a206dc2eb9b280/768w.png"> | ||
<source media="(max-width: 1024px)" srcset="https://static.rerun.io/blueprint_stocks/8bfe6f16963acdceb2debb9de9a206dc2eb9b280/1024w.png"> | ||
<source media="(max-width: 1200px)" srcset="https://static.rerun.io/blueprint_stocks/8bfe6f16963acdceb2debb9de9a206dc2eb9b280/1200w.png"> | ||
</picture> | ||
|
||
This example fetches the last 5 days of stock data for a few different stocks. | ||
We show how Rerun blueprints can then be used to present many different views of the same data. | ||
|
||
```bash | ||
pip install -r examples/python/blueprint_stocks/requirements.txt | ||
python examples/python/blueprint_stocks/blueprint_main.py | ||
``` | ||
|
||
The different blueprints can be explored using the `--blueprint` flag. For example: | ||
|
||
``` | ||
python examples/python/blueprint_stocks/main.py --blueprint=one-stock | ||
``` | ||
|
||
Available choices are: | ||
|
||
- `auto`: Reset the blueprint to the auto layout used by the viewer. | ||
- `one-stock`: Uses a filter to show only a single chart. | ||
- `one-stock-with-info`: Uses a container to layout a chart and its info document | ||
- `one-stock-no-peaks`: Uses a filter to additionally remove some of the data from the chart. | ||
- `compare-two`: Adds data from multiple sources to a single chart. | ||
- `grid`: Shows all the charts in a grid layout. | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
#!/usr/bin/env python3 | ||
""" | ||
A simple application that fetches stock data from Yahoo Finance and visualizes it using the Rerun SDK. | ||
|
||
The main focus of this example is using blueprints to control how the data is displayed in the viewer. | ||
""" | ||
from __future__ import annotations | ||
|
||
import argparse | ||
import datetime as dt | ||
from typing import Any | ||
|
||
import humanize | ||
import pytz | ||
import rerun as rr | ||
import rerun.blueprint as rrb | ||
import yfinance as yf | ||
|
||
################################################################################ | ||
# Helper functions to create blueprints | ||
################################################################################ | ||
|
||
|
||
def auto_blueprint() -> rrb.ViewportLike: | ||
"""A blueprint enabling auto space views, which matches the application default.""" | ||
return rrb.Viewport(auto_space_views=True, auto_layout=True) | ||
|
||
|
||
def one_stock(symbol: str) -> rrb.ViewportLike: | ||
"""Create a blueprint showing a single stock.""" | ||
return rrb.TimeSeriesView(name=f"{symbol}", origin=f"/stocks/{symbol}") | ||
|
||
|
||
def one_stock_with_info(symbol: str) -> rrb.ViewportLike: | ||
"""Create a blueprint showing a single stock with its info arranged vertically.""" | ||
return rrb.Vertical( | ||
rrb.TextDocumentView(name=f"{symbol}", origin=f"/stocks/{symbol}/info"), | ||
rrb.TimeSeriesView(name=f"{symbol}", origin=f"/stocks/{symbol}"), | ||
row_shares=[1, 4], | ||
) | ||
|
||
|
||
def compare_two(symbol1: str, symbol2: str, day: Any) -> rrb.ViewportLike: | ||
"""Create a blueprint comparing 2 stocks for a single day.""" | ||
return rrb.TimeSeriesView( | ||
name=f"{symbol1} vs {symbol2} ({day})", | ||
contents=[ | ||
f"+ /stocks/{symbol1}/{day}", | ||
f"+ /stocks/{symbol2}/{day}", | ||
], | ||
) | ||
|
||
|
||
def one_stock_no_peaks(symbol: str) -> rrb.ViewportLike: | ||
""" | ||
Create a blueprint showing a single stock without annotated peaks. | ||
|
||
This uses an exclusion pattern to hide the peaks. | ||
""" | ||
return rrb.TimeSeriesView( | ||
name=f"{symbol}", | ||
origin=f"/stocks/{symbol}", | ||
contents=[ | ||
"+ $origin/**", | ||
"- $origin/peaks/**", | ||
], | ||
) | ||
|
||
|
||
def stock_grid(symbols: list[str], dates: list[Any]) -> rrb.ViewportLike: | ||
"""Create a grid of stocks and their time series over all days.""" | ||
return rrb.Vertical( | ||
contents=[ | ||
rrb.Horizontal( | ||
contents=[rrb.TextDocumentView(name=f"{symbol}", origin=f"/stocks/{symbol}/info")] | ||
+ [rrb.TimeSeriesView(name=f"{day}", origin=f"/stocks/{symbol}/{day}") for day in dates], | ||
) | ||
for symbol in symbols | ||
] | ||
) | ||
|
||
|
||
def hide_panels(viewport: rrb.ViewportLike) -> rrb.BlueprintLike: | ||
"""Wrap a viewport in a blueprint that hides the time and selection panels.""" | ||
return rrb.Blueprint( | ||
viewport, | ||
rrb.TimePanel(expanded=False), | ||
rrb.SelectionPanel(expanded=False), | ||
) | ||
|
||
|
||
################################################################################ | ||
# Helper functions for styling | ||
################################################################################ | ||
|
||
brand_colors = { | ||
"AAPL": 0xA2AAADFF, | ||
"AMZN": 0xFF9900FF, | ||
"GOOGL": 0x34A853FF, | ||
"META": 0x0081FBFF, | ||
"MSFT": 0xF14F21FF, | ||
} | ||
|
||
|
||
def style_plot(symbol: str) -> rr.SeriesLine: | ||
return rr.SeriesLine( | ||
color=brand_colors[symbol], | ||
name=symbol, | ||
) | ||
|
||
|
||
def style_peak(symbol: str) -> rr.SeriesPoint: | ||
return rr.SeriesPoint( | ||
color=0xFF0000FF, | ||
name=f"{symbol} (peak)", | ||
marker="Up", | ||
) | ||
|
||
|
||
################################################################################ | ||
# Main script | ||
################################################################################ | ||
|
||
|
||
def main() -> None: | ||
parser = argparse.ArgumentParser(description="Visualize stock data using the Rerun SDK") | ||
parser.add_argument( | ||
"--blueprint", | ||
choices=["auto", "one-stock", "one-stock-with-info", "compare-two", "one-stock-no-peaks", "grid"], | ||
default="grid", | ||
help="Select the blueprint to use", | ||
) | ||
parser.add_argument( | ||
"--show_panels", | ||
action="store_true", | ||
help="Show the time and selection panels", | ||
) | ||
|
||
rr.script_add_args(parser) | ||
args = parser.parse_args() | ||
|
||
et_timezone = pytz.timezone("America/New_York") | ||
current_date = dt.datetime.now(et_timezone).date() | ||
symbols = ["AAPL", "AMZN", "GOOGL", "META", "MSFT"] | ||
dates = list(filter(lambda x: x.weekday() < 5, [current_date - dt.timedelta(days=i) for i in range(7, 0, -1)])) | ||
|
||
blueprint: rrb.BlueprintLike | ||
|
||
if args.blueprint == "auto": | ||
blueprint = auto_blueprint() | ||
elif args.blueprint == "one-stock": | ||
blueprint = one_stock("AAPL") | ||
elif args.blueprint == "one-stock-with-info": | ||
blueprint = one_stock_with_info("AMZN") | ||
elif args.blueprint == "one-stock-no-peaks": | ||
blueprint = one_stock_no_peaks("GOOGL") | ||
elif args.blueprint == "compare-two": | ||
blueprint = compare_two("META", "MSFT", dates[-1]) | ||
elif args.blueprint == "grid": | ||
blueprint = stock_grid(symbols, dates) | ||
else: | ||
raise ValueError(f"Unknown blueprint: {args.blueprint}") | ||
|
||
if not args.show_panels: | ||
blueprint = hide_panels(blueprint) | ||
|
||
rr.init("rerun_example_blueprint_stocks", spawn=True, blueprint=blueprint) | ||
|
||
# In a future blueprint release, this can move into the blueprint as well | ||
for symbol in symbols: | ||
for day in dates: | ||
rr.log(f"stocks/{symbol}/{day}", style_plot(symbol), timeless=True) | ||
rr.log(f"stocks/{symbol}/peaks/{day}", style_peak(symbol), timeless=True) | ||
|
||
for symbol in symbols: | ||
stock = yf.Ticker(symbol) | ||
|
||
name = stock.info["shortName"] | ||
industry = stock.info["industry"] | ||
marketCap = humanize.intword(stock.info["marketCap"]) | ||
revenue = humanize.intword(stock.info["totalRevenue"]) | ||
|
||
info_md = ( | ||
f"- **Name**: {name}\n" | ||
f"- **Industry**: {industry}\n" | ||
f"- **Market cap**: ${marketCap}\n" | ||
f"- **Total Revenue**: ${revenue}\n" | ||
) | ||
|
||
rr.log( | ||
f"stocks/{symbol}/info", | ||
rr.TextDocument(info_md, media_type=rr.MediaType.MARKDOWN), | ||
timeless=True, | ||
) | ||
|
||
for day in dates: | ||
open_time = dt.datetime.combine(day, dt.time(9, 30)) | ||
close_time = dt.datetime.combine(day, dt.time(16, 00)) | ||
|
||
hist = stock.history(start=open_time, end=close_time, interval="5m") | ||
|
||
hist.index = hist.index - et_timezone.localize(open_time) | ||
peak = hist.High.idxmax() | ||
|
||
for row in hist.itertuples(): | ||
rr.set_time_seconds("time", row.Index.total_seconds()) | ||
rr.log(f"stocks/{symbol}/{day}", rr.Scalar(row.High)) | ||
if row.Index == peak: | ||
rr.log(f"stocks/{symbol}/peaks/{day}", rr.Scalar(row.High)) | ||
|
||
rr.script_teardown(args) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
humanize | ||
rerun-sdk | ||
yfinance |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we have to give them different application ids each: Right now it's quite confusing when you just leave the viewer open and try to execute the script several times with different blueprints :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
discussed on slack, no immediate action to take. We know that application id changing is more wrong. Comes down to figuring out the blueprint lifecycle