vega-litealtair

Table with multi-line strings in Altair


I was trying to write a table with some entries being multi-line using altair, but seem to get into trouble with fixing line spacing. For example:

text_df = pd.DataFrame({"a":["very very very very long thing", "very very very very very long thing"]})
text_chart_base = alt.Chart(text_df).transform_window(row_number="row_number()").transform_calculate(
    y=f"split(datum.a, ' ')"
    ).mark_text(align="left", baseline="top"
    ).encode(y=alt.Y("row_number:N", axis=None, scale=alt.Scale(reverse=True)))
col1 = text_chart_base.encode(text=f"y:N")
col2= text_chart_base.encode(text=f"row_number:N")
col1 | col2

gives me overlapping multi-line strings

enter image description here

Instead when I make the row_number Quantitative with encode(y=alt.Y("row_number:Q", axis=None, scale=alt.Scale(reverse=True))), I get too much space between the strings

enter image description here

Is there a way I can get mark_text to give the right row spacing between rows? (That is, an output something like the following)

enter image description here


Solution

  • You can set the overall height of the chart or the height per tick/step, e.g.:

    import altair as alt
    import pandas as pd
    
    text_df = pd.DataFrame({"a":["one two three four", "A B", "1 2"]})
    text_chart_base = alt.Chart(text_df, height=alt.Step(60)).transform_window(
        row_number="row_number()"
    ).transform_calculate(
        y="split(datum.a, ' ')",
    ).mark_text(
        align="left",
        baseline="bottom"
    ).encode(
        y=alt.Y("row_number:O")
    )
    
    col1 = text_chart_base.encode(text="y:N")
    col2 = text_chart_base.encode(text="row_number:N")
    col1 | col2
    

    enter image description here

    As you can see the spacing is not adaptive to the content but static per position, so there will be a gap between the second on third row. I think it should be possible to fix this by setting the step height to be applied per offset instead of per tick position, but I couldn't get something like this to work:

    text_df = pd.DataFrame({"a":["one two three four", "A B", "1 2"]})
    text_chart_base = alt.Chart(text_df, height=alt.Step(70, **{'for': 'offset'})).transform_window(
        row_number="row_number()"
    ).transform_calculate(
        y="split(datum.a, ' ')",
        offset="length(datum.y)"
    ).mark_text(
        align="left",
        baseline="bottom"
    ).encode(
        y=alt.Y("row_number:O"),
        yOffset=alt.Y("offset:Q")
    )
    
    col1 = text_chart_base.encode(text="y:N")
    col2 = text_chart_base.encode(text="offset:N")
    col1 | col2