Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x_origin and y_origin are off by 1/2 a step size #21

Open
pfbuxton opened this issue Aug 28, 2024 · 0 comments
Open

x_origin and y_origin are off by 1/2 a step size #21

pfbuxton opened this issue Aug 28, 2024 · 0 comments

Comments

@pfbuxton
Copy link

Hello. This is a nice and useful crate.

I found that x_origin and y_origin are off by 1/2 a step size. You could either change how the API works or keep it as is and add extra documentation.

Here is a reproducible example, the important parts are .x_origin(x[0] - d_x/2.0) and .y_origin(y[0] - d_y/2.0)

src/main.rs

use contour::ContourBuilder;
use ndarray::{Array1, Array2};


fn main() {
    let n_x: usize = 10;
    let n_y: usize = 9;
    let x: Array1<f64> = ndarray::Array1::linspace(0.0, 1.0, n_x);
    let y: Array1<f64> = ndarray::Array1::linspace(0.0, 1.0, n_y);
    let d_x = x[1] - x[0];
    let d_y = y[1] - y[0];

    let mut h: Array2<f64> = Array2::zeros((n_y, n_x));

    for i_x in 0..n_x {
        for i_y in 0..n_y {
            h[[i_y, i_x]] = x[i_x] * y[i_y];
        }
    }

    let c: ContourBuilder = ContourBuilder::new(n_x, n_y, true) // x dim., y dim., smoothing
        .x_step(d_x)
        .y_step(d_y)
        .x_origin(x[0] - d_x/2.0)
        .y_origin(y[0] - d_y/2.0);

    let h_flattened: Vec<f64> = h.iter().cloned().collect();

    let contour_results: Vec<contour::Contour> = c.contours(&h_flattened, &[0.5]).unwrap(); // values, thresholds

    let first_contour = contour_results[0].geometry(); // The [0] is because we have only supplied one threshold

    // Start with an empty Vec
    let mut x_contour: Vec<f64> = Vec::new();
    let mut y_contour: Vec<f64> = Vec::new();

    for polygon in first_contour.iter() {
        for coord in polygon.exterior().coords() {
            x_contour.push(coord.x);
            y_contour.push(coord.y);
        }
    }

    let x_contour: Array1<f64> = Array1::from_vec(x_contour);
    let y_contour: Array1<f64> = Array1::from_vec(y_contour);

    println!("{}", x_contour);
    println!("{}", y_contour);

}

Cargo.toml

[package]
name = "contour_example"
version = "0.1.0"
edition = "2021"

[dependencies]
contour = "0.13.1"
ndarray = "0.16.1"

and comparing with Python (doing a copy and paste from the rust prtinln):

import matplotlib.pyplot as plt
import numpy as np

n_x = 10
n_y = 9
x = np.linspace(0.0, 1.0, n_x)
y = np.linspace(0.0, 1.0, n_y)

h = np.zeros([n_y, n_x])
for i_x in range(0, n_x):
    for i_y in range(0, n_y):
        h[i_y, i_x] = x[i_x] * y[i_y]

plt.contour(x, y, h, [0.5], colors="blue")

# Plot the rust result
x_rust = [1.0555555555555556, 1.0555555555555556, 1.0555555555555556, 1.0555555555555556, 1.0555555555555556, 1, 1, 0.8888888888888888, 0.8, 0.7777777777777777, 0.6666666666666666, 0.6666666666666666, 0.5714285714285713, 0.5555555555555555, 0.5, 0.5555555555555555, 0.6666666666666666, 0.7777777777777777, 0.8888888888888888, 1, 1.0555555555555556]
y_rust = [1, 0.875, 0.75, 0.625, 0.5, 0.5, 0.5, 0.5625, 0.625, 0.6428571428571429, 0.75, 0.75, 0.875, 0.8999999999999999, 1, 1.0625, 1.0625, 1.0625, 1.0625, 1.0625, 1]
plt.plot(x_rust, y_rust, linestyle="--", color="red")

plt.savefig('python_vs_rust.svg')

and we get this figure:
python_vs_rust

There is something a bit odd with the points which are at the boundary as they are now at the boundary + 1/2 step size, which is now outside the grid!

Thanks,
Peter

Repository owner deleted a comment Aug 28, 2024
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

No branches or pull requests

1 participant