9

This is how I would like the image to look like

I am trying to shade different regions in my plot created with Altair (like axvspan in matplotlib) but can't find a way to do it.

Chart(data).mark_line(color='r').encode(
    x=X('Voltage'),
    y=Y('Current (pA)', axis=Axis(format='r'), title='Current (pA)'),
    color='Line polarity:N',
    shape='Line polarity:N',
)
Yiti
  • 281
  • 3
  • 9
  • do you have a sample of how the plot should look like? – Nipun Batra Jul 02 '17 at 12:38
  • I have added the image, I managed to do it by creating the data for the shaded region and then using 'mark_area'. Then using LayeredChart to superimpose them. I wondering if there is a more straightforward way – Yiti Jul 05 '17 at 13:57
  • 2
    Your way may be the best way. Do you want to put the code up here? (edit question) – Nipun Batra Jul 05 '17 at 14:16

1 Answers1

4

The best way to mimic matplotlib's axvspan in Altair is with a rect mark tied to pixel values in the y-axis.

Here is an example:

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

np.random.seed(1701)

data = pd.DataFrame({
    'Voltage': np.linspace(0, 100, 10),
    'Current': np.random.randn(10).cumsum()
})

cutoff = pd.DataFrame({
    'start': [0, 8, 30],
    'stop': [8, 30, 100]
})

line = alt.Chart(data).mark_line().encode(
    x=alt.X('Voltage'),
    y=alt.Y('Current')
)

areas = alt.Chart(
    cutoff.reset_index()
).mark_rect(
    opacity=0.2
).encode(
    x='start',
    x2='stop',
    y=alt.value(0),  # pixels from top
    y2=alt.value(300),  # pixels from top
    color='index:N'
)

(areas + line).interactive()

enter image description here

jakevdp
  • 77,104
  • 11
  • 125
  • 160
  • Thanks for this solution. Can I combine this with facetting? I have a similar problem but I also want to facet. `(areas + line).facet(row='foo')` gives me `ValueError: Facet charts require data to be specified at the top level.` I think this is because the two layered charts do not share the same data. I don't see a way around this. – Epimetheus May 07 '21 at 16:55