Invert axis direction Altair - python
For some reason, the Y-axis while plotting with altair seems to be inverted (would expect values to go from lower (bottom) to higher (top) of the plot). Also, I would like to be able to change the ticks frequency. With older versions I could use ticks=n_ticks but it seems now this argument can take only boolean.
import altair as alt
alt.renderers.enable('notebook')
eff_metals = pd.read_excel(filename, sheet_name='summary_eff_metals')
points = alt.Chart(eff_metals, height=250, width=400).mark_circle().encode(
x=alt.X('Temperature:Q',axis=alt.Axis(title='Temperature (°C)'),
scale=alt.Scale(zero=False, padding=50)),
y=alt.Y('Efficiency:N',axis=alt.Axis(title='Efficiency (%)'),
scale=alt.Scale(zero=False, padding=1)),
color=alt.Color('Element:N'),
)
text = points.mark_text(align='right', dx=0, dy=-5).encode(
text='Element:N'
)
chart = alt.layer(points, text, data=eff_metals,
width=600, height=300)
chart
And the figure:
I don't have your data, so difficult to write working code.
But here's an example of an inverted scale with additional ticks that is similar to the example scatter with tooltips example. See here for it in the vega editor.
import altair as alt
from vega_datasets import data
iris = data.iris()
alt.Chart(iris).mark_point().encode(
x='petalWidth',
y=alt.Y('petalLength', scale=alt.Scale(domain=[7,0]), axis=alt.Axis(tickCount=100)),
color='species'
).interactive()
This might work with your data:
eff_metals = pd.read_excel(filename, sheet_name='summary_eff_metals')
points = alt.Chart(eff_metals, height=250, width=400).mark_circle().encode(
x=alt.X('Temperature:Q',axis=alt.Axis(title='Temperature (°C)'),
scale=alt.Scale(zero=False, padding=50)),
y=alt.Y('Efficiency:N',axis=alt.Axis(title='Efficiency (%)'),
scale=alt.Scale(zero=False, padding=1, domain=[17,1])),
color=alt.Color('Element:N'),
)
text = points.mark_text(align='right', dx=0, dy=-5).encode(
text='Element:N'
)
chart = alt.layer(points, text, data=eff_metals,
width=600, height=300)
chart
However, I think it's possible that you've might just have the wrong type on your efficiency variable. You could try and replace 'Efficiency:N' with `'Efficiency:Q' and that might do it?
While it's possible to reverse the domain manually, that requires hardcoding the bounds.
Instead we can just pass Scale(reverse=True) to the axis encoding, e.g.:
from vega_datasets import data
alt.Chart(data.wheat().head()).mark_bar().encode(
x='wheat:Q',
y=alt.Y('year:O', scale=alt.Scale(reverse=True)),
)
Here it's been passed to alt.Y, so the years are inverted (left) vs the default y='year:O' (right):
Related
Add formatting, surrounding box to Altair vertical line tooltip label?
I am new to Altair, and am attempting to plot a monthly time-series variable, and have a vertical line tooltip display the date and corresponding y-value. The code I have (warning, probably a bit ugly) gets me most of the way there: import altair as alt import datetime as dt import numpy as np import pandas as pd # create DataFrame monthly_dates = pd.date_range('1997-09-01', '2022-08-01', freq = 'M') monthly_data = pd.DataFrame( index=['Date', 'y_var'], data=[monthly_dates, np.random.normal(size = len(monthly_dates))] ).T # Create a selection that chooses the nearest point & selects based on x-value nearest = alt.selection(type='single', nearest=True, on='mouseover', fields=['Date'], empty='none') # The basic line line = alt.Chart(monthly_data).mark_line().encode( x='Date:T', y=alt.Y('y_var', title='Y variable') ) # Transparent selectors across the chart. This is what tells us # the x-value of the cursor selectors = alt.Chart(monthly_data).mark_point().encode( x='Date', opacity=alt.value(0), ).add_selection( nearest ) # Draw points on the line, and highlight based on selection points = line.mark_point().encode( opacity=alt.condition(nearest, alt.value(1), alt.value(0)) ) # Draw text labels near the points, and highlight based on selection text_x = line.mark_text(align='left', dx=5, dy=-10).encode( text=alt.condition(nearest, 'Date', alt.value(' ')) ) # Draw text labels near the points, and highlight based on selection text_y = line.mark_text(align='left', dx=5, dy=5).encode( text=alt.condition(nearest, 'y_var', alt.value(' ')) ).transform_calculate(label='datum.y_var + "%"') # Draw a rule at the location of the selection rules = alt.Chart(monthly_data).mark_rule(color='gray').encode( x='Date', ).transform_filter( nearest ) # Put the seven layers into a chart and bind the data chart = alt.layer( line, selectors, points, rules, text_x, text_y ).properties( width=600, height=300 ).interactive() chart.show() yields the following interactive chart: There are two things I need to do, though: Add a box around the tooltip labels (and a plain background to this box), so that they are easy to read. Format the labels independently: since we have monthly data, it would be great to drop the day and just have Oct 2008 or 2008-10 or something along those lines. For the value, rounding to one or two digits and adding '%' afterwards would be great. I tried using the example found here (as you can see for creating text_y) but to no avail. Any and all help would be greatly appreciated. Apologies in advance for any dumb mistakes or poor coding practices; again, I am still learning the basics of Altair.
Update: I figured both out. The solutions to both 1 and 2 are in the code below. For 1: instead of trying to add a box around the text manually, I instead added tooltips to the selectors object and dropped the text_x and text_y entirely. For 2: I used transform_calculate to create new fields for x_label and y_label that are exactly what I want to display, then feed these into the tooltip objects. This page has tons of ways to transform data. selectors = alt.Chart(monthly_data).mark_point().transform_calculate( x_label='timeFormat(datum.Date, "%b %Y")', y_label='format(datum.y_var, ".1f") + "%"' ).encode( x='Date', opacity=alt.value(0), tooltip=[ alt.Tooltip('x_label:N', title='Date'), alt.Tooltip('y_label:N', title='Pct. Change') ] ).add_selection( nearest ) The finished product:
Parallel coordinates in Altair
I want to do a parallel coordinates plot with multiple y axis. I've found how to do it in Vega-Lite here but I haven't found the way to do it with Altair, there's only a very simple example where all the y axis are the same. Is there any way to do this plot in altair?
Note that this kind of chart is not "built-in" to Altair or Vega-Lite, so the only way to create it is with a manual sequence of transforms, and manually constructing your axes from tick and text marks. Here is an Altair version of the chart in the answer you linked to: import altair as alt from vega_datasets import data base = alt.Chart( data.iris.url ).transform_window( index="count()" ).transform_fold( ["petalLength", "petalWidth", "sepalLength", "sepalWidth"] ).transform_joinaggregate( min="min(value)", max="max(value)", groupby=["key"] ).transform_calculate( norm_val="(datum.value - datum.min) / (datum.max - datum.min)", mid="(datum.min + datum.max) / 2" ).properties(width=600, height=300) lines = base.mark_line(opacity=0.3).encode( x='key:N', y=alt.Y('norm_val:Q', axis=None), color="species:N", detail="index:N", tooltip=["petalLength:N", "petalWidth:N", "sepalLength:N", "sepalWidth:N"] ) rules = base.mark_rule( color="#ccc", tooltip=None ).encode( x="key:N", detail="count():Q", ) def ytick(yvalue, field): scale = base.encode(x='key:N', y=alt.value(yvalue), text=f"min({field}):Q") return alt.layer( scale.mark_text(baseline="middle", align="right", dx=-5, tooltip=None), scale.mark_tick(size=8, color="#ccc", orient="horizontal", tooltip=None) ) alt.layer( lines, rules, ytick(0, "max"), ytick(150, "mid"), ytick(300, "min") ).configure_axisX( domain=False, labelAngle=0, tickColor="#ccc", title=None ).configure_view( stroke=None )
Change errorbar thickness in Altair
How can I change the thickness of my errorbars in Altair? When I tried to change the color to black, it turns out than it should be. Why is that? My expected output is But the actual output is Here is my code import altair as alt alt.Chart(df2).mark_errorbar(color='black').encode( alt.X( "quantile95", axis=alt.Axis(title="lower",tickMinStep=5), scale=alt.Scale(domain=[0, 55]) ) ).properties(width=450, height=20)
Since no data was provided, I used the data from the official reference to create the expected output. One is a box plot and the other is an overlaid strip plot. import altair as alt from vega_datasets import data source = data.barley() error_bar_s = alt.Chart(source).mark_boxplot(color='black').encode( x=alt.X("yield:Q", axis=alt.Axis(title="lower", tickMinStep=5), scale=alt.Scale(domain=[0, source['yield'].max()+10])), y=alt.Y('variety:N') ).properties(width=450, height=450) strip = alt.Chart(source).mark_tick(color='red').encode( x='yield:Q', y='variety:N' ) error_bar_s + strip
Using Iris dataset as example this will be the necessary code from vega_datasets import data # pip install vega_datasets import altair as alt dataset = data.iris() ticks = alt.Chart(dataset).mark_tick().encode( alt.X('sepalWidth', scale=alt.Scale(zero=False)), ) mean_point = alt.Chart(dataset).mark_circle().encode( x=alt.X('mean(sepalWidth)'), color=alt.value("black"), size=alt.value(50) ) errorbar = alt.Chart(dataset).mark_errorbar(extent='stdev', ticks=True).encode( x=alt.X('sepalWidth'), color=alt.value("black"), strokeWidth=alt.value(5) ) errorbar + mean_point + ticks Output: Some key remarks: If ticks are not needed, remove the ticks parameter in the mark_errobar The "thickness" of the CI is the strokeWidth parameter in the encode of the mark_errorbar The extend parameter could be "ci", "stdev", "stderr", "iqr". See docs
How to color lines on mouseover in a bump chart using Altair Viz?
The goal is to highlight the entire line when hovering anywhere (not just at the data points) on the line. Imports: from IPython.display import display import pandas as pd import altair as alt Data: data = '{"Date":{"5":1560643200000,"18":1560643200000,"22":1560643200000,"24":1560643200000,"59":1560643200000,"65":1561248000000,"78":1561248000000,"82":1561248000000,"84":1561248000000,"119":1561248000000,"125":1561852800000,"138":1561852800000,"142":1561852800000,"144":1561852800000,"179":1561852800000,"185":1562457600000,"198":1562457600000,"202":1562457600000,"204":1562457600000,"239":1562457600000,"245":1563062400000,"258":1563062400000,"262":1563062400000,"264":1563062400000,"299":1563062400000,"305":1563667200000,"318":1563667200000,"322":1563667200000,"324":1563667200000,"359":1563667200000,"365":1564272000000,"378":1564272000000,"382":1564272000000,"384":1564272000000,"419":1564272000000,"425":1564876800000,"438":1564876800000,"442":1564876800000,"444":1564876800000,"479":1564876800000,"485":1565481600000,"498":1565481600000,"502":1565481600000,"504":1565481600000,"539":1565481600000,"545":1566086400000,"558":1566086400000,"562":1566086400000,"564":1566086400000,"599":1566086400000,"605":1566691200000,"618":1566691200000,"622":1566691200000,"624":1566691200000,"659":1566691200000,"665":1567296000000,"678":1567296000000,"682":1567296000000,"684":1567296000000,"719":1567296000000,"725":1567900800000,"738":1567900800000,"742":1567900800000,"744":1567900800000,"779":1567900800000,"785":1568505600000,"798":1568505600000,"802":1568505600000,"804":1568505600000,"839":1568505600000,"845":1569110400000,"858":1569110400000,"862":1569110400000,"864":1569110400000,"899":1569110400000,"905":1569715200000,"918":1569715200000,"922":1569715200000,"924":1569715200000,"959":1569715200000,"965":1570320000000,"978":1570320000000,"982":1570320000000,"984":1570320000000,"1019":1570320000000,"1025":1570924800000,"1038":1570924800000,"1042":1570924800000,"1044":1570924800000,"1079":1570924800000,"1085":1571529600000,"1098":1571529600000,"1102":1571529600000,"1104":1571529600000,"1139":1571529600000,"1145":1572134400000,"1158":1572134400000,"1162":1572134400000,"1164":1572134400000,"1199":1572134400000,"1205":1572739200000,"1218":1572739200000,"1222":1572739200000,"1224":1572739200000,"1259":1572739200000,"1265":1573344000000,"1278":1573344000000,"1282":1573344000000,"1284":1573344000000,"1319":1573344000000,"1325":1573948800000,"1338":1573948800000,"1342":1573948800000,"1344":1573948800000,"1379":1573948800000,"1385":1574553600000,"1398":1574553600000,"1402":1574553600000,"1404":1574553600000,"1439":1574553600000,"1445":1575158400000,"1458":1575158400000,"1462":1575158400000,"1464":1575158400000,"1499":1575158400000,"1505":1575763200000,"1518":1575763200000,"1522":1575763200000,"1524":1575763200000,"1559":1575763200000,"1565":1576368000000,"1578":1576368000000,"1582":1576368000000,"1584":1576368000000,"1619":1576368000000},"Store":{"5":"store1","18":"store2","22":"store3","24":"store4","59":"store5","65":"store1","78":"store2","82":"store3","84":"store4","119":"store5","125":"store1","138":"store2","142":"store3","144":"store4","179":"store5","185":"store1","198":"store2","202":"store3","204":"store4","239":"store5","245":"store1","258":"store2","262":"store3","264":"store4","299":"store5","305":"store1","318":"store2","322":"store3","324":"store4","359":"store5","365":"store1","378":"store2","382":"store3","384":"store4","419":"store5","425":"store1","438":"store2","442":"store3","444":"store4","479":"store5","485":"store1","498":"store2","502":"store3","504":"store4","539":"store5","545":"store1","558":"store2","562":"store3","564":"store4","599":"store5","605":"store1","618":"store2","622":"store3","624":"store4","659":"store5","665":"store1","678":"store2","682":"store3","684":"store4","719":"store5","725":"store1","738":"store2","742":"store3","744":"store4","779":"store5","785":"store1","798":"store2","802":"store3","804":"store4","839":"store5","845":"store1","858":"store2","862":"store3","864":"store4","899":"store5","905":"store1","918":"store2","922":"store3","924":"store4","959":"store5","965":"store1","978":"store2","982":"store3","984":"store4","1019":"store5","1025":"store1","1038":"store2","1042":"store3","1044":"store4","1079":"store5","1085":"store1","1098":"store2","1102":"store3","1104":"store4","1139":"store5","1145":"store1","1158":"store2","1162":"store3","1164":"store4","1199":"store5","1205":"store1","1218":"store2","1222":"store3","1224":"store4","1259":"store5","1265":"store1","1278":"store2","1282":"store3","1284":"store4","1319":"store5","1325":"store1","1338":"store2","1342":"store3","1344":"store4","1379":"store5","1385":"store1","1398":"store2","1402":"store3","1404":"store4","1439":"store5","1445":"store1","1458":"store2","1462":"store3","1464":"store4","1499":"store5","1505":"store1","1518":"store2","1522":"store3","1524":"store4","1559":"store5","1565":"store1","1578":"store2","1582":"store3","1584":"store4","1619":"store5"},"Rank":{"5":1.0,"18":1.0,"22":1.0,"24":1.0,"59":1.0,"65":2.0,"78":2.0,"82":2.0,"84":2.0,"119":2.0,"125":2.0,"138":2.0,"142":2.0,"144":2.0,"179":2.0,"185":2.0,"198":2.0,"202":2.0,"204":2.0,"239":2.0,"245":2.0,"258":2.0,"262":2.0,"264":2.0,"299":2.0,"305":2.0,"318":2.0,"322":2.0,"324":2.0,"359":2.0,"365":2.0,"378":2.0,"382":2.0,"384":1.0,"419":2.0,"425":3.0,"438":1.0,"442":3.0,"444":2.0,"479":3.0,"485":4.0,"498":1.0,"502":4.0,"504":3.0,"539":4.0,"545":4.0,"558":1.0,"562":3.0,"564":3.0,"599":4.0,"605":5.0,"618":1.0,"622":2.0,"624":4.0,"659":5.0,"665":6.0,"678":1.0,"682":2.0,"684":5.0,"719":6.0,"725":7.0,"738":1.0,"742":2.0,"744":5.0,"779":7.0,"785":8.0,"798":1.0,"802":2.0,"804":6.0,"839":8.0,"845":8.0,"858":1.0,"862":2.0,"864":5.0,"899":8.0,"905":8.0,"918":1.0,"922":2.0,"924":4.0,"959":8.0,"965":8.0,"978":1.0,"982":2.0,"984":4.0,"1019":8.0,"1025":10.0,"1038":1.0,"1042":2.0,"1044":5.0,"1079":10.0,"1085":10.0,"1098":1.0,"1102":2.0,"1104":5.0,"1139":10.0,"1145":11.0,"1158":1.0,"1162":2.0,"1164":5.0,"1199":11.0,"1205":12.0,"1218":1.0,"1222":2.0,"1224":6.0,"1259":12.0,"1265":13.0,"1278":2.0,"1282":1.0,"1284":7.0,"1319":13.0,"1325":13.0,"1338":2.0,"1342":1.0,"1344":6.0,"1379":13.0,"1385":14.0,"1398":2.0,"1402":1.0,"1404":6.0,"1439":14.0,"1445":3.0,"1458":2.0,"1462":1.0,"1464":6.0,"1499":8.0,"1505":3.0,"1518":2.0,"1522":1.0,"1524":6.0,"1559":4.0,"1565":3.0,"1578":2.0,"1582":1.0,"1584":8.0,"1619":5.0}}' Dataframe: df_slim = pd.read_json(data) Chart: highlight = alt.selection(type='single', on='mouseover', fields=['Store'], nearest=True, empty="none") chart = alt.Chart(df_slim).mark_line().encode( x='Date', y='Rank', #color='Store', strokeDash='Store', color=alt.condition(highlight, 'Store', alt.value("lightgray")), tooltip=['Rank','Store'] ).properties( width=800, height=600, title='Bump Chart: Store Ranking' ).configure_title( fontSize=30, font='Courier', anchor='start', color='gray' ).add_selection( highlight ) display(chart) Output: Any help? Not sure what went wrong here.
Good question! It turns out this is one of the current limitations of Vega-Lite. I found this note in the VL docs on Nearest Value The nearest transform is not supported for continuous mark types (i.e., line and area). For these mark types, consider layering a discrete mark type (e.g., point) with a 0-value opacity So for your example I would do something like this highlight = alt.selection(type='single', on='mouseover', fields=['Store'], nearest=True, empty="none") chart = alt.Chart(df_slim).mark_line().encode( x='Date', y='Rank', #color='Store', strokeDash='Store', color=alt.condition(highlight, 'Store', alt.value("lightgray")), tooltip=['Rank','Store'] ) points = alt.Chart(df_slim).mark_point(opacity=0).encode( x='Date', y='Rank',).add_selection( highlight ) chart + points
Altair slider transform data
I've been enjoying using Altair for a couple of weeks now but I'm stuck on how to solve a problem. I've been trying to do a simple plot of average temp data vs. month and using a slider widget to filter though the years. I can get the plot to work but as soon as I use the slider option it doesn't show any data. I tried just using the selection option but that didn't work. I just don't know how to handle the transform option. I use the US Population Over Time example as a guide. import altair as alt from altair.expr import datum, if_ alt.renderers.enable('notebook') path = 'https://raw.githubusercontent.com/SpiritR/datpr6754/master/prtas_1901_2015.csv' slider = alt.binding_range(min=1900, max=2020, step=10) year = alt.selection_single(name="year", fields=['Year'], bind=slider) alt.Chart(path).mark_bar().encode( alt.X('Month_Name:O'), alt.Y('tas:Q', scale=alt.Scale(domain=(20, 28))), ).properties( width=900, height=300, ).add_selection( year ).transform_calculate( ???? ).transform_filter( year.ref() )
The CSV data are being parsed as strings rather than numbers. When you use the slider to select a date (say 1959) it is filters the data to check which values are equal to that... and since the data are strings, "1959" != 1959 and the resulting subset is empty. You can force the column to be parsed as a number, and then the slider will work correctly. For example: import altair as alt alt.renderers.enable('notebook') path = 'https://raw.githubusercontent.com/SpiritR/datpr6754/master/prtas_1901_2015.csv' data = alt.UrlData(url=path, format=alt.CsvDataFormat(parse={'Year': 'number'})) slider = alt.binding_range(min=1901, max=2015, step=1) year = alt.selection_single(name="year", fields=['Year'], bind=slider) alt.Chart(data).mark_bar().encode( alt.X('Month_Name:O'), alt.Y('tas:Q', scale=alt.Scale(domain=(20, 28))), ).properties( width=900, height=300, ).add_selection( year ).transform_filter( year )