oxyplot icon indicating copy to clipboard operation
oxyplot copied to clipboard

`LineAnnotation` `X` and `Y` are ignored for sloped lines

Open colejohnson66 opened this issue 3 years ago • 8 comments

Steps to reproduce

  1. Add an annotation as per below.
  2. Observe it ignoring X and passing through (0, 0).
ChartModel.Annotations.Add(new LineAnnotation
{
    Slope = 2,
    X = 5,
});

Expected behaviour

Setting X and Slope will give me an offset line.

Actual behaviour

It doesn't. I get a line with the correct slope, but passing through (0, 0), not (X, 0).

The documentation even mentions this issue by saying that X is ignored unless the line is Type == Vertical, and Y is ignored unless Type == Horizontal.

colejohnson66 avatar Jun 30 '22 18:06 colejohnson66

I see I can do Type = LinearEquation, but I think the system could be simplified. If you want a horizontal line, set Slope to 0, and if you want a vertical one, set it to double.PositiveInfinity.

colejohnson66 avatar Jun 30 '22 18:06 colejohnson66

@colejohnson66 you need to use the Intercept property in combination with Slope to specify the intercept for a linear LineAnnotation

VisualMelon avatar Jun 30 '22 18:06 VisualMelon

Yeah. I figured that out. I still think it'd be nice to have a line annotation where I go, "Here's X, Y, and Slope. Figure out what line gives b in Y = Slope * X + b"

colejohnson66 avatar Jun 30 '22 18:06 colejohnson66

It doesn't seem too hard. I'd be willing to make a patch that would allow that, but I don't think it'd be wise to break the API of LineAnnotation. Any ideas?

colejohnson66 avatar Jun 30 '22 18:06 colejohnson66

(hurried thoughts) I could image that as a convenience method somewhere; OxyPlot doesn't have a whole lot of such convenience methods, but I don't think it would suffer if there were a few more.

My main concern with baking this into the class itself would be that it will create even more confusion than the current design, as we'll need to spec what happens when e.g. Intercept and X or Y are non-NaN, and that's going to be messy. Personally I don't like using infinity for this sort of thing, but that's probably just me.

The existing API has another issue: the terms Horizontal and Vertical are a bit fuzzy now anyway, given they really mean X or Y aligned.

VisualMelon avatar Jun 30 '22 19:06 VisualMelon

I think infinity is ugly too, but that's how it was taught to me in school: a vertical line is just one with an infinite slope.

As for a convenience function, where would it go and what would it be called?

colejohnson66 avatar Jun 30 '22 19:06 colejohnson66

As for a convenience function, where would it go and what would it be called?

I don't know; I'm afraid my imagination is pretty limited. I feel like AnnotationHelpers could be a thing, but probably not justifiable for a single static method.

An overhaul of LineAnnotation might be a reasonable thing for 3.0, but my instinct is that the current API isn't bad enough to break or otherwise convolute it. Might be worth looking at other packages to see what is generally expected. My inclination at the moment is to leave it as-is.

VisualMelon avatar Jun 30 '22 19:06 VisualMelon

I wonder if it could be reworked so Type == LinearEquation could use either Intercept or X and Y? So initially, all would be double.NaN, then when rendering, if the type is LinearEquation, it figures out what to use?

double intercept = Intercept;
if (double.IsNaN(yIntercept))
{
    if (double.IsNaN(Slope) || double.IsNaN(X) || double.IsNaN(Y))
    { /* error? */ }
    intercept = Y - Slope * X;
}

I don't think initializing to NaN would break the API, but I'm probably wrong. If you feel it's not worth it, feel free to close this issue.

colejohnson66 avatar Jul 01 '22 13:07 colejohnson66