Fast Bar Charts¶
The fast_bar() method creates bar-like visualizations using stacked areas. This renders much faster than actual bar charts for large datasets because it uses a single polygon per trace instead of individual rectangles.
In [1]:
Copied!
import numpy as np
import xarray as xr
from xarray_plotly import config, xpx
config.notebook()
import numpy as np
import xarray as xr
from xarray_plotly import config, xpx
config.notebook()
Basic Example¶
In [2]:
Copied!
# Quarterly revenue data by product and region
np.random.seed(42)
da = xr.DataArray(
np.random.rand(4, 3, 2) * 100 + 50,
dims=["quarter", "product", "region"],
coords={
"quarter": ["Q1", "Q2", "Q3", "Q4"],
"product": ["Widgets", "Gadgets", "Gizmos"],
"region": ["North", "South"],
},
name="revenue",
)
xpx(da).fast_bar()
# Quarterly revenue data by product and region
np.random.seed(42)
da = xr.DataArray(
np.random.rand(4, 3, 2) * 100 + 50,
dims=["quarter", "product", "region"],
coords={
"quarter": ["Q1", "Q2", "Q3", "Q4"],
"product": ["Widgets", "Gadgets", "Gizmos"],
"region": ["North", "South"],
},
name="revenue",
)
xpx(da).fast_bar()
In [3]:
Copied!
# Comparison with regular bar()
xpx(da).bar()
# Comparison with regular bar()
xpx(da).bar()
With Faceting¶
In [4]:
Copied!
xpx(da).fast_bar(facet_col="region")
xpx(da).fast_bar(facet_col="region")
With Animation¶
In [5]:
Copied!
# Multi-year data for animation
np.random.seed(123)
da_anim = xr.DataArray(
np.random.rand(4, 3, 5) * 100 + 20,
dims=["quarter", "product", "year"],
coords={
"quarter": ["Q1", "Q2", "Q3", "Q4"],
"product": ["Widgets", "Gadgets", "Gizmos"],
"year": [2020, 2021, 2022, 2023, 2024],
},
name="revenue",
)
xpx(da_anim).fast_bar(animation_frame="year")
# Multi-year data for animation
np.random.seed(123)
da_anim = xr.DataArray(
np.random.rand(4, 3, 5) * 100 + 20,
dims=["quarter", "product", "year"],
coords={
"quarter": ["Q1", "Q2", "Q3", "Q4"],
"product": ["Widgets", "Gadgets", "Gizmos"],
"year": [2020, 2021, 2022, 2023, 2024],
},
name="revenue",
)
xpx(da_anim).fast_bar(animation_frame="year")
Faceting + Animation¶
In [6]:
Copied!
# 4D data: quarter x product x region x year
np.random.seed(456)
da_4d = xr.DataArray(
np.random.rand(4, 3, 2, 4) * 80 + 30,
dims=["quarter", "product", "region", "year"],
coords={
"quarter": ["Q1", "Q2", "Q3", "Q4"],
"product": ["Widgets", "Gadgets", "Gizmos"],
"region": ["North", "South"],
"year": [2021, 2022, 2023, 2024],
},
name="revenue",
)
xpx(da_4d).fast_bar(facet_col="region", animation_frame="year")
# 4D data: quarter x product x region x year
np.random.seed(456)
da_4d = xr.DataArray(
np.random.rand(4, 3, 2, 4) * 80 + 30,
dims=["quarter", "product", "region", "year"],
coords={
"quarter": ["Q1", "Q2", "Q3", "Q4"],
"product": ["Widgets", "Gadgets", "Gizmos"],
"region": ["North", "South"],
"year": [2021, 2022, 2023, 2024],
},
name="revenue",
)
xpx(da_4d).fast_bar(facet_col="region", animation_frame="year")
Positive and Negative Values¶
fast_bar() classifies each trace by its values:
- Purely positive → stacks upward
- Purely negative → stacks downward
- Mixed signs → warning + dashed line (use
bar()instead)
In [7]:
Copied!
# Profit (positive) and Loss (negative) - stacks correctly
np.random.seed(789)
da_split = xr.DataArray(
np.column_stack(
[
np.random.rand(6) * 80 + 20, # Revenue: positive
-np.random.rand(6) * 50 - 10, # Costs: negative
]
),
dims=["month", "category"],
coords={
"month": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
"category": ["Revenue", "Costs"],
},
name="financials",
)
xpx(da_split).fast_bar()
# Profit (positive) and Loss (negative) - stacks correctly
np.random.seed(789)
da_split = xr.DataArray(
np.column_stack(
[
np.random.rand(6) * 80 + 20, # Revenue: positive
-np.random.rand(6) * 50 - 10, # Costs: negative
]
),
dims=["month", "category"],
coords={
"month": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
"category": ["Revenue", "Costs"],
},
name="financials",
)
xpx(da_split).fast_bar()
In [8]:
Copied!
# With animation - sign classification is consistent across frames
np.random.seed(321)
da_split_anim = xr.DataArray(
np.stack(
[
np.column_stack([np.random.rand(6) * 80 + 20, -np.random.rand(6) * 50 - 10])
for _ in range(4)
],
axis=-1,
),
dims=["month", "category", "year"],
coords={
"month": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
"category": ["Revenue", "Costs"],
"year": [2021, 2022, 2023, 2024],
},
name="financials",
)
xpx(da_split_anim).fast_bar(animation_frame="year")
# With animation - sign classification is consistent across frames
np.random.seed(321)
da_split_anim = xr.DataArray(
np.stack(
[
np.column_stack([np.random.rand(6) * 80 + 20, -np.random.rand(6) * 50 - 10])
for _ in range(4)
],
axis=-1,
),
dims=["month", "category", "year"],
coords={
"month": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
"category": ["Revenue", "Costs"],
"year": [2021, 2022, 2023, 2024],
},
name="financials",
)
xpx(da_split_anim).fast_bar(animation_frame="year")
Mixed Sign Warning¶
When a trace has both positive and negative values, fast_bar() shows a warning and displays it as a dashed line:
In [9]:
Copied!
# Both columns have mixed signs - triggers warning
da_mixed = xr.DataArray(
np.array(
[
[50, -30],
[-40, 60],
[30, -50],
[-20, 40],
]
),
dims=["month", "category"],
coords={
"month": ["Jan", "Feb", "Mar", "Apr"],
"category": ["A", "B"],
},
)
# This will show a warning
xpx(da_mixed).fast_bar()
# Both columns have mixed signs - triggers warning
da_mixed = xr.DataArray(
np.array(
[
[50, -30],
[-40, 60],
[30, -50],
[-20, 40],
]
),
dims=["month", "category"],
coords={
"month": ["Jan", "Feb", "Mar", "Apr"],
"category": ["A", "B"],
},
)
# This will show a warning
xpx(da_mixed).fast_bar()
/home/runner/work/xarray_plotly/xarray_plotly/xarray_plotly/accessor.py:199: UserWarning: fast_bar: traces ['A', 'B'] have mixed positive/negative values and cannot be stacked. They are shown as dashed lines. Consider using bar() for proper stacking of mixed data.
In [10]:
Copied!
# For mixed data, use bar() instead
xpx(da_mixed).bar()
# For mixed data, use bar() instead
xpx(da_mixed).bar()
When to Use¶
| Method | Use when... |
|---|---|
fast_bar() |
Large datasets, animations, performance matters, data is same-sign per trace |
bar() |
Need grouped bars, pattern fills, or have mixed +/- values per trace |
area() |
Want smooth continuous fills |