Skip to content

fix: preserve paired series fill boundaries#31

Open
zao111222333 wants to merge 1 commit into
donkeyteethUX:mainfrom
zao111222333:main
Open

fix: preserve paired series fill boundaries#31
zao111222333 wants to merge 1 commit into
donkeyteethUX:mainfrom
zao111222333:main

Conversation

@zao111222333

@zao111222333 zao111222333 commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Previously, series-to-series fills were first reduced to strictly increasing x coordinates before interpolation. This dropped duplicate x values and could flatten or remove vertical step edges, producing incorrect filled regions for step-like boundaries. It also could not represent boundaries that are naturally paired by y instead of x.

This PR updates fill generation so that:

  • equal-length series with matching paired x coordinates are filled segment-by-segment
  • equal-length series with matching paired y coordinates are also filled segment-by-segment
  • duplicate coordinates and vertical step edges are preserved
  • non-paired series still use the existing monotonic x interpolation fallback

Demo

Before:

Screenshot 2026-06-28 at 01 57 36

Now:

Screenshot 2026-06-28 at 01 57 12

Demo code:

//! Demonstrates fill regions between paired series boundaries.
use iced::Element;
use iced_plot::{
    Color, Fill, LineStyle, MarkerStyle, PlotUiMessage, PlotWidget, PlotWidgetBuilder, Series,
};

fn main() -> iced::Result {
    iced::application(new, update, view)
        .font(include_bytes!("fonts/FiraCodeNerdFont-Regular.ttf"))
        .default_font(iced::Font::with_name("FiraCode Nerd Font"))
        .run()
}

fn update(widget: &mut PlotWidget, message: PlotUiMessage) {
    widget.update(message);
}

fn view(widget: &PlotWidget) -> Element<'_, PlotUiMessage> {
    widget.view()
}

fn new() -> PlotWidget {
    let step_lower_positions = vec![
        [0.0, 0.0],
        [1.0, 0.0],
        [1.0, 0.7],
        [2.0, 0.7],
        [2.0, 0.25],
        [3.0, 0.25],
        [3.0, 1.05],
        [4.0, 1.05],
        [4.0, 0.55],
        [5.0, 0.55],
        [5.0, 1.35],
        [6.0, 1.35],
    ];
    let step_upper_positions: Vec<[f64; 2]> = step_lower_positions
        .iter()
        .map(|p| [p[0], p[1] + 1.05])
        .collect();

    let left_positions = vec![
        [7.0, -0.25],
        [7.7, -0.25],
        [7.7, 0.55],
        [7.2, 0.55],
        [7.2, 1.35],
        [7.9, 1.35],
        [7.9, 2.15],
        [7.4, 2.15],
    ];
    let right_positions: Vec<[f64; 2]> =
        left_positions.iter().map(|p| [p[0] + 0.9, p[1]]).collect();

    let step_lower = Series::line_only(
        step_lower_positions,
        LineStyle::solid().with_pixel_width(2.5),
    )
    .with_marker_style(MarkerStyle::circle(3.5))
    .with_color(Color::from_rgb(0.1, 0.45, 0.95))
    .with_label("step lower");
    let step_upper = Series::line_only(
        step_upper_positions,
        LineStyle::solid().with_pixel_width(2.5),
    )
    .with_marker_style(MarkerStyle::circle(3.5))
    .with_color(Color::from_rgb(0.95, 0.35, 0.1))
    .with_label("step upper");
    let step_fill = Fill::new(step_lower.id, step_upper.id)
        .with_color(Color::from_rgba(0.15, 0.6, 0.95, 0.24))
        .with_label("paired x fill");

    let left_boundary = Series::line_only(left_positions, LineStyle::solid().with_pixel_width(2.5))
        .with_marker_style(MarkerStyle::square(3.8))
        .with_color(Color::from_rgb(0.15, 0.62, 0.3))
        .with_label("left boundary");
    let right_boundary =
        Series::line_only(right_positions, LineStyle::solid().with_pixel_width(2.5))
            .with_marker_style(MarkerStyle::square(3.8))
            .with_color(Color::from_rgb(0.6, 0.28, 0.82))
            .with_label("right boundary");
    let side_fill = Fill::new(left_boundary.id, right_boundary.id)
        .with_color(Color::from_rgba(0.3, 0.75, 0.45, 0.24))
        .with_label("paired y fill");

    PlotWidgetBuilder::new()
        .with_x_lim(-0.3, 9.2)
        .with_y_lim(-0.8, 3.2)
        .with_x_label("x")
        .with_y_label("y")
        .add_series(step_lower)
        .add_series(step_upper)
        .add_series(left_boundary)
        .add_series(right_boundary)
        .add_fill(step_fill)
        .add_fill(side_fill)
        .with_cursor_overlay(true)
        .with_crosshairs(true)
        .build()
        .unwrap()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant