【问题标题】:Multi-Line Interactive Plot with drop-down menu带下拉菜单的多线交互式绘图
【发布时间】:2019-06-05 05:01:57
【问题描述】:

我正在尝试创建一个类似于此的情节:

https://altair-viz.github.io/gallery/multiline_tooltip.html

我想添加一个下拉菜单来选择不同的对象。

我已经修改了我的代码以创建一个示例来说明:

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

np.random.seed(42)
source = pd.DataFrame(np.cumsum(np.random.randn(100, 3), 0).round(2),
                    columns=['A', 'B', 'C'], index=pd.RangeIndex(100, name='x'))
source = source.reset_index().melt('x', var_name='category', value_name='y')
source['Type'] = 'First'

source_1 = source.copy()
source_1['y'] = source_1['y'] + 5
source_1['Type'] = 'Second'

source_2 = source.copy()
source_2['y'] = source_2['y'] - 5
source_2['Type'] = 'Third'

source = pd.concat([source, source_1, source_2])

input_dropdown = alt.binding_select(options=['First', 'Second', 'Third'])
selection = alt.selection_single(name='Select', fields=['Type'],
                                   bind=input_dropdown)

# color = alt.condition(select_state,
#                       alt.Color('Type:N', legend=None),
#                       alt.value('lightgray'))

# Create a selection that chooses the nearest point & selects based on x-value
nearest = alt.selection(type='single', nearest=True, on='mouseover',
                        fields=['x'], empty='none')

# The basic line
base = alt.Chart(source).encode(
    x='x:Q',
    y='y:Q',
    color='category:N'
)

# add drop-down menu
lines = base.mark_line(interpolate='basis').add_selection(selection
).transform_filter(selection)

# Transparent selectors across the chart. This is what tells us
# the x-value of the cursor
selectors = alt.Chart(source).mark_point().encode(
    x='x:Q',
    opacity=alt.value(0),
).add_selection(
    nearest
)

# Draw points on the line, and highlight based on selection
points = base.mark_point().encode(
    opacity=alt.condition(nearest, alt.value(1), alt.value(0))
)

# Draw text labels near the points, and highlight based on selection
text = base.mark_text(align='left', dx=5, dy=-5).encode(
    text=alt.condition(nearest, 'y:Q', alt.value(' '))
)

# Draw a rule at the location of the selection
rules = alt.Chart(source).mark_rule(color='gray').encode(
    x='x:Q',
).transform_filter(
    nearest
)

#Put the five layers into a chart and bind the data
alt.layer(
    lines, selectors, points, rules, text
).properties(
    width=500, height=300
)

如您所见,每次我选择一种类型(“第一”、“第二”或“第三”)时,交互式绘图仍会显示所有这三种类型的点,而不是仅显示一种类型的点,尽管只有一种类型的线显示出来。


原问题:

我正在尝试创建一个类似于此的情节:

https://altair-viz.github.io/gallery/multiline_tooltip.html

有出口、进口和赤字。我想添加一个下拉菜单来选择不同的状态(所以每个状态都会有这样的情节)。

我的数据如下所示:

    State           Year    Category        Trade, in Million Dollars
0   Texas           2008     Export         8970.979210
1   California      2008    Export          11697.850116
2   Washington      2008    Import          8851.678608
3   South Carolina  2008     Deficit        841.495319
4   Oregon          2008     Import         2629.939168

我尝试了几种不同的方法,但都失败了。如果我只想绘制“线”对象,我可以做得很好。但我不能将“线”与“点”结合起来。

import altair as alt

states = list(df_trade_china.State.unique())
input_dropdown = alt.binding_select(options=states)
select_state = alt.selection_single(name='Select', fields=['State'],
                                   bind=input_dropdown)

# Create a selection that chooses the nearest point & selects based on x-value
nearest = alt.selection(type='single', nearest=True, on='mouseover',
                        fields=['Year'], empty='none')

# The basic line
line = alt.Chart(df_trade_china).mark_line().encode(
    x='Year:O',
    y='Trade, in Million Dollars:Q',
    color='Category:N'
).add_selection(select_state
).transform_filter(select_state
)

# Transparent selectors across the chart. This is what tells us
# the x-value of the cursor
selectors = alt.Chart(df_trade_china).mark_point().encode(
    x='Year:O',
    opacity=alt.value(0),
).add_selection(
    nearest
)

# Draw points on the line, and highlight based on selection
points = line.mark_point().encode(
    opacity=alt.condition(nearest, alt.value(1), alt.value(0))
)

# Draw text labels near the points, and highlight based on selection
text = line.mark_text(align='left', dx=5, dy=-5).encode(
    text=alt.condition(nearest, 'Trade, in Million Dollars:Q', alt.value(' '))
)

# Draw a rule at the location of the selection
rules = alt.Chart(df_trade_china).mark_rule(color='gray').encode(
    x='Year:Q',
).transform_filter(
    nearest
)

#Put the five layers into a chart and bind the data
alt.layer(
    line
).properties(
    width=500, height=300
)

这是我收到的错误消息。

JavaScript Error: Duplicate signal name: "Select_tuple"

This usually means there's a typo in your chart specification. See the javascript console for the full traceback.

【问题讨论】:

    标签: python plot interactive altair


    【解决方案1】:

    新问题的新答案:

    您的过滤器转换仅应用于行数据,因此它仅过滤行。如果要过滤每一层,请确保每一层都有过滤器变换。

    你的代码如下所示:

    import altair as alt
    import pandas as pd
    import numpy as np
    
    np.random.seed(42)
    source = pd.DataFrame(np.cumsum(np.random.randn(100, 3), 0).round(2),
                        columns=['A', 'B', 'C'], index=pd.RangeIndex(100, name='x'))
    source = source.reset_index().melt('x', var_name='category', value_name='y')
    source['Type'] = 'First'
    
    source_1 = source.copy()
    source_1['y'] = source_1['y'] + 5
    source_1['Type'] = 'Second'
    
    source_2 = source.copy()
    source_2['y'] = source_2['y'] - 5
    source_2['Type'] = 'Third'
    
    source = pd.concat([source, source_1, source_2])
    
    input_dropdown = alt.binding_select(options=['First', 'Second', 'Third'])
    selection = alt.selection_single(name='Select', fields=['Type'],
                                       bind=input_dropdown, init={'Type': 'First'})
    
    # color = alt.condition(select_state,
    #                       alt.Color('Type:N', legend=None),
    #                       alt.value('lightgray'))
    
    # Create a selection that chooses the nearest point & selects based on x-value
    nearest = alt.selection(type='single', nearest=True, on='mouseover',
                            fields=['x'], empty='none')
    
    # The basic line
    base = alt.Chart(source).encode(
        x='x:Q',
        y='y:Q',
        color='category:N'
    ).transform_filter(
        selection
    )
    
    # add drop-down menu
    lines = base.mark_line(interpolate='basis').add_selection(selection
    )
    
    # Transparent selectors across the chart. This is what tells us
    # the x-value of the cursor
    selectors = alt.Chart(source).mark_point().encode(
        x='x:Q',
        opacity=alt.value(0),
    ).add_selection(
        nearest
    )
    
    # Draw points on the line, and highlight based on selection
    points = base.mark_point().encode(
        opacity=alt.condition(nearest, alt.value(1), alt.value(0))
    )
    
    # Draw text labels near the points, and highlight based on selection
    text = base.mark_text(align='left', dx=5, dy=-5).encode(
        text=alt.condition(nearest, 'y:Q', alt.value(' '))
    )
    
    # Draw a rule at the location of the selection
    rules = alt.Chart(source).mark_rule(color='gray').encode(
        x='x:Q',
    ).transform_filter(
        nearest
    )
    
    #Put the five layers into a chart and bind the data
    alt.layer(
        lines, selectors, points, rules, text
    ).properties(
        width=500, height=300
    )
    

    原始问题的原始答案:

    单个选择只能添加到图表一次。当你写这样的东西时:

    line = alt.Chart(...).add_selection(selection)
    
    points = line.mark_point()
    

    linepoints 中添加了相同的选择(因为points 派生自line)。当您对它们进行分层时,每个层都会声明一个相同的选择,这会导致重复信号名称错误。

    要解决此问题,请避免将相同的选择添加到单个图表的多个组件中。

    例如,您可以执行以下操作(切换到示例数据集,因为您没有在问题中提供数据):

    import altair as alt
    from vega_datasets import data
    
    stocks = data.stocks()
    stocks.symbol.unique().tolist()
    
    input_dropdown = alt.binding_select(options=stocks.symbol.unique().tolist())
    selection = alt.selection_single(fields=['symbol'], bind=input_dropdown,
                                     name='Company', init={'symbol': 'GOOG'})
    color = alt.condition(selection,
                          alt.Color('symbol:N', legend=None),
                          alt.value('lightgray'))
    
    
    base = alt.Chart(stocks).encode(
        x='date',
        y='price',
        color=color
    )
    
    line = base.mark_line().add_selection(
        selection
    )
    
    point = base.mark_point()
    
    line + point
    

    请注意,通过add_selection() 的选择声明只能在图表的单个组件上调用,而选择的效果(这里是颜色条件)可以添加到图表的多个组件。

    【讨论】:

    • 我该怎么做?我希望一次只能从下拉菜单中选择一个对象并且只显示它的点,所以似乎points 必须从line 派生。例如,当我将代码更改为# The basic line line = alt.Chart(df_trade_china).mark_line().encode( x='Year:O', y='Trade, in Million Dollars:Q', color='Category:N' ) # add drop-down menu line_plot = line.add_selection(select_state ).transform_filter(select_state ) 时,points 选择所有对象而不是下拉菜单中的一个。
    • 代码在评论线程中效果不佳。我用一个例子编辑了答案。
    • 您的过滤器转换仅在行上运行,因此您仅过滤行。将您的过滤器转换放在基础上,以便过滤所有内容。我用你的新问题的答案编辑了我的答案。
    • 一旦您的问题已经得到回答,请不要在未来对您的问题进行大量编辑。如果您有其他问题要问,请打开一个新问题。
    • 我会这样做的。将来——我一开始没有明确说明我的问题。
    猜你喜欢
    • 2019-10-07
    • 1970-01-01
    • 2021-10-23
    • 2022-07-01
    • 2021-04-08
    • 2018-07-18
    • 2022-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多