Skip to content

Commit

Permalink
Add timeseries filtering example to illustrate subsetting of columns …
Browse files Browse the repository at this point in the history
…from selector values (#3357)

* Add timeseries filtering example to illustrate selection of columns

* Change to a more version forgiving approach for dropping columns

* Make column renaming compatible with more pandas versions
  • Loading branch information
joelostblom authored Mar 13, 2024
1 parent 32443be commit 89b717c
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 0 deletions.
82 changes: 82 additions & 0 deletions tests/examples_arguments_syntax/interactive_column_selection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"""
Interactive Selection of Columns
================================
This example shows how columns can be selected interactively
by accessing the values from selector widgets,
and then compute the difference of the selected columns.
It also illustrates how to use `indexof` to filter
columns based on active selection values.
"""
# category: interactive charts

import pandas as pd
import numpy as np
import altair as alt


# Create timeseries data
rng = np.random.default_rng(905)
ex_ts = pd.DataFrame(
rng.random((10, 4)),
columns=['a', 'b', 'c', 'd'],
).assign(
date=pd.date_range(
start=pd.to_datetime('2022-02-22')-pd.Timedelta(9, unit='D'),
end=pd.to_datetime('2022-02-22')).strftime('%Y-%m-%d'),
)

# Create heatmap with selection
select_x = alt.selection_point(fields=['level_0'], name='select_x', value='b')
select_y = alt.selection_point(fields=['level_1'], name='select_y', value='d')
heatmap = alt.Chart(
ex_ts.drop(columns='date').corr().stack().reset_index().rename(columns={0: 'correlation'}),
title='Click a tile to compare timeseries',
height=250,
width=250,
).mark_rect().encode(
alt.X('level_0', title=None),
alt.Y('level_1', title=None),
alt.Color('correlation', scale=alt.Scale(domain=[-1, 1], scheme='blueorange')),
opacity=alt.condition(select_x & select_y, alt.value(1), alt.value(0.4))
).add_params(
select_x, select_y
)

# Create chart with individual lines/timeseries
base = alt.Chart(
ex_ts.melt(
id_vars='date',
var_name='category',
value_name='value',
),
height=100,
width=300,
title='Individual timeseries',
)
lines = base.transform_filter(
# If the category is not in the selected values, the returned index is -1
'indexof(datum.category, select_x.level_0) !== -1'
'| indexof(datum.category, select_y.level_1) !== -1'
).mark_line().encode(
alt.X('date:T', axis=alt.Axis(labels=False), title=None),
alt.Y('value', scale=alt.Scale(domain=(0, 1))),
alt.Color('category', legend=alt.Legend(orient='top', offset=-20), title=None)
)

# Create chart with difference between lines/timeseries
dynamic_title = alt.Title(alt.expr(f'"Difference " + {select_x.name}.level_0 + " - " + {select_y.name}.level_1'))
# We pivot transform to get each category as a column
lines_diff = base.transform_pivot(
'category', 'value', groupby=['date']
# In the calculate transform we use the values from the selection to subset the columns to substract
).transform_calculate(
difference = f'datum[{select_x.name}.level_0] - datum[{select_y.name}.level_1]'
).mark_line(color='grey').encode(
alt.X('date:T', axis=alt.Axis(format='%Y-%m-%d'), title=None),
alt.Y('difference:Q', scale=alt.Scale(domain=(-1, 1))),
).properties(
title=dynamic_title
)

# Layout the charts
(lines & lines_diff) | heatmap
80 changes: 80 additions & 0 deletions tests/examples_methods_syntax/interactive_column_selection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""
Interactive Selection of Columns
================================
This example shows how columns can be selected interactively
by accessing the values from selector widgets,
and then compute the difference of the selected columns.
It also illustrates how to use `indexof` to filter
columns based on active selection values.
"""
import pandas as pd
import numpy as np
import altair as alt


# Create timeseries data
rng = np.random.default_rng(905)
ex_ts = pd.DataFrame(
rng.random((10, 4)),
columns=['a', 'b', 'c', 'd'],
).assign(
date=pd.date_range(
start=pd.to_datetime('2022-02-22')-pd.Timedelta(9, unit='D'),
end=pd.to_datetime('2022-02-22')).strftime('%Y-%m-%d'),
)

# Create heatmap with selection
select_x = alt.selection_point(fields=['level_0'], name='select_x', value='b')
select_y = alt.selection_point(fields=['level_1'], name='select_y', value='d')
heatmap = alt.Chart(
ex_ts.drop(columns='date').corr().stack().reset_index().rename(columns={0: 'correlation'}),
title='Click a tile to compare timeseries',
height=250,
width=250,
).mark_rect().encode(
alt.X('level_0').title(None),
alt.Y('level_1').title(None),
alt.Color('correlation').scale(domain=[-1, 1], scheme='blueorange'),
opacity=alt.condition(select_x & select_y, alt.value(1), alt.value(0.4))
).add_params(
select_x, select_y
)

# Create chart with individual lines/timeseries
base = alt.Chart(
ex_ts.melt(
id_vars='date',
var_name='category',
value_name='value',
),
height=100,
width=300,
title='Individual timeseries',
)
lines = base.transform_filter(
# If the category is not in the selected values, the returned index is -1
'indexof(datum.category, select_x.level_0) !== -1'
'| indexof(datum.category, select_y.level_1) !== -1'
).mark_line().encode(
alt.X('date:T').axis(labels=False).title(None),
alt.Y('value').scale(domain=(0, 1)),
alt.Color('category').legend(orient='top', offset=-20).title(None)
)

# Create chart with difference between lines/timeseries
dynamic_title = alt.Title(alt.expr(f'"Difference " + {select_x.name}.level_0 + " - " + {select_y.name}.level_1'))
# We pivot transform to get each category as a column
lines_diff = base.transform_pivot(
'category', 'value', groupby=['date']
# In the calculate transform we use the values from the selection to subset the columns to substract
).transform_calculate(
difference = f'datum[{select_x.name}.level_0] - datum[{select_y.name}.level_1]'
).mark_line(color='grey').encode(
alt.X('date:T').axis(format='%Y-%m-%d').title(None),
alt.Y('difference:Q').scale(domain=(-1, 1)),
).properties(
title=dynamic_title
)

# Layout the charts
(lines & lines_diff) | heatmap

0 comments on commit 89b717c

Please sign in to comment.