I have found some examples where a color scale is defined and a category variable is chosen based on which the plots are colored. E.g. here:
https://github.com/altair-viz/altair/issues/921
I want the user to be able to plot various lines onto a LayerChart, and select the color manually for each line added (i.e. choose a color from a dropdown list, click plot, and add a new plot to the existing chart with the color chosen). How can I directly tell altair to plot using a certain color?
I tried:
lines = alt.Chart(df).mark_line().encode(
x=alt.X(...),
y=alt.Y(...),
color='rgb(255,184,56)'
)
but this does not work.
Thanks.
Two ways to do this:
alt.Chart(df).mark_line(color="#FFAA00").encode(
x='x',
y='y'
)
or
alt.Chart(df).mark_line().encode(
x='x',
y='y',
color=alt.value("#FFAA00")
)
The reason your first approach doesn't work is because it indicates you want to encode using a column named 'rgb(255,184,56)'.
See Customizing Visualizations for more information.
Thanks, not sure how I missed that.
Hi, I am using multi chart and there is no way to specify the legends directly. So as a hack, introduced a separate legend column to each of the charts. However, still stuck with giving colour of my own choice. Colour has to be consistent for different plots that will be drawn several times for different timeframes on the same page. Here is an example:
dataframe_1['Legend'] = "Speed_GPS"
base = alt.Chart(
dataframe_1,
title="Speed plot",
).interactive()
udf_chart = (
base.mark_line(color="steelblue")
.encode(
x=alt.X("Timestamp", axis=alt.Axis(title="Timestamp")),
y=alt.Y("Location Speed", axis=alt.Axis(title="Speed in m/s")),
color='Legend'
)
.properties(width=2000)
)
dataframe_2['Legend'] = "Speed_others"
sdf = alt.Chart(dataframe_2)
sdf_chart = sdf.mark_line(color="#F4D03F").encode(x="timestamp", y="speed",
color="Legend")
###(hb_events_df is another dataframe for the same time period)
hb_events_df['Legend'] = "Car Hard Brakes"
hb_dot = (
alt.Chart(hb_events_df)
.mark_circle(color="red", size=150)
.encode(x="Timestamp", y="Location Speed", color="Legend")
)
###(ra_events_df is another dataframe for the same time period)
ra_events_df['Legend'] = "Car Rapid Acceleration"
ra_dot = (
alt.Chart(ra_events_df)
.mark_circle(color="red", size=150)
.encode(x="Timestamp", y="Location Speed", color="Legend")
)
udf_chart + sdf_chart + hb_dot + ra_dot
The above plot gives different color each time and would like to know if there is a way to mention alt.value after color column. Thanks in advance.
You can specify a desired color scale using alt.Scale. See https://altair-viz.github.io/user_guide/customization.html#color-domain-and-range for some examples.
Thanks. It fit my purpose. Though I tried alt.Scale as suggested here, the color is not consistent for the plots called several times on the same page. Now it is. Probably I missed a common range/domain definition.
Here is my not so good looking code. Just in case it helps someone introduce legends to multi layer, though I don't recommend taking this path..
domain = ["Speed 1", "Speed 2", "x", "y"]
range_ = ["steelblue", "lightsalmon", "green", "red"]
selector = alt.selection_single(fields=["Legend"], empty="all", bind="legend")
dataframe_1["Legend"] = domain[0]
base = alt.Chart(
title="Some title",
).interactive()
dataframe_2["Legend"] = domain[1]
sdf = alt.Chart(dataframe_2.reset_index())
udf_chart = (
base.mark_line(color="steelblue")
.encode(
x=alt.X("timestamp", axis=alt.Axis(title="Timestamp")),
y=alt.Y("speed", axis=alt.Axis(title="Speed in m/s")),
color=alt.Color("Legend", scale=alt.Scale(domain=domain, range=range_)),
opacity=alt.condition(selector, alt.value(1), alt.value(0)),
)
.add_selection(selector)
.properties(width=2000)
)
sdf_chart = sdf.mark_line(color="lightsalmon").encode(
x="timestamp",
y="speed",
color=alt.Color("Legend", scale=alt.Scale(domain=domain, range=range_)),
opacity=alt.condition(selector, alt.value(1), alt.value(0)),
)
if x1.empty:
x_lines = text_hb = None
else:
x1.loc[x1.index, "Legend"] = "xline"
x_lines = (
alt.Chart(x1.reset_index())
.mark_rule(color="chartreuse", strokeWidth=1)
.encode(x="timestamp")
)
text_x1 = x_lines.mark_text(align="left", baseline="top", y=ymax).encode(
text="Legend"
)
if y1.empty:
y_lines = text_ra = None
else:
y1.loc[y1.index, "Legend"] = "yline"
y_lines = (
alt.Chart(y1.reset_index())
.mark_rule(color="lightpink", strokeWidth=2)
.encode(x="timestamp")
)
text_y1 = y_lines.mark_text(align="left", baseline="top", y=ymax).encode(
text="Legend"
)
if x.empty:
x_dot = None
else:
x["Legend"] = domain[2]
x_dot = (
alt.Chart(x)
.mark_circle(color="green", size=150)
.encode(
x="timestamp",
y="speed",
color=alt.Color(
"Legend", scale=alt.Scale(domain=domain, range=range_)
),
)
)
if y.empty:
y_dot = None
else:
y["Legend"] = domain[3]
y_dot = (
alt.Chart(y)
.mark_circle(color="red", size=150)
.encode(
x="timestamp",
y="speed",
color=alt.Color(
"Legend", scale=alt.Scale(domain=domain, range=range_)
),
)
)
chart_list = [
"x_lines",
"y_lines",
"text_x1",
"text_y1",
"x_dot",
"y_dot",
]
to_plot = "udf_chart + sdf_chart"
for item in chart_list:
if eval(item) is not None:
to_plot = to_plot + " + " + item
st.altair_chart(eval(to_plot))
(Of course, I would like to avoid 'eval' .. work in progress)
Most helpful comment
Two ways to do this:
or
The reason your first approach doesn't work is because it indicates you want to encode using a column named
'rgb(255,184,56)'.See Customizing Visualizations for more information.