davidfokkema / artist

Artist makes beautiful plots
http://davidfokkema.github.io/artist/
GNU General Public License v3.0
12 stars 2 forks source link

Relative position does not work for multi-valued series #21

Closed davidfokkema closed 9 years ago

davidfokkema commented 9 years ago

If you try to plot a circle or ellipse, and add a pin at relative_position=.5, the x-coordinate is interpolated and that value is used to interpolate the y-coordinate. The resulting value for y, however, is the first one in the series and not halfway in the series. The pin ends up at the wrong spot. We need to fix this.

153957 commented 9 years ago

The function in question: _calc_position_for_pin

The problem is in:

x0, x1 = x[0], x[-1]
xs = relative_position * (x1 - x0) + x0

Because if the start and end x values are equal you always get xs = x0. So relative position assumes the x values are continuously increasing/decreasing values.

The question is, what should we assume about the spread of/steps between the data points? And should relative_position be relative to the data points or to the start/end value of the data.

For example: if x = [0, 1, 3], should relative_position = .5 mean x value 1 (half way through the data points) or x value 1.5 (half way between the start and end points)? And relative_position = .6667 would be something like this (if y = x):

l1 = len(x) - 1
idx = int(l1 * relative_position)
part = idx / float(l1)
x0 = x[idx]
x1 = x[idx + 1]
xs = (relative_position - part) * (x1 - x0) + x0
ys = np.interp(xs, x, y)
# ys = 1.334

This should work fine for cricles and ellipses. However, it would work best/most predictable if the length of the paths between data points is evenly distributed.. The problem is that you can not easily determine the speed at which the data moves from one point to the next..

It's hard to think of one solution for all cases..

davidfokkema commented 9 years ago

Yes, it's hard! Nice summary. Ideally, it should be (in my opinion) halfway along the path. But then you must know the path length. That may be approximated by piecewise linear interpolation, since the path is usually drawn with linear segments.

153957 commented 9 years ago

Total length is 'easy'

length = sum(sqrt((x[i] - x[i - 1]) ** 2 + (y[i] - y[i - 1]) ** 2)
             for i in range(1, len(x)))

But then you need to find the point where you are at a fraction (relative_position) of that length.. Perhaps numpy.cumsum can help..

153957 commented 9 years ago

See #23. Is that what you had in mind?

davidfokkema commented 9 years ago

This is exactly what I had in mind. Nice implementation, as well!

153957 commented 9 years ago

Fixed by #23. (Only need to decide on handling for log plots)