def plot(spreading, _type, shift, style): def get_line(spread, _type): if _type == 'left' or _type == 'right': return spread.spread[_type]['std_error'] elif _type == 'radius': _, radius = calc_radius(spread, error=True) return radius for i, spread_list in enumerate(spreading): spread, _ = combine_spread(spread_list, shift=shift[0]) domain = spread.times line = get_line(spread, _type) plot_line( line=line, domain=domain, color=colours[i], label=labels[i], linestyle=style[i], hold=True ) return None
def spread_plot(args): """Draw the spreading as a function of time.""" # Get colours and line styles from default colours = get_colours(args.colour, len(args.spreading)) labels, draw_legend = get_labels(args.label, len(args.spreading)) linestyles = {} linestyles['line'] = get_linestyles(args.linestyle, len(args.spreading)) linestyles['fit'] = get_linestyles(args.fitstyle, len(args.spreading), 'dashed') # Create linear fitting function fitfunc = lambda p, t, r: r - p[0] - p[1] * t pinit = [1.0, 1/7] # Find shift array for synchronisation shift_array = get_shift(args.spreading, sync=args.sync) impact_shift = get_shift(args.spreading, sync='impact') # Create dicts for lists of fit constants (r = amp * t**index) amp = {} index = {} ampError = {} indexError = {} ampMean = [] ampMeanError = [] indexMean = [] indexMeanError = [] for i, spread_list in enumerate(args.spreading): amp[i] = [] index[i] = [] ampError[i] = [] indexError[i] = [] spread, full_data = combine_spread(spread_list, shift=shift_array[i]) spread.times = np.array(spread.times) - spread.times[0] for k, _file in enumerate(spread_list): data = Spread().read(_file) data.times = np.array(data.times) - impact_shift[i][k] # Get radius and domain radius = {'real': np.array(calc_radius(data))} domain = {'real': np.array(data.times)} # Cut times outside of range for j, time in enumerate(domain['real']): if time > args.tend: radius['real'] = radius['real'][:j] domain['real'] = domain['real'][:j] # Add logged values radius['log'] = np.log10(radius['real'][1:]) domain['log'] = np.log10(domain['real'][1:]) # Cut in log range for j, logt in enumerate(domain['log']): if logt > args.tendlog: radius['log'] = radius['log'][:j] domain['log'] = domain['log'][:j] # Fit constants to data out = optimize.leastsq(fitfunc, pinit, args=(domain['log'], radius['log']), full_output=1) pfinal = out[0] covar = out[1] # Add unlogged constants to lists amp[i].append(10**pfinal[0]) index[i].append(pfinal[1]) ampError[i].append(np.sqrt(covar[1][1]) * amp[i][-1]) indexError[i].append(np.sqrt(covar[0][0])) if args.draw == 'log' and args.nomean: plot_line( line=radius['log'], domain=domain['log'], color=colours[i], linestyle=linestyles['line'][i] ) if not args.nofit: plot_line( line=out[0][0] + out[0][1] * domain['log'], domain=domain['log'], color=colours[i], linestyle=linestyles['fit'][i] ) if args.draw == 'real' and args.nomean: plot_line( line=radius['real'], domain=domain['real'], color=colours[i], linestyle=linestyles['line'][i] ) if not args.nofit: plot_line( line=amp[i][-1] * (domain['real']**index[i][-1]), domain=domain['real'], color=colours[i], linestyle=linestyles['fit'][i] ) ampMean.append(np.mean(amp[i])) ampMeanError.append(np.std(amp[i]) / np.sqrt(len(amp[i]) - 1)) indexMean.append(np.mean(index[i])) indexMeanError.append(np.std(index[i]) / np.sqrt(len(index[i]) - 1)) if not args.nomean: if args.draw == 'log': plot_line( line=np.log10(calc_radius(spread)), domain=np.log10(spread.times), label=labels[i], color=colours[i], linestyle=linestyles['line'][i] ) if not args.nofit: plot_line( line=(np.log10(ampMean[i]) + indexMean[i] * np.log10(spread.times)), domain=np.log10(spread.times), label='C=%.2f, n=%.2f'%(ampMean[i], indexMean[i]), color=colours[i], linestyle=linestyles['fit'][i] ) if args.draw == 'real': plot_line( line=calc_radius(spread), domain=spread.times, label=labels[i], color=colours[i], linestyle=linestyles['line'][i] ) if not args.nofit: plot_line( line=ampMean[i] * (domain['real']**indexMean[i]), domain=domain['real'], label='C=%.2f, n=%.2f'%(ampMean[i], indexMean[i]), color=colours[i], linestyle=linestyles['fit'][i] ) plt.title(args.title, fontsize='medium') plt.axis('normal') plt.legend() # Default xlabel and xlims based on draw method if args.draw == 'real': if args.ylabel == None: args.ylabel = "Spread radius (nm)" if args.xlabel == None: args.xlabel = "Time (ps)" if (args.tend and args.tendlog) < np.inf: plt.xlim([None, min(args.tend, 10**args.tendlog)]) elif args.draw == 'log': if args.ylabel == None: args.ylabel = "log10 of radius (in nm)" if args.xlabel == None: args.xlabel = "log10 of time (in ps)" if (args.tend and args.tendlog) < np.inf: plt.xlim([None, min(args.tend, args.tendlog)]) plt.xlabel(args.xlabel, fontsize='medium') plt.ylabel(args.ylabel, fontsize='medium') if args.xlim: plt.xlim(args.xlim) # Print collected output print("Fitting spread radius 'R' of input file sets to power law functions " "of time 't' as 'R = C * (t ** n)' and taking means:") for i, _ in enumerate(amp): print() # If nomean, print individual line values if args.nomean: for values in zip(amp[i], ampError[i], index[i], indexError[i]): print("%f +/- %f" % (values[0], values[1]), end=', ') print("%f +/- %f" % (values[2], values[3])) # Print mean values if args.nomean: print(" -> ", end='') print("C = %f +/- %f" % (ampMean[i], ampMeanError[i])) if args.nomean: print(" -> ", end='') print("n = %f +/- %f" % (indexMean[i], indexMeanError[i])) # Finish by saving and / or showing if args.save: plt.savefig(args.save) if args.draw != 'off': plt.show() return None
def vel_plot(args): """Draw the spreading as a function of time.""" def plot_data(spread, times): """Plot either edges or radius of specified line.""" for _type in args.plot_type: velocity = spread[_type]['val'] plot_line( line=velocity, domain=times, color=colours[i], label=label, linestyle=linestyles['line'][i] ) return None def calc_velocity(spread, plot_type, N, N_sample): """ Returns the velocity of the spreading curve, as a running average over N frames. """ def get_velocity(spreading, times, N_sample): velocity = [] for i, _ in enumerate(spreading): i_min = max(0, i-N_sample) i_max = min(i+N_sample, len(spreading)-1) delta_x = spreading[i_max] - spreading[i_min] delta_t = times[i_max] - times[i_min] velocity.append(delta_x/delta_t) return velocity def calc_running_avg(velocity, full_times, N): N0 = N running_avg = {'val': [], 'std': []} times = [] for i, _ in enumerate(velocity): if args.include == 'equal': N = min(i - max(0, i-N0), min(i+N0, len(velocity)-1)-i) i_min = max(0, i-N) i_max = min(i+N, len(velocity)-1) if N == 0 or (args.include == 'limited' and i_max - i_min != 2*N): continue running_avg['val'].append(np.average(velocity[i_min:i_max+1])) times.append(full_times[i]) return running_avg, times running_avg = {} for _type in plot_type: velocity = get_velocity(spread.spread[_type]['val'], spread.times, N_sample) running_avg[_type], times = calc_running_avg(velocity, spread.times, N) return running_avg, times def print_vel(velocity, times): """Output the mean spread velocity to standard output.""" print("%9c Velocity of (nm / ps)" % ' ') print("%9s " % "Time (ps)", end='') for _key in velocity.keys(): print("%9s " % _key.capitalize(), end='') print() for i, time in enumerate(times[1:]): print("%9g " % time, end='') for _type in velocity.keys(): print("%9g " % velocity[_type]['val'][i+1], end='') print() return None # Get colours, labels and line styles from default colours = get_colours(args.colour, len(args.spreading)) labels, draw_legend = get_labels(args.label, len(args.spreading)) linestyles = {} linestyles['line'] = get_linestyles(args.linestyle, len(args.spreading)) # Find shift array for synchronisation shift_array = get_shift(args.spreading, sync=args.sync) for i, spread_list in enumerate(args.spreading): spread, data = combine_spread(spread_list, shift=shift_array[i]) # If --nomean, draw lines here label = labels[i] if args.nomean: for spread_data in data: vel, times = calc_velocity(spread_data, args.plot_type, args.num_average, args.num_sample) plot_data(vel, times) label = '_nolegend_' # Else draw the mean result else: vel, times = calc_velocity(spread, args.plot_type, args.num_average, args.num_sample) plot_data(vel, times) plt.title(args.title, fontsize='medium') plt.xlabel(args.xlabel, fontsize='medium') plt.ylabel(args.ylabel, fontsize='medium') if args.loglog: plt.xscale('log') plt.yscale('log') plt.axis('normal') plt.xlim([args.t0, args.tend]) if draw_legend: plt.legend(loc=args.legend_loc) # Finish by saving and / or showing if args.save: plt.savefig( args.save, dpi=args.dpi, transparent=args.transparent, bbox_inches='tight' ) if args.print: if args.nomean: vel = calc_velocity(spread, args.plot_type, args.num_average, args.num_sample) print_vel(vel, spread.times) if args.show: plt.show() return None
def com_plot(args): """Draw the center of mass height as a function of time.""" # Get colours, labels and line styles from default colours = get_colours(args.colour, len(args.spreading)) labels, draw_legend = get_labels(args.label, len(args.spreading)) linestyles = {} linestyles['line'] = get_linestyles(args.linestyle, len(args.spreading)) linestyles['error'] = get_linestyles(args.errorstyle, len(args.spreading), 'dashed') # Find shift array for synchronisation shift_array = get_shift(args.spreading, sync=args.sync) for i, spread_list in enumerate(args.spreading): spread, data = combine_spread(spread_list, shift=shift_array[i]) # Check if error bars need to be included error = args.error and len(spread_list) > 1 # Create graph if args.nomean: label = labels[i] for spread_data in data: domain = spread_data.times line = spread_data.dist plot_line(line=line, domain=domain, color=colours[i], label=label, linestyle=linestyles['line'][i]) label = '_nolegend_' else: domain = spread.times line = spread.dist plot_line(line=line, domain=domain, color=colours[i], label=labels[i], linestyle=linestyles['line'][i]) if error: domain = spread.times line = list(np.array(spread.dist) + np.array(spread.spread['dist']['std_error']) * args.sigma) plot_line(line=line, domain=domain, color=colours[i], linestyle=linestyles['error'][i]) line = list(np.array(spread.dist) - np.array(spread.spread['dist']['std_error']) * args.sigma) plot_line(line=line, domain=domain, color=colours[i], linestyle=linestyles['error'][i]) plt.title(args.title) plt.xlabel(args.xlabel) plt.ylabel(args.ylabel) plt.axis('normal') plt.xlim([args.t0, args.tend]) if draw_legend: plt.legend() # Finish by saving and / or showing if args.save: plt.savefig(args.save) if args.show: plt.show() return None
def spread_plot(args): """Draw the spreading of sets of droplets as a function of time.""" def add_xvgdata(spread, xvg_set): """ Adds data for current line to list of data to output in .xvg format. """ add = {} line = [] for _type in plot_type: add['legend'] = labels[i] add['line'] = spread.spread[_type]['val'][0:] add['time'] = np.array(spread.times[0:]) line.append(add.copy()) xvg_set.append(line) return None def save_xvgdata(xvg_data): """ Saves spreading lines to .xvg files of input filenames. """ def print_xvgfile(line, fnin): fnout = fnin.rsplit('.', 1)[0] + '.xvg' backup_file(fnout) with open(fnout, 'w') as _file: _file.write( "@ title \"%s\"\n" "@ xaxis label \"%s\"\n" "@ yaxis label \"%s\"\n" "@TYPE xy\n" % (args.title, args.xlabel, args.ylabel) ) # Output legend information _file.write( "@ legend on\n" "@ legend box on\n" "@ legend loctype view\n" "@ legend 0.78 0.8\n" "@ legend length 2\n" "@s0 legend \"%s\"\n\n" % line[0]['legend'] ) for i in range(len(line[0]['time'])): time = line[0]['time'][i] _file.write("%f " % time) for j in range(len(line)): value = line[j]['line'][i] _file.write("%f " % value) _file.write("\n") return None def backup_file(fn): """If a file 'fn' exists, move to backup location.""" fnmv = fn n = 0 while (os.path.isfile(fnmv)): n += 1 try: _path, _file = fn.rsplit('/', 1) _path += '/' except ValueError: _path = '' _file = fn fnmv = _path + '#' + _file.rsplit('.', 1)[0] + '.xvg.%d#' % n if (n > 0): print("File '%s' backed up to '%s'" % (fn, fnmv)) shutil.move(fn, fnmv) return None for i, xvg_set in enumerate(xvg_data): # Print either all lines to separate files with extension switch if args.nomean: for j, line in enumerate(xvg_set): # Replace last extension with .xvg fnin = args.spreading[i][j] print_xvgfile(line, fnin) # Or print combined lines to files with base filename as first file else: line = xvg_set[0] fnin = args.spreading[i][0] print_xvgfile(line, fnin) return None def plot_data(spread, times): """Plot either edges or radius of specified line.""" for _type in plot_type: plot_line( line=spread[_type]['val'][0:], domain=np.array(times[0:]), color=colours[i], label=label, linestyle=linestyles['line'][i], linewidth=2 ) return None def plot_error(spread): """Plot the error of either the edges or radius of a line.""" def draw_error_line(spread): mean = np.array(get_line(spread, _type, error=False)) std = np.array(get_line(spread, _type, error=True)) # If not standard deviation desired, calculate std error if args.std: error = std else: error = (std / np.sqrt(spread.spread['num']))*args.sigma plot_line( line=(mean + error), domain=spread.times, color=colours[i], linestyle=linestyles['error'][i] ) plot_line( line=(mean - error), domain=spread.times, color=colours[i], linestyle=linestyles['error'][i] ) return None for _type in plot_type: draw_error_line(spread) return None def get_line(spread, _type, error=False): """Return a desired line to plot.""" _value = 'val' if error: _value = 'std' return spread.spread[_type][_value] def get_scaling(input_time, input_radius, num_factors, default=1.0): """Get scaling factors for time and radii of all lines.""" scaling = {} input_factors = {'time': input_time, 'radius': input_radius} for key in ['time', 'radius']: scaling[key] = [] for i in range(0, num_factors): if i < len(input_factors[key]): scaling[key].append(input_factors[key][i]) else: scaling[key].append(default) return scaling def apply_scaling(spread, all_data, scaling, num): """Apply time and radius scaling onto all spread data.""" spread.scale_data(scaling['time'][num], scaling['radius'][num]) for i, _ in enumerate(all_data): all_data[i].scale_data(scaling['time'][num], scaling['radius'][num]) return None # Get colours, labels and line styles from default colours = get_colours(args.colour, len(args.spreading)) labels, draw_legend = get_labels(args.label, len(args.spreading)) linestyles = {} linestyles['line'] = get_linestyles(args.linestyle, len(args.spreading)) linestyles['error'] = get_linestyles(args.errorstyle, len(args.spreading), 'dashed') # Find scaling factors for lines scaling = get_scaling(args.time_scaling, args.radius, len(args.spreading)) # Find shift array for synchronisation shift_array = get_shift(args.spreading, sync=args.sync, radius_array=scaling['radius'], radius_fraction=args.sync_radius_fraction) # Initiate xvg data xvgdata = [] for i, spread_list in enumerate(args.spreading): spread, data = combine_spread(spread_list, shift=shift_array[i]) apply_scaling(spread, data, scaling, i) # Either draw all or a combined line; set which set here xvg_set = [] if args.nomean: spread_array = data else: spread_array = [spread] label = labels[i] for spread_data in spread_array: plot_data(spread_data.spread, spread_data.times) label = '_nolegend_' if args.xvg: add_xvgdata(spread_data, xvg_set) # If error for line is desired, calculate and plot if args.error: plot_error(spread) # Add set of xvg data to array if args.xvg: xvgdata.append(xvg_set) plt.title(args.title, fontsize='medium') plt.xlabel(args.xlabel, fontsize='medium') plt.ylabel(args.ylabel, fontsize='medium') if args.loglog: plt.xscale('log') plt.yscale('log') plt.axis('normal') plt.xlim([args.t0, args.tend]) if draw_legend: plt.legend(loc=args.legend_loc) # Finish by saving and / or showing if args.save: plt.savefig( args.save, dpi=args.dpi, transparent=args.transparent, bbox_inches='tight' ) if args.xvg: save_xvgdata(xvgdata) if args.show: plt.show() return None