def get_segments(self): """ Adaptively gets segments for plotting. The adaptive sampling is done by recursively checking if three points are almost collinear. If they are not collinear, then more points are added between those points. References ========== [1] Adaptive polygonal approximation of parametric curves, Luiz Henrique de Figueiredo. """ f_x = lambdify([self.var], self.expr_x) f_y = lambdify([self.var], self.expr_y) list_segments = [] def sample(param_p, param_q, p, q, depth): """ Samples recursively if three points are almost collinear. For depth < 6, points are added irrespective of whether they satisfy the collinearity condition or not. The maximum depth allowed is 12. """ #Randomly sample to avoid aliasing. random = 0.45 + np.random.rand() * 0.1 param_new = param_p + random * (param_q - param_p) xnew = f_x(param_new) ynew = f_y(param_new) new_point = np.array([xnew, ynew]) #Maximum depth if depth > 12: list_segments.append([p, q]) #Sample irrespective of whether the line is flat till the #depth of 6. We are not using linspace to avoid aliasing. elif depth < 6: sample(param_p, param_new, p, new_point, depth + 1) sample(param_new, param_q, new_point, q, depth + 1) #Sample ten points if complex values are encountered #at both ends. If there is a real value in between, then #sample those points further. elif ((p[0] is None and q[1] is None) or (p[1] is None and q[1] is None)): param_array = np.linspace(param_p, param_q, 10) x_array = map(f_x, param_array) y_array = map(f_y, param_array) if any(x is not None and y is not None for x, y in zip(x_array, y_array)): for i in len(y_array) - 1: if ((x_array[i] is not None and y_array[i] is not None) or (x_array[i+1] is not None and y_array[i] is not None)): point_a = [x_array[i], y_array[i]] point_b = [x_array[i + 1], y_array[i + 1]] sample(param_array[i], param_array[i], point_a, point_b, depth + 1) #Sample further if one of the end points in None( ie a complex #value) or the three points are not almost collinear. elif (p[0] is None or p[1] is None or q[1] is None or q[0] is None or not flat(p, new_point, q)): sample(param_p, param_new, p, new_point, depth + 1) sample(param_new, param_q, new_point, q, depth + 1) else: list_segments.append([p, q]) f_start_x = f_x(self.start) f_start_y = f_y(self.start) start = [f_start_x, f_start_y] f_end_x = f_x(self.end) f_end_y = f_y(self.end) end = [f_end_x, f_end_y] sample(self.start, self.end, start, end, 0) return list_segments
def get_segments(self): """ Adaptively gets segments for plotting. The adaptive sampling is done by recursively checking if three points are almost collinear. If they are not collinear, then more points are added between those points. References ========== [1] Adaptive polygonal approximation of parametric curves, Luiz Henrique de Figueiredo. """ if self.only_integers: return super(LineOver1DRangeSeries, self).get_segments() else: f = lambdify([self.var], self.expr) list_segments = [] def sample(p, q, depth): """ Samples recursively if three points are almost collinear. For depth < 6, points are added irrespective of whether they satisfy the collinearity condition or not. The maximum depth allowed is 12. """ #Randomly sample to avoid aliasing. random = 0.45 + np.random.rand() * 0.1 xnew = p[0] + random * (q[0] - p[0]) ynew = f(xnew) new_point = np.array([xnew, ynew]) #Maximum depth if depth > 12: list_segments.append([p, q]) #Sample irrespective of whether the line is flat till the #depth of 6. We are not using linspace to avoid aliasing. elif depth < 6: sample(p, new_point, depth + 1) sample(new_point, q, depth + 1) #Sample ten points if complex values are encountered #at both ends. If there is a real value in between, then #sample those points further. elif p[1] is None and q[1] is None: xarray = np.linspace(p[0], q[0], 10) yarray = map(f, xarray) if any(y is not None for y in yarray): for i in len(yarray) - 1: if yarray[i] is None or yarray[i + 1] is None: sample([xarray[i], yarray[i]], [xarray[i + 1], yarray[i + 1]], depth + 1) #Sample further if one of the end points in None( i.e. a complex #value) or the three points are not almost collinear. elif p[1] is None or q[1] is None or not flat(p, new_point, q): sample(p, new_point, depth + 1) sample(new_point, q, depth + 1) else: list_segments.append([p, q]) f_start = f(self.start) f_end = f(self.end) sample([self.start, f_start], [self.end, f_end], 0) return list_segments