Skip to content

Long legend labels overflow out of the legend box #35

@ilya-zlobintsev

Description

@ilya-zlobintsev

When using series labels that are very long, at some point the legend box size stops scaling correctly with the text size, causing it to overflow.

Example chart drawn with the plotters-cairo backend:
Image

Same chart, but with the bitmap backend (no overflow here):
Image

I did some basic debugging, and it seems like plotters does not call estimate_text_size on the backend for the legend labels, and instead calculates text dimensions internally based on the font. Perhaps the estimated text size ends up being different from what it actually is in draw_text on the backend?

Chart code to reproduce this:

fn plot_pdf<'a, DB: DrawingBackend + 'a>(backend: DB) -> Result<(), Box<dyn Error + 'a>> {
    let root = backend.into_drawing_area();

    root.fill(&WHITE)?;

    let root_area = root.titled("Image Title", ("noto-sans", 60))?;

    let x_axis = (-3.4f32..3.4).step(0.1);

    let mut cc = ChartBuilder::on(&root_area)
        .margin(5)
        .set_all_label_area_size(50)
        .caption("Sine and Cosine", ("noto-sans", 40))
        .build_cartesian_2d(-3.4f32..3.4, -1.2f32..1.2f32)?;

    cc.configure_mesh()
        .x_labels(20)
        .y_labels(10)
        .disable_mesh()
        .x_label_formatter(&|v| format!("{:.1}", v))
        .y_label_formatter(&|v| format!("{:.1}", v))
        .draw()?;

    cc.draw_series(LineSeries::new(x_axis.values().map(|x| (x, x.sin())), &RED))?
        .label("Sine")
        .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], RED));

    cc.draw_series(LineSeries::new(
        x_axis.values().map(|x| (x, x.cos())),
        &BLUE,
    ))?
    .label("An extremely long description of what a Cosine is that overflows")
    .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], BLUE));

    cc.configure_series_labels()
        .border_style(BLACK)
        .label_font(("noto-sans", 14))
        .draw()?;

    // Otherwise you can use a function to construct your pointing element yourself
    cc.draw_series(PointSeries::of_element(
        (-3.0f32..2.1f32).step(1.0).values().map(|x| (x, x.sin())),
        5,
        ShapeStyle::from(&RED).filled(),
        &|coord, size, style| {
            EmptyElement::at(coord)
                + Circle::new((0, 0), size, style)
                + Text::new(format!("{:?}", coord), (0, 15), ("noto-sans", 15))
        },
    ))?;

    root.present()?;
    Ok(())
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions