Enable points for specific series

Hi,

I am new to streamlit. Please check the attached image. I am using altair chart. When I make points=true it add points to all series in the chart. Can I mix points=true and points=false for each series in the same chart? Foe example, i want Log series to be without points. visualization

Hello @msherif4u, welcome to the forums :slight_smile:

The .mark_line(points=True) is actually in Vega-lite equivalent to layering a lines chart .mark_line() and a points chart .mark_point(). By decomposing your problem into 2 different charts you have total control on the data to display with lines and with points, like in the following :

df = pd.DataFrame({
  'date': pd.date_range(start='2020-01-01', end='2020-01-31'),
  'OLS': [random.randint(0, 1) for x in range(31)],
  'OLS2': [random.randint(0, 10) for x in range(31)],
  'OLS3_nopoint': [random.randint(0, 100) for x in range(31)]
}).melt(id_vars='date', var_name="OLS", value_name="value")

lines = alt.Chart(df).mark_line().encode(
  x="date:T",
  y="value:Q",
  color='OLS:N'
)
points = alt.Chart(df[df["OLS"]!="OLS3_nopoint"]).mark_point(filled=True, opacity=1).encode(
  x="date:T",
  y="value:Q",
  color='OLS:N'
)
st.altair_chart(lines + points, use_container_width=True)

image

It should also be possible to add a column on your dataframe and use this column as an opacity channel to your points chart, I prefer that solution because you build a base graph with your x, y, color encodings, add a line over and a points controlled by opacity encoding only

df = pd.DataFrame({
  'date': pd.date_range(start='2020-01-01', end='2020-01-31'),
  'OLS': [random.randint(0, 1) for x in range(31)],
  'OLS2': [random.randint(0, 10) for x in range(31)],
  'OLS3_nopoint': [random.randint(0, 100) for x in range(31)]
}).melt(id_vars='date', var_name="OLS", value_name="value")

df['opacity'] = 0
df.loc[df['OLS']!="OLS3_nopoint", 'opacity'] = 1

base = alt.Chart(df).encode(
  x="date:T",
  y="value:Q",
  color='OLS:N'
)
lines = base.mark_line()
points = base.mark_point(filled=True).encode(
  opacity=alt.Opacity("opacity:N", legend=None)
)
st.altair_chart(lines + points, use_container_width=True)

Hope that helps,
Fanilo

Many thanks. What if i want to add two nopoint series? Can you guide me?

You can try this and replace df[df["OLS"]!="OLS3_nopoint"] by df[~df["OLS"].isin(["OLS1", "OLS2"])] to select more than one value. Did not test but should do the trick !

Wow… That’s cool… Many thanks…

1 Like

st.altair_chart(
df_columns_chart(alt, columns={
" Log active": calibration_df[‘logActive’],
“Active OLS”: intercept_active + calibration_df.index * active_ols.params.x1,
" Log positive": calibration_df[‘logPositive’],
“Positive OLS”: intercept_positive + calibration_df.index * positive_ols.params.x1,
}, as_date=False, start=StartDate, point=True),
use_container_width=True,
)

I was creating chart like this before.
as_date=False to show the days instead of numbers in x axis and
start=StartDate to provide the starting date. the end it automatically calculates based on the other series values.
So with your code is it possible to achieve this?

Which library is df_columns_chart from ? Do you have the code of this function ?

Otherwise you could build a dataframe with the columns you want and use my function afterwards :wink: but I feel we’re pretty much rewriting the function there …

endDate = # some code to find latest date in your dataframe

df = pd.DataFrame({
  'date': pd.date_range(start=StartDate , end=endDate),
  'Log active': calibration_df[‘logActive’],
  'Active OLS':  intercept_active + calibration_df.index * active_ols.params.x1,
  'Log positive': calibration_df[‘logPositive’]
  'Positive OLS': intercept_positive + calibration_df.index * positive_ols.params.x1
}).melt(id_vars='date', var_name="OLS", value_name="value")

df['opacity'] = 0
df.loc[df['OLS'].isin(["Log positive", "Positive OLS"]), 'opacity'] = 1

base = alt.Chart(df).encode(
  x=alt.Axis("date:T", format="%d/%m/%Y"),  # format the axis label there !
  y="value:Q",
  color='OLS:N'
)
lines = base.mark_line()
points = base.mark_point(filled=True).encode(
  opacity=alt.Opacity("opacity:N", legend=None)
)
st.altair_chart(lines + points, use_container_width=True)