altair
altair copied to clipboard
Make it easy to create arbitrary text box
I'm often making graphs where I would like to list the parameters used to create the graph, for example:
scale_constant = 28.3 median_shift = 12.3 frequency = 93.2
I found this ticket which was talks about it:
https://github.com/altair-viz/altair/issues/984
and this SO question:
https://stackoverflow.com/questions/61277181/adding-r-value-correlation-to-scatter-chart-in-altair
But didn't see a clean solution. It would be great if something like this was possible:
altair.text_box(text=""" scale_constant = 28.3 median_shift = 12.3 frequency = 93.2 """, location="top_right")
or something along those lines. If HTML was supported, that'd be great too.
To be clear, this stuff isn't related to specific data-points, doesn't belong in the title, and doesn't belong in the legend. It belongs in a box (ideally with a different background color than the graph) that is overlayed onto the graph somewhere where it doesn't occlude the graph data.
It occurs to me I could create a box with a div in HTML, and overlay it onto the graph with CSS, but this seems hokey. But perhaps if there was an easy way to specify the overlay onto one of the four corners of the graph this would work. Perhaps someone has an example of this already?
A text box function would have to be added to Vega-Lite before it can be added to Altair. You can check if there is an open issue about it on their tracker or start a new one. Note that it is already possible to do what you want by combining mark_text
and mark_rect
. With the example you linked to:
import altair as alt
from vega_datasets import data
cars = data.cars()
chart = alt.Chart(cars).mark_circle().encode(
alt.X('Miles_per_Gallon', scale=alt.Scale(domain=(5,50))),
y='Weight_in_lbs')
corl = cars[['Miles_per_Gallon','Weight_in_lbs']].corr().iloc[0,1]
text = alt.Chart({'values':[{}]}).mark_text(
align="left", baseline="top"
).encode(
x=alt.value(5), # pixels from left
y=alt.value(5), # pixels from top
text=alt.value([f"r: {corl:.3f}", 'Line 2']))
box = alt.Chart({'values':[{}]}).mark_rect(stroke='black', color='orange').encode(
x=alt.value(3),
x2=alt.value(50),
y=alt.value(3),
y2=alt.value(30))
chart + box + text + chart.transform_regression('Miles_per_Gallon','Weight_in_lbs').mark_line()
Fantastic, thank you! I guess the advantage of a built-in command is that the rectangle size could be auto-calculated, and that it could be done in fewer steps, eh?
I will check that this enhancement request is in Vega-lite, and will link to this answer, thank you!
Posted here:
https://github.com/vega/vega-lite/issues/7376
Circling back on this, since Vega-lite already supports this with reactive geometries (see thread: https://github.com/vega/vega-lite/issues/7376) . Can we make so this can easily be done in Altair?
A text box function would have to be added to Vega-Lite before it can be added to Altair. You can check if there is an open issue about it on their tracker or start a new one. Note that it is already possible to do what you want by combining
mark_text
andmark_rect
. With the example you linked to:import altair as alt from vega_datasets import data cars = data.cars() chart = alt.Chart(cars).mark_circle().encode( alt.X('Miles_per_Gallon', scale=alt.Scale(domain=(5,50))), y='Weight_in_lbs') corl = cars[['Miles_per_Gallon','Weight_in_lbs']].corr().iloc[0,1] text = alt.Chart({'values':[{}]}).mark_text( align="left", baseline="top" ).encode( x=alt.value(5), # pixels from left y=alt.value(5), # pixels from top text=alt.value([f"r: {corl:.3f}", 'Line 2'])) box = alt.Chart({'values':[{}]}).mark_rect(stroke='black', color='orange').encode( x=alt.value(3), x2=alt.value(50), y=alt.value(3), y2=alt.value(30)) chart + box + text + chart.transform_regression('Miles_per_Gallon','Weight_in_lbs').mark_line()
Thanks for providing this example! I noticed that the text from the text box is not selectable, is there a way to change this?
@masta-g3 I don't think the text is selectable in any Vega-Lite chart, at least not in the Vega Editor or Jupyter Lab. You can try with the examples here https://vega.github.io/vega-lite/examples/. You could always right click and view the source of the page to select it or save an svg
Hello,
What if, e.g. my x axis was a text category? How could I give the coordinates of that string?
In particular:
x=alt.value(5), # pixels from left. y=alt.value(5), # pixels from top
should be replaced, do you guys know how?
@ccsuehara alt.value
specifies the number of pixels in the charts so it should work regardless of what data type you have on the x-axis. Could you include the code for a complete reproducible example with your data included that shows the issue you are encountering?
@dsandber I am going through a few of the older issues and taking a second look at the reply you got from the Vega-Lite devs indicated that this is not yet supported in Vega-Lite (the reactive geometries are present in Vega, but not Vega-Lite):
To draw the box, you would still need some way to generate a reactive geometry (the box size depends on the size of the text). It could be part of annotations such as https://github.com/vega/vega-lite/pull/3401. Alternatively, Vega could add a text background color (and padding) option to text marks.
I am closing this as there is nothing we can do about this on the altair side of things, following https://github.com/vega/vega-lite/pull/3401 or similar issues in the Vega-Lite repo would be the best way to know when a feature like this might end up in Altair.