提问人:multipitch 提问时间:11/16/2023 最后编辑:toyota Supramultipitch 更新时间:11/16/2023 访问量:34
Altair:根据列表中的标签成员身份将条件应用于轴标签颜色
Altair: Apply condition to axis label color based on label membership in a list
问:
我有一个调度图,其中 Y 轴是分类的(每个 Y 条目对应于一台设备,x 轴显示时间)。
我有一个包含调度冲突的设备列表。 对于有冲突的装备列表中的每个装备项目,我想在剧情上用红色突出显示装备名称。
我找不到一种方法来应用检查列表中成员身份的测试。
这里发布了一个类似的问题: 在 altair 图中为一些 x 标签着色? - 但是这个解决方案涉及将测试编码为一个字符串,我猜这个字符串是由 altair 解释的。“is in”测试似乎在这种结构中不起作用。
下面是一个最小的工作示例:
import streamlit as st
import altair as alt
import pandas as pd
data = [
{"task": "Task 1", "start": 1, "finish": 10, "equipment": "XXX-101"},
{"task": "Task 2", "start": 9, "finish": 20, "equipment": "XXX-101"},
{"task": "Task 3", "start": 6, "finish": 8, "equipment": "XXX-102"},
{"task": "Task 4", "start": 9, "finish": 12, "equipment": "XXX-102"},
{"task": "Task 5", "start": 13, "finish": 18, "equipment": "XXX-102"},
{"task": "Task 6", "start": 5, "finish": 15, "equipment": "XXX-103"},
{"task": "Task 7", "start": 16, "finish": 18, "equipment": "XXX-103"},
{"task": "Task 8", "start": 6, "finish": 8, "equipment": "XXX-104"},
{"task": "Task 9", "start": 4, "finish": 12, "equipment": "XXX-104"},
{"task": "Task 10", "start": 11, "finish": 16, "equipment": "XXX-104"},
]
dataframe = pd.DataFrame(data)
equipment_has_clashes = ["XXX-101", "XXX-104"] # determined by another algorithm
chart = (
alt.Chart(dataframe)
.mark_bar(height=20)
.encode(
x=alt.X("start").title("time"),
x2=("finish"),
y=alt.Y(
"equipment",
axis=alt.Axis(
labelColor=alt.condition(
# Want to apply test equivalent to "equipment is in equipment_has_clashes"
predicate="datum",
if_true=alt.value("red"),
if_false=alt.value("black"),
)
),
),
tooltip=[alt.Tooltip(t) for t in ["task", "equipment", "start", "finish"]],
color=alt.Color("task", type="nominal").scale(scheme="category20"),
)
.properties(height=alt.Step(30))
.configure_view(strokeWidth=1)
.configure_axis(domain=True, grid=True)
.interactive()
)
st.altair_chart(chart, use_container_width=True)
答:
2赞
Suraj Shourie
11/16/2023
#1
也许不是最优雅的解决方案,但您可以在此处的解决方案中使用“OR”运算符传递每个条件。
cond = " || ".join([f'datum.value == "{x}"' for x in equipment_has_clashes])
并将其传递到您的:labelColor
axis=alt.Axis(
labelColor=alt.condition(cond, alt.value('red'), alt.value('blue'))
),
输出:
另一种解决方案可能是使用这样的东西,但我无法实现它。
评论
0赞
multipitch
11/16/2023
感谢您的建议 - 似乎工作正常。
0赞
multipitch
11/16/2023
#2
看来谓语表达式必须用 vega 表达式语言编写。
没有定义的成员资格测试函数,但使用 似乎提供了一个有效的技巧:https://vega.github.io/vega/docs/expressions/#indexofindexof
我将equipment_has_clashes列表作为字符串提供给 vega 表达式:
predicate = f"indexof({equipment_has_clashes}, datum.value) >= 0"
print(predicate)
这将给出以下谓词表达式:
indexof(['XXX-101', 'XXX-104'], datum.value) >= 0
我相应地修改了我的代码,如下所示:
import streamlit as st
import altair as alt
import pandas as pd
data = [
{"task": "Task 1", "start": 1, "finish": 10, "equipment": "XXX-101"},
{"task": "Task 2", "start": 9, "finish": 20, "equipment": "XXX-101"},
{"task": "Task 3", "start": 6, "finish": 8, "equipment": "XXX-102"},
{"task": "Task 4", "start": 9, "finish": 12, "equipment": "XXX-102"},
{"task": "Task 5", "start": 13, "finish": 18, "equipment": "XXX-102"},
{"task": "Task 6", "start": 5, "finish": 15, "equipment": "XXX-103"},
{"task": "Task 7", "start": 16, "finish": 18, "equipment": "XXX-103"},
{"task": "Task 8", "start": 6, "finish": 8, "equipment": "XXX-104"},
{"task": "Task 9", "start": 4, "finish": 12, "equipment": "XXX-104"},
{"task": "Task 10", "start": 11, "finish": 16, "equipment": "XXX-104"},
]
dataframe = pd.DataFrame(data)
equipment_has_clashes = ["XXX-101", "XXX-104"] # determined by another algorithm
predicate = f"indexof({equipment_has_clashes}, datum.value) >= 0"
chart = (
alt.Chart(dataframe)
.mark_bar(height=20)
.encode(
x=alt.X("start").title("time"),
x2=("finish"),
y=alt.Y(
"equipment",
axis=alt.Axis(
labelColor=alt.condition(
predicate=predicate,
if_true=alt.value("red"),
if_false=alt.value("black"),
)
),
),
tooltip=[alt.Tooltip(t) for t in ["task", "equipment", "start", "finish"]],
color=alt.Color("task", type="nominal").scale(scheme="category20"),
)
.properties(height=alt.Step(30))
.configure_view(strokeWidth=1)
.configure_axis(domain=True, grid=True)
.interactive()
)
st.altair_chart(chart, use_container_width=True)
评论