def check_4(self,f=f1,per=0,s=0,a=0,b=2*pi,N=20,xb=None,xe=None, ia=0,ib=2*pi,dx=0.2*pi): if xb is None: xb=a if xe is None: xe=b x=a+(b-a)*arange(N+1,dtype=float)/float(N) # nodes x1=a+(b-a)*arange(1,N,dtype=float)/float(N-1) # middle points of the nodes v,v1=f(x),f(x1) nk=[] put(" u = %s N = %d"%(repr(round(dx,3)),N)) put(" k : [x(u), %s(x(u))] Error of splprep Error of splrep "%(f(0,None))) for k in range(1,6): tckp,u=splprep([x,v],s=s,per=per,k=k,nest=-1) tck=splrep(x,v,s=s,per=per,k=k) uv=splev(dx,tckp) err1 = abs(uv[1]-f(uv[0])) err2 = abs(splev(uv[0],tck)-f(uv[0])) assert_(err1 < 1e-2) assert_(err2 < 1e-2) put(" %d : %s %.1e %.1e"%\ (k,repr([round(z,3) for z in uv]), err1, err2)) put("Derivatives of parametric cubic spline at u (first function):") k=3 tckp,u=splprep([x,v],s=s,per=per,k=k,nest=-1) for d in range(1,k+1): uv=splev(dx,tckp,d) put(" %s "%(repr(uv[0])))
def check_4(self,f=f1,per=0,s=0,a=0,b=2*pi,N=20,xb=None,xe=None, ia=0,ib=2*pi,dx=0.2*pi): if xb is None: xb = a if xe is None: xe = b x = a+(b-a)*arange(N+1,dtype=float)/float(N) # nodes x1 = a + (b-a)*arange(1,N,dtype=float)/float(N-1) # middle points of the nodes v,v1 = f(x),f(x1) put(" u = %s N = %d" % (repr(round(dx,3)),N)) put(" k : [x(u), %s(x(u))] Error of splprep Error of splrep " % (f(0,None))) for k in range(1,6): tckp,u = splprep([x,v],s=s,per=per,k=k,nest=-1) tck = splrep(x,v,s=s,per=per,k=k) uv = splev(dx,tckp) err1 = abs(uv[1]-f(uv[0])) err2 = abs(splev(uv[0],tck)-f(uv[0])) assert_(err1 < 1e-2) assert_(err2 < 1e-2) put(" %d : %s %.1e %.1e" % (k,repr([round(z,3) for z in uv]), err1, err2)) put("Derivatives of parametric cubic spline at u (first function):") k = 3 tckp,u = splprep([x,v],s=s,per=per,k=k,nest=-1) for d in range(1,k+1): uv = splev(dx,tckp,d) put(" %s " % (repr(uv[0])))
def fitEdge(og,e,VERBOSE=False): path = og[e[0]][e[1]]['wpath'] #pstart=og.node[e[0]]['wcrd'] #pend = og.node[e[1]]['wcrd'] #path.extend([pend]) #p = [pstart] #p.extend(path) ae = np.array(path) if( ae.shape[0] > 3 ): # there are not enough points to fit with if( VERBOSE ): print("refitting edge with %d points"%len(path)) s = ae.shape[0]/2.0 fit2 = splprep(ae.transpose(),task=0,full_output =1, s=s)[0] u = np.array(list(range(ae.shape[0]+1))).\ astype(np.float64)/(ae.shape[0]) # location of spline points og[e[0]][e[1]]['d0'] = splev(u,fit2[0],der=0) # first derivative (tangent) of spline og[e[0]][e[1]]['d1'] =np.array( splev(u,fit2[0],der=1)) # second derivative (curvature) of spline og[e[0]][e[1]]['d2'] = np.array(splev(u,fit2[0],der=2)) else: if( VERBOSE ): print("no or insufficient points to fit") og[e[0]][e[1]]['d0'] = None og[e[0]][e[1]]['d1'] = None og[e[0]][e[1]]['d2'] = None
def fitEdge(og, e, VERBOSE=False): path = og[e[0]][e[1]]['wpath'] #pstart=og.node[e[0]]['wcrd'] #pend = og.node[e[1]]['wcrd'] #path.extend([pend]) #p = [pstart] #p.extend(path) ae = np.array(path) if (ae.shape[0] > 3): # there are not enough points to fit with if (VERBOSE): print("refitting edge with %d points" % len(path)) s = ae.shape[0] / 2.0 fit2 = splprep(ae.transpose(), task=0, full_output=1, s=s)[0] u = np.array(list(range(ae.shape[0]+1))).\ astype(np.float64)/(ae.shape[0]) # location of spline points og[e[0]][e[1]]['d0'] = splev(u, fit2[0], der=0) # first derivative (tangent) of spline og[e[0]][e[1]]['d1'] = np.array(splev(u, fit2[0], der=1)) # second derivative (curvature) of spline og[e[0]][e[1]]['d2'] = np.array(splev(u, fit2[0], der=2)) else: if (VERBOSE): print("no or insufficient points to fit") og[e[0]][e[1]]['d0'] = None og[e[0]][e[1]]['d1'] = None og[e[0]][e[1]]['d2'] = None
def to_spline(self, smoothing=0, spacing_corrected=False): """Return the best-fit periodic parametric 3rd degree b-spline to the data points. The smoothing parameter is an upper-bound on the mean squared deviation between the data points and the points produced by the smoothed spline. By default it is 0, forcing an interpolating spline. The returned spline is valid over the parametric range [0, num_points+1], where the value at 0 is the same as the value at num_points+1. If spacing_corrected is True, then the intermediate points will be placed according to the physical spacing between them, which is useful in some situations like resampling. However, it means that the spline evalueated at position N will not necessarialy give the same point as contour.points[n], unless all of the points are exactly evenly spaced. Similarly, non-zero values of smoothing will disrupt this property as well. Two values are returned: tck and u. 'tck' is a tuple containing the spline c oefficients, the knots (two lists; x-knots and y-knots), and the degree of the spline. This 'tck' tuple can be used by the routines in scipy.fitpack. 'u' is a list of the parameter values corresponding to the points in the range. """ # the fitpack smoothing parameter is an upper-bound on the TOTAL squared deviation; # ours is a bound on the MEAN squared deviation. Fix the mismatch: l = len(self.points) smoothing = smoothing * l if spacing_corrected: interpoint_distances = self.interpoint_distances() last_to_first = interpoint_distances[0] interpoint_distances[0] = 0 cumulative_distances = numpy.add.accumulate(interpoint_distances) u = numpy.empty(l + 1, dtype=float) u[:-1] = cumulative_distances u[-1] = cumulative_distances[-1] + last_to_first u *= l / u[-1] else: u = numpy.arange(0, l + 1) points = numpy.resize(self.points, [l + 1, 2]) points[-1] = points[0] tck, uout = fitpack.splprep(x=points.transpose(), u=u, per=True, s=smoothing) return tck, uout
def fitPath(self,maxiter=40, s=20000): """fits a least squares spline through the path find descriptions of maxiter and s from scipy documentation""" try: pth = path.getCrds() pp = [pth[:,0],pth[:,1],pth[:,2]] if( len(pp[0]) <= 3 ): # there are not enough points to fit with self.splinePoints = pp self.splineTangents = None self.splineCurvature = None return else: s = len(pp[0])/2.0 cont = 1 j=0 while( j < maxiter ): fit2 = splprep(pp,task=0,full_output =1, s=s)[0] u = na.array(range(pp[0].shape[0]+1)).\ astype(na.float64)/(pp[0].shape[0]) # location of spline points self.splinePoints = splev(u,fit2[0],der=0) # first derivative (tangent) of spline valsd = splev(u,fit2[0],der=1) self.splineTangents = na.array(valsd).astype(na.float64) # second derivative (curvature) of spline valsc = splev(u,fit2[0],der=2) self.splineCurvature = na.array(valsc).astype(na.float64) success = 1 # this doesn't make much sense if( success ): # how should I be determining success? break else: s = s*0.9 j += 1 return True except Exception, error: print "failed in fitPath()",error
def fitPath(self, maxiter=40, s=20000): """fits a least squares spline through the path find descriptions of maxiter and s from scipy documentation""" try: pth = path.getCrds() pp = [pth[:, 0], pth[:, 1], pth[:, 2]] if (len(pp[0]) <= 3): # there are not enough points to fit with self.splinePoints = pp self.splineTangents = None self.splineCurvature = None return else: s = len(pp[0]) / 2.0 cont = 1 j = 0 while (j < maxiter): fit2 = splprep(pp, task=0, full_output=1, s=s)[0] u = na.array(range(pp[0].shape[0]+1)).\ astype(na.float64)/(pp[0].shape[0]) # location of spline points self.splinePoints = splev(u, fit2[0], der=0) # first derivative (tangent) of spline valsd = splev(u, fit2[0], der=1) self.splineTangents = na.array(valsd).astype(na.float64) # second derivative (curvature) of spline valsc = splev(u, fit2[0], der=2) self.splineCurvature = na.array(valsc).astype(na.float64) success = 1 # this doesn't make much sense if (success): # how should I be determining success? break else: s = s * 0.9 j += 1 return True except Exception, error: print "failed in fitPath()", error
def distribution_plot(data_groups, filename, axis_title = None, plot_title = None, colors = default_colors, names = None, axes_at_origin = True, plot_points = False, fix_xrange = (None, None), scale_factors = None): """Plot the 1D distributions of several collections of points to a SVG file. The distributions of the 1D points in 'data_groups' are estimated with kernel density estimation, fit to splines, and plotted on numerical axes with an optional legend. Parameters: data_groups -- a list of grouped data points. Each group is a list of numbers, the distribution of which will be estimated and plotted. filename -- file to write the SVG out to. axis_title -- Title for the x-axis. plot_title -- title for the plot. colors -- the colors to fill the contours of each group with. Either color names that are defined in the SVG specification or (r,g,b) triplets are acceptable. This parameter must be an iterable; if there are not enough elements for the groups, they will be cycled. names -- the name of each group. Must be a list as long as contour_groups. If names is None, then there will be no legend in the output SVG. axes_at_origin -- if True, then the plot axes will intersect at the origin (or the nearest point to it in the data plot). Otherwise the axes will be at the bottom and left of the plot. plot_points -- if True, dots will be plotted at the location of each sample. fix_xrange, fix_yrange -- (min, max) tuples. If either or both values are None, then the best-fit range given the contours and their positions is chosen. Setting either or both forces the axis to have that minimum or maximum point. scale_factors -- If not None, a list of values by which to scale the heights of each distribution. """ from scipy.interpolate import fitpack data_groups = [numpy.asarray(data_group, dtype=numpy.float32) for data_group in data_groups] if not numpy.alltrue([data_group.ndim == 1 for data_group in data_groups]): raise ValueError('Can only plot distributions in one dimension.') data_groups = [numpy.asarray(data_group) for data_group in data_groups] data_ranges = [(g.min(), g.max()) for g in data_groups] kd_estimators = [kde.gaussian_kde(data_group) for data_group in data_groups] min = numpy.min([m for m, x in data_ranges]) max = numpy.max([x for m, x in data_ranges]) extra = 0.05*(max - min) min -= extra max += extra #min, max, data_ranges = _kde_range(kd_estimators, data_ranges, 5e-6) # pin the values to those of fix_xrange, if specified if fix_xrange[0] is not None: min = fix_xrange[0] if fix_xrange[1] is not None: max = fix_xrange[1] height = 0 beziers = [] err = numpy.seterr(under='ignore') # ignore underflow -- KDE can underflow when estimating regions of very low density if scale_factors is None: scale_factors = [1]*len(kd_estimators) for (range_min, range_max), estimator, scale_factor in zip(data_ranges, kd_estimators, scale_factors): if fix_xrange[0] is not None and range_min < min: range_min=min if fix_xrange[1] is not None and range_max > max: range_max=max eval_points = list(numpy.linspace(range_min, range_max, 100, True)) kde_points = estimator.evaluate(eval_points) * scale_factor data_height = kde_points.max() if data_height > height: height = data_height #s = 0.0005 * numpy.min([range_max - range_min, data_height]) / 100 s = 0 spline = fitpack.splprep([eval_points, kde_points], u=eval_points, s=s)[0] beziers.append(utility_tools.b_spline_to_bezier_series(spline)) numpy.seterr(**err) data_xrange = [min, max] data_yrange = [0, height] equal_axis_spacing = False plot = plot_class.Plot(_CANVAS_WIDTH, _CANVAS_HEIGHT, data_xrange, data_yrange, equal_axis_spacing, _LEFT_PAD, _RIGHT_PAD, _TOP_PAD, _BOTTOM_PAD) legend = True if names is None: legend = False names = ['distribution-%d'%d for d in range(len(data_groups))] else: names = [name.replace(' ', '_') for name in names] if plot_points: point_radius = 0.005 * (data_xrange[1] - data_xrange[0]) plot.style.add_selector('[class~="point"]', fill='black', stroke=None) for name, bezier, data_group, estimator, color in zip(names, beziers, data_groups, kd_estimators, itertools.cycle(colors)): plot.add_bezier(bezier, id=name, svg_class='data density', layer=name) plot.style.add_selector('[class~="density"][id="%s"]'%name, fill='none', stroke=color) plot.style.add_selector('[class~="legend"][id="%s"]'%name, fill='none', stroke=color) if plot_points: values = numpy.unique(data_group) for point in zip(values, estimator(values)): plot.add_circle(point, point_radius, id=None, svg_class="data point", layer=name, in_data_coords=True) if legend: legend_x = _CANVAS_WIDTH - _PAD - 80 legend_y = _FONT_SIZE_SMALL * plot_class._TOP_TO_BASELINE + _PAD line_length = 50 plot.add_legend(legend_x, legend_y, line_length, names, _FONT_SIZE_SMALL) if plot_title is not None: plot.add_title(plot_title, _FONT_SIZE) if axes_at_origin: positions = (-1,0) else: positions = (-1,-1) plot.add_axes(positions = positions, titles = (axis_title, None), ticsize = _TICSIZE, font_size = _FONT_SIZE_SMALL) plot.to_svg(filename, plot_title) return plot
def line_plot(data_groups, filename, axis_titles = (None, None), plot_title = None, colors = default_colors, names = None, axes_at_origin = True, fix_xrange = (None, None), fix_yrange = (None, None), bezier=None): """Plot smooth lines connecting at given x, y locations to an SVG file. The resulting SVG will have numerical axes (either centered at the origin, or placed on the left and bottom of the plot) and optionally a legend. Parameters: data_groups -- a list of polylines to be plotted, where each polyline is placed in a different SVG group and colored differently. Each polyline is itself a list of [x, y] pairs. filename -- file to write the SVG out to. line_width -- Pixel width of the lines to be plotted. axis_titles -- pair of titles for the x and y axes, respectively. plot_title -- title for the plot. colors -- the colors to fill the contours of each group with. Either color names that are defined in the SVG specification or (r,g,b) triplets are acceptable. This parameter must be an iterable; if there are not enough elements for the groups, they will be cycled. names -- the name of each group. Must be a list as long as contour_groups. If names is None, then there will be no legend in the output SVG. axes_at_origin -- if True, then the plot axes will intersect at the origin (or the nearest point to it in the data plot). Otherwise the axes will be at the bottom and left of the plot. fix_xrange, fix_yrange -- (min, max) tuples. If either or both values are None, then the best-fit range given the contours and their positions is chosen. Setting either or both forces the axis to have that minimum or maximum point. """ from scipy.interpolate import fitpack all_points = numpy.array([p for dg in data_groups for p in dg]) plot_width = _CANVAS_WIDTH - _LEFT_PAD - _RIGHT_PAD plot_height = _CANVAS_HEIGHT - _TOP_PAD - _BOTTOM_PAD data_xrange, data_yrange = numpy.transpose([all_points.min(axis=0), all_points.max(axis=0)]) fmin, fmax = fix_xrange if fmin is not None: data_xrange[0] = fmin if fmax is not None: data_xrange[1] = fmax fmin, fmax = fix_yrange if fmin is not None: data_yrange[0] = fmin if fmax is not None: data_yrange[1] = fmax equal_axis_spacing = False plot = plot_class.Plot(_CANVAS_WIDTH, _CANVAS_HEIGHT, data_xrange, data_yrange, equal_axis_spacing, _LEFT_PAD, _RIGHT_PAD, _TOP_PAD, _BOTTOM_PAD) legend = True if names is None: legend = False names = ['group-%d'%d for d in range(len(data_groups))] else: names = [name.replace(' ', '_') for name in names] for name, data_group, color in zip(names, data_groups, itertools.cycle(colors)): if bezier is not None: spline = fitpack.splprep(numpy.transpose(data_group), s=bezier)[0] curve = utility_tools.b_spline_to_bezier_series(spline) plot.add_bezier(curve, id=name, svg_class='data line', layer=name) else: plot.add_polyline(data_group, id=name, svg_class='data line', layer=name) plot.style.add_selector('[id="%s"]'%name, fill='none', stroke=color) if legend: legend_x = _CANVAS_WIDTH - _PAD - 80 legend_y = _FONT_SIZE_SMALL * plot_class._TOP_TO_BASELINE + _PAD line_length = 50 plot.add_legend(legend_x, legend_y, line_length, names, _FONT_SIZE_SMALL, box=False) if plot_title is not None: plot.add_title(plot_title, _FONT_SIZE) if axes_at_origin: positions = (0,0) else: positions = (-1,-1) plot.add_axes(positions = positions, titles = axis_titles, ticsize = _TICSIZE, font_size = _FONT_SIZE_SMALL) plot.to_svg(filename, plot_title) return plot