Use one shape for last element, another for all others in chart

Viewed 221

Is there a way in Altair to use one shape for all the elements in a dataframe but the last? I have data columns and a category column. I'd like all but one of the categories to plot with a circle and one category to plot with a diamond.

I understand how to set shape and color ranges, but I don't understand how to set them conditionally based on the data, just the order and values of the shapes/colors

This is a simplified example:


myData = {'category':['Cat 1','Cat 2','Cat 3'], 
          'valueX':['10','20','30'], 
          'valueY':['10','20','30']}

df = pd.DataFrame(data=myData)

alt.Chart(df).mark_point().encode(
  x = 'valueX',
  y = 'valueY',
  shape = alt.Shape('category', scale=alt.Scale(range=['circle','diamond']))
)

This just alternates between the circle and diamond. How do I have my first two categories use the circle and 'Cat 3' use the diamond?

2 Answers

The scale property allow you to map a domain to a range, where the domain specifies input values, and the range specifies the visual properties to which the domain is mapped. If you want multiple domain values to map to the same range value, it can be done like this:

alt.Chart(df).mark_point().encode(
  x = 'valueX',
  y = 'valueY',
  shape = alt.Shape('category',
    scale=alt.Scale(
      domain=['Cat 1', 'Cat 2', 'Cat 3'],
      range=['circle', 'circle', 'diamond']
    )
  )
)

enter image description here

The issue is that according to grammar of altair, the shape encoding will assign a new shape to every category. The purpose of the encoding is to distinguish between categories, so it makes sense to assign each category a new shape.

When you want to encode many categories using only two shapes, you are losing information, and this goes again the purpose of encodings in altair.

So, if you would like to have the first two categories be a circle, and the last be a diamond, you can make another column in your dataset that explicitly encodes this.

This is a data issue (i.e., addressed using pandas) rather than being an issue with altair.

In the example code below, I named the new column shape

import altair as alt
import pandas as pd

myData = {'category':['Cat 1','Cat 2','Cat 3'],
          'shape':['c','c','d'],
          'valueX':['10','20','30'], 
          'valueY':['10','20','30']}

df = pd.DataFrame(data=myData)

alt.Chart(df).mark_point().encode(
  x = 'valueX',
  y = 'valueY',
  shape = alt.Shape('shape', scale=alt.Scale(range=['circle','diamond']))
)

enter image description here

Related