Altair: Crop Log10 axis to desired interval (domain)

Viewed 618

Using the Altair in Python, is it possible to crop Log10 axis at the designated value? I would like to show only between 5 - 50 on the log scale.

Below is my code and the image I get:

import altair as alt
import pandas as pd

from vega_datasets import data
cars = data.cars()

nice = pd.DataFrame([{'x_min': [0],
                    'x_max': [240],
                    'y_min': [5],
                    'y_max': [10]}])

good = pd.DataFrame([{'x_min': [0],
                    'x_max': [240],
                    'y_min': [10],
                    'y_max': [20]}])

bad = pd.DataFrame([{'x_min': [0],
                    'x_max': [240],
                    'y_min': [20],
                    'y_max': [50]}])

mpg_nice_fill = alt.Chart(nice).mark_rect(color= 'green', opacity=0.2).encode(
    x='x_min:Q',
    x2='x_max:Q',
    y='y_min:Q',
    y2='y_max:Q'
)

mpg_good_fill = alt.Chart(good).mark_rect(color= 'yellow', opacity=0.2).encode(
    x='x_min:Q',
    x2='x_max:Q',
    y='y_min:Q',
    y2='y_max:Q'
)

mpg_bad_fill = alt.Chart(bad).mark_rect(color= 'red', opacity=0.2).encode(
    x='x_min:Q',
    x2='x_max:Q',
    y='y_min:Q',
    y2='y_max:Q'
)

chart = alt.Chart(cars).mark_point().encode(
    x='Horsepower',
    y= alt.Y('Miles_per_Gallon', scale= alt.Scale(type= 'log')),
    color='Origin',
)

alt.layer(chart + mpg_nice_fill + mpg_good_fill + mpg_bad_fill + chart
         )

enter image description here

This is probably scientifically correct, but I think removing white area (< 5 mpg and > 50 mpg domains) would give me aesthetically better one. However, a domain = (5, 50) in the alt.Y() does not work for me.

1 Answers

The domain argument does work with log scales, but domains must start and end on integer powers of the base, and other values will be rounded to the next integer power.

For example, here is a default base-10 domain:

import altair as alt
import pandas as pd

data = pd.DataFrame({'x': [1, 10, 100]})

alt.Chart(data).mark_point().encode(
    x=alt.X('x', scale=alt.Scale(type='log'))
)

enter image description here

Here is a base-2 domain, with the limits set at 1 and 256:

alt.Chart(data).mark_point().encode(
    x=alt.X('x', scale=alt.Scale(type='log', base=2, domain=[1, 256]))
)

enter image description here

Unfortunately, Vega-Lite does not provide any way to set log domains to non-integer powers of the base.

For your chart above, a base-2 log scale between 8 and 64 might be a good fit:

alt.Chart(cars).mark_point().encode(
    x='Horsepower',
    y= alt.Y('Miles_per_Gallon', scale= alt.Scale(type= 'log', base=2, domain=[8, 64])),
    color='Origin',
)

enter image description here

Related