finlab.plot
Data visualization module. plot_candles() draws candlestick charts from any price series, so it works for US stocks; plot_tw_stock_radar() compares any FinLab dataset across a portfolio. The other plot_tw_stock_* helpers read Taiwan datasets and are for the Taiwan market only.
Use Cases
- Draw stock candlestick charts with technical indicators
- Compare financial metrics across multiple stocks (radar charts)
- Display strategy performance statistics against a benchmark
- Analyze strategy holdings distribution (sunburst charts)
- Taiwan market only: market treemaps and P/E or P/B river charts
Quick Examples
Candlestick Chart with Technical Indicators
from finlab import data
from finlab.plot import plot_candles
data.set_market('us')
symbol = 'AAPL'
# Draw an Apple candlestick chart with the default Bollinger Bands and KD indicator
plot_candles(
symbol,
close=data.get('price:close')[symbol],
open_=data.get('price:open')[symbol],
high=data.get('price:high')[symbol],
low=data.get('price:low')[symbol],
volume=data.get('price:volume')[symbol],
recent_days=200,
).show()
Financial Metrics Radar Chart
from finlab import data
from finlab.plot import plot_tw_stock_radar
data.set_market('us')
# Compare the latest profitability ranks of three US stocks
plot_tw_stock_radar(
portfolio=['AAPL', 'MSFT', 'NVDA'],
feats=[
'us_ratios:gross_profit_margin',
'us_ratios:operating_profit_margin',
'us_ratios:net_profit_margin',
],
mode='bar_polar',
).show()
Detailed Guide
See Data Visualization Tutorial for: - Complete examples for all visualization tools - Custom chart styles and color schemes - Interactive chart usage tips - Exporting charts as images
API Reference
All plotting functions return a plotly.graph_objects.Figure; call .show() to display it or use plotly methods to customize it.
plot_candles()
def plot_candles(
symbol: str,
close: pd.Series,
open_: pd.Series,
high: pd.Series,
low: pd.Series,
volume: pd.Series,
recent_days: int = 250,
resample: str = 'D',
overlay_func: dict | list[dict] | None = None,
technical_func: list[dict] | dict | None = None,
) -> go.Figure
Draw a candlestick chart with volume, overlay lines on the price panel, and technical-indicator subplots, from price series you supply. Use it for US stocks or any custom data.
| Parameter | Type | Description |
|---|---|---|
symbol |
str |
Symbol shown in the title; also used to pick the symbol's column when an indicator returns a DataFrame. stock_id is accepted as an alias. |
close, open_, high, low, volume |
pd.Series |
Date-indexed price and volume series of one symbol. |
recent_days |
int |
Number of most recent rows to plot. |
resample |
str |
Candle period: 'D' daily, 'W' weekly, 'M' monthly. |
overlay_func |
dict or list[dict] |
Lines drawn on the price panel, {name: indicator}. Defaults to Bollinger Bands from data.indicator('BBANDS'). |
technical_func |
dict or list[dict] |
Indicator subplots; each dict is one subplot. Defaults to the KD indicator from data.indicator('STOCH'). |
An indicator can be a DataFrame (from data.indicator()), a Series, a NumPy array, a callable that receives the OHLCV DataFrame, or a TA-Lib function name such as 'RSI(timeperiod=14)'.
Usage Examples:
from finlab import data
from finlab.data import indicator
from finlab.plot import plot_candles
data.set_market('us')
symbol = 'MSFT'
prices = {
'close': data.get('price:close')[symbol],
'open_': data.get('price:open')[symbol],
'high': data.get('price:high')[symbol],
'low': data.get('price:low')[symbol],
'volume': data.get('price:volume')[symbol],
}
overlay_func = {
'ema_20': indicator('EMA', timeperiod=20),
'ema_60': indicator('EMA', timeperiod=60),
}
k, d = indicator('STOCH')
rsi = indicator('RSI')
technical_func = [{'K': k, 'D': d}, {'RSI': rsi}]
plot_candles(
symbol,
**prices,
recent_days=300,
overlay_func=overlay_func,
technical_func=technical_func,
).show()
data.indicator() uses unadjusted prices by default, so pass the unadjusted price:close/open/high/low series to keep the overlay lines aligned with the candles.
Notes
- Requires the
plotlypackage:pip install plotly - TA-Lib function names require the
ta-libpackage - Call
.show()to display the chart in Jupyter Notebook
plot_tw_stock_candles()
Taiwan market only
This helper reads Taiwan price datasets. For US stocks, use plot_candles() with US price series.
def plot_tw_stock_candles(
symbol: str,
recent_days: int = 400,
adjust_price: bool = False,
resample: str = 'D',
overlay_func: dict | list[dict] | None = None,
technical_func: list[dict] | dict | None = None,
) -> go.Figure
Draw a candlestick chart for a Taiwan stock. It loads the stock's prices and volume, then calls plot_candles().
| Parameter | Type | Description |
|---|---|---|
symbol |
str |
Taiwan stock code. stock_id is accepted as an alias. |
recent_days |
int |
Number of most recent trading days to plot. |
adjust_price |
bool |
Use adjusted prices. |
resample |
str |
Candle period: 'D' daily, 'W' weekly, 'M' monthly. |
overlay_func |
dict or list[dict] |
Lines on the price panel. Defaults to Bollinger Bands. |
technical_func |
dict or list[dict] |
Indicator subplots. Defaults to one KD subplot. |
Returns: plotly.graph_objects.Figure, the candlestick chart.
plot_tw_stock_radar()
def plot_tw_stock_radar(
portfolio: list[str],
feats: list[str] | None = None,
mode: str = 'line_polar',
line_polar_fill: str | None = None,
period: str | None = None,
cut_bins: int = 10,
title: str | None = None,
custom_data: pd.DataFrame | None = None,
) -> go.Figure | None
Compare the rank levels of several metrics across a portfolio. Each metric is ranked across all symbols at the chosen row and cut into cut_bins levels; missing values show no level.
| Parameter | Type | Description |
|---|---|---|
portfolio |
list[str] |
Symbols to compare, e.g. ['AAPL', 'MSFT']. |
feats |
list[str] |
FinLab dataset keys to compare. The default is 18 Taiwan financial metrics, so pass feats for other markets. Axis names are the part of each key after :. |
mode |
str |
'line_polar', 'bar_polar' or 'scatter_polar' (see plotly express). |
line_polar_fill |
str |
Fill for 'line_polar': None, 'toself' (close each trace into a shape) or 'tonext' (fill between consecutive traces). |
period |
str |
Row label of the datasets to compare. Defaults to the latest row. |
cut_bins |
int |
Number of rank levels. |
title |
str |
Chart title. |
custom_data |
pd.DataFrame |
Your own rank levels: index of symbols, one column per metric. Replaces feats. |
Returns: plotly.graph_objects.Figure, or None (with an error log) when none of the symbols has data.
Usage Examples:
from finlab import data
from finlab.plot import plot_tw_stock_radar
data.set_market('us')
# Example 1: Compare profitability and leverage of four large caps
plot_tw_stock_radar(
portfolio=['AAPL', 'MSFT', 'NVDA', 'AMZN'],
feats=[
'us_ratios:gross_profit_margin',
'us_ratios:operating_profit_margin',
'us_ratios:net_profit_margin',
'us_ratios:debt_to_assets_ratio',
],
mode='bar_polar', # Bar polar chart
).show()
# Example 2: Show where one stock ranks on each metric
plot_tw_stock_radar(
portfolio=['NVDA'],
feats=[
'us_ratios:gross_profit_margin',
'us_ratios:operating_profit_margin',
'us_ratios:net_profit_margin',
'us_ratios:current_ratio',
'us_ratios:debt_to_assets_ratio',
],
mode='line_polar', # Line polar chart
line_polar_fill='toself',
cut_bins=8, # Split metric values into 8 levels
).show()
us_ratios:* keys hold recent daily snapshots, which suits this latest-value comparison.
mode Parameter Options
- 'bar_polar': Bar polar chart (recommended for comparing 2-5 stocks)
- 'line_polar': Line polar chart (suitable for single stock multi-metric display)
- 'scatter_polar': Scatter polar chart (suitable for viewing raw data points)
plot_tw_stock_treemap()
Taiwan market only
The treemap groups stocks by Taiwan market and industry using Taiwan company data.
def plot_tw_stock_treemap(
start: str | None = None,
end: str | None = None,
area_ind: str = 'market_value',
item: str = 'return_ratio',
clip: tuple[float, float] | None = None,
color_continuous_scale: str = 'Temps',
treemap_data: pd.DataFrame | None = None,
) -> go.Figure | None
Draw a nested treemap of Taiwan stocks grouped by market and industry. Block area and color show two metrics at once.
| Parameter | Type | Description |
|---|---|---|
start, end |
str |
Date range, e.g. '2024-01-02' and '2024-01-31'. |
area_ind |
str |
Metric for block area: 'market_value' or 'turnover' (trading value). |
item |
str |
Metric for block color: 'return_ratio' (return between start and end) or a FinLab dataset key, which shows its latest value in the range. |
clip |
tuple |
Clip item to (lower, upper) so extreme values do not flatten the color scale (see DataFrame.clip). |
color_continuous_scale |
str |
Name of a plotly color scale. |
treemap_data |
pd.DataFrame |
Custom data in the format returned by create_treemap_data(). |
Returns: plotly.graph_objects.Figure, or None when the data or area_ind is unavailable.
Usage Example (Taiwan market):
from finlab.plot import plot_tw_stock_treemap
# Block area: trading value; color: return over the period
plot_tw_stock_treemap(
start='2024-01-02',
end='2024-01-31',
area_ind='turnover',
item='return_ratio',
).show()
create_treemap_data()
Taiwan market only
def create_treemap_data(
start: str,
end: str,
item: str = 'return_ratio',
clip: tuple[float, float] | None = None,
) -> pd.DataFrame | None
Build the data behind plot_tw_stock_treemap(): one row per Taiwan stock with symbol, close, turnover, return_ratio, category, market, market_value and country, plus a column for item when it is a dataset key. Add your own columns, then pass the result as plot_tw_stock_treemap(treemap_data=...).
| Parameter | Type | Description |
|---|---|---|
start, end |
str |
Date range. |
item |
str |
'return_ratio' or a FinLab dataset key whose latest value in the range is added. |
clip |
tuple |
Clip item to (lower, upper). |
Returns: pd.DataFrame, or None if item has no data in the range.
plot_tw_stock_river()
Taiwan market only
The river chart reads Taiwan P/E and P/B datasets.
Draw a P/E or P/B river chart for a Taiwan stock: the bands are the price implied by evenly spaced multiples between the stock's lowest and highest P/E (or P/B) in the period, and the line is the closing price, showing where the current valuation sits.
| Parameter | Type | Description |
|---|---|---|
symbol |
str |
Taiwan stock code (pass the stock you want; the default is a sample code). stock_id is accepted as an alias. |
start, end |
str |
Date range, e.g. '2020-01-02' and '2024-01-05'. Default: all data. |
mode |
str |
'pe' (price-to-earnings) or 'pb' (price-to-book). |
split_range |
int |
Number of bands. Default 8. |
Returns: plotly.graph_objects.Figure, or None when the mode or symbol is invalid.
StrategySunburst
Taiwan market only. Sunburst chart of the holdings of your strategies uploaded to FinLab cloud, for monitoring several strategies at once. Requires finlab.login(). Holdings are grouped by Taiwan industry and labeled for the Taiwan site; holdings in other markets all fall under other_securities, so it is not useful for U.S. strategies.
get_strategy_df()
Return the combined holdings after applying strategy weights.
| Parameter | Type | Description |
|---|---|---|
select_strategy |
dict |
Strategy names and their capital weights, e.g. {'US Momentum': 0.6, 'Quality Value': 0.4}. Default: all strategies, equally weighted. |
Returns: pd.DataFrame of holdings, or None when you have no strategies.
plot()
def plot(
self,
select_strategy: dict[str, float] | None = None,
path: list[str] | None = None,
color_continuous_scale: str = 'RdBu_r',
) -> go.Figure | None
| Parameter | Type | Description |
|---|---|---|
select_strategy |
dict |
Strategy names and weights, as in get_strategy_df(). |
path |
list[str] |
Rings from inside to outside. Default ['s_name', 'market', 'category', 'stock_id']; ['market', 'category', 'stock_id', 's_name'] shows which strategies hold each position. |
color_continuous_scale |
str |
Name of a plotly color scale. |
Returns: plotly.graph_objects.Figure, the holdings sunburst.
StrategyReturnStats
class StrategyReturnStats(
start_date: str,
end_date: str,
strategy_names: list[str] | None = None,
benchmark_return: pd.Series | None = None,
)
Compare the returns of your uploaded strategies with a benchmark over a period. Requires finlab.login().
| Parameter | Type | Description |
|---|---|---|
start_date |
str |
Start date of the return calculation. |
end_date |
str |
End date of the return calculation. |
strategy_names |
list[str] |
Names of your own strategies to include. Default: all uploaded strategies. |
benchmark_return |
pd.Series |
Benchmark price series. The default is the Taiwan weighted return index, so pass one for US strategies. |
| Method | Returns |
|---|---|
get_benchmark_return() |
The benchmark series between start_date and end_date |
plot_strategy_last_return() |
Horizontal bar chart of each strategy's return over the period, with the benchmark and strategy mean marked |
plot_strategy_creturn() |
Cumulative return of each strategy over the period, with the benchmark |
from finlab import data
from finlab.plot import StrategyReturnStats
sp500 = data.get('world_index:adj_close')['^GSPC']
stats = StrategyReturnStats('2025-01-01', '2025-12-31', benchmark_return=sp500)
stats.plot_strategy_last_return().show()
stats.plot_strategy_creturn().show()
FAQ
The snippets below reuse symbol and prices from the plot_candles() example.
Q: Charts are not displaying, what should I do?
# Cause 1: Forgot to call .show()
fig = plot_candles(symbol, **prices)
# Not displayed
fig = plot_candles(symbol, **prices)
fig.show() # Correct
# Cause 2: Missing plotly package
# Solution: pip install plotly
# Cause 3: Jupyter Notebook environment issue
# Add at the beginning of the notebook:
import plotly.io as pio
pio.renderers.default = 'notebook'
Q: How do I export charts as images?
fig = plot_candles(symbol, **prices, recent_days=200)
# Export as HTML (interactive)
fig.write_html('chart.html')
For a PNG, install Kaleido (pip install kaleido, which also needs a Chrome browser) and call fig.write_image('chart.png', width=1200, height=800).
Q: How do I customize chart styles?
fig = plot_candles(symbol, **prices, recent_days=200)
# Change title
fig.update_layout(title='Apple Price Trend')
# Change color theme
fig.update_layout(template='plotly_dark') # Dark theme
# Adjust chart size
fig.update_layout(width=1200, height=600)
fig.show()
Q: Which datasets can the radar chart compare?
Any dataset key whose rows hold one value per symbol works, such as the us_ratios:* and us_key_metrics:* snapshot fields:
Q: Radar chart shows large value differences, what can I do?
Values are already converted to rank levels, so metrics with different units are comparable. Use cut_bins to change how many levels there are:
plot_tw_stock_radar(
portfolio=['AAPL', 'MSFT'],
feats=[
'us_ratios:gross_profit_margin',
'us_key_metrics:return_on_equity',
'us_ratios:debt_to_equity_ratio',
],
cut_bins=10, # Split all metrics into 10 levels
).show()
Resources
- Data Visualization Tutorial - Jupyter Notebook interactive examples
- Plotly Official Documentation - Advanced customization techniques
- Backtest Report Visualization - Built-in charts in Report object