def _calculateDeviation( self, track, value, uncertainty, highMeasuredUncertainty, measured, prefix, label ): if not measured: return None out = dict() measuredUncertainty = measured*( 0.12 if highMeasuredUncertainty else 0.06) v = NumericUtils.toValueUncertainty(value, uncertainty) mv = NumericUtils.toValueUncertainty(measured, measuredUncertainty) unc = math.sqrt(v.uncertainty**2 + mv.uncertainty**2) deviation = v.value - mv.value out['%sDev' % prefix] = deviation/measured try: out['%sDelta' % prefix] = abs(deviation)/unc except ZeroDivisionError: self.logger.write([ '[ERROR]: Track without %s uncertainty' % label, 'TRACK: %s (%s)' % (track.fingerprint, track.uid) ]) raise return out
def test_isNumber(self): """test_isNumber doc...""" self.assertTrue(NumericUtils.isNumber(1.234)) self.assertTrue(NumericUtils.isNumber(100)) self.assertTrue(NumericUtils.isNumber(-24)) self.assertFalse(NumericUtils.isNumber('12')) self.assertFalse(NumericUtils.isNumber(self))
def _resolveSpatialCoincidences(self, pair): """ Correct for cases where projected prints reside at the same spatial location on the curve series by adjusting one of the tracks projection position slightly. """ segment = pair['segment'] try: nextSegment = self.segments[self.segments.index(segment) + 1] nextOffset = nextSegment.offset except Exception: nextOffset = 1.0e8 # Adjust a pair print if it resides at the same position as its curve series track if NumericUtils.equivalent(pair['distance'], 0.0): self._adjustPositionForward(pair, nextOffset) try: # Retrieve the next pair track in the segment if one exists nextPair = segment.pairs[segment.pairs.index(pair) + 1] except Exception: return pDist = pair['distance'] npDist = nextPair['distance'] # Adjust pair tracks that reside at the same spatial position if npDist <= pDist or NumericUtils.equivalent(pDist, npDist): self._adjustPositionForward(nextPair, nextOffset)
def __unicode__(self): isPy2 = bool(sys.version < '3') return '<%s (%s, %s)>' % ( self.__class__.__name__, NumericUtils.toValueUncertainty(self.x, self.xUnc, asciiLabel=isPy2).label, NumericUtils.toValueUncertainty(self.y, self.yUnc, asciiLabel=isPy2).label)
def _adjustPositionForward(self, pair, maxOffset =1.0e8): """_adjustPositionForward doc...""" delta = 0.001 segment = pair['segment'] offset = segment.offset + pair['distance'] while maxOffset <= (offset + delta) or NumericUtils.equivalent(maxOffset, offset + delta): delta *= 0.5 point = pair['line'].start.clone() segment.line.adjustPointAlongLine(point, delta, inPlace=True) dist = segment.line.start.distanceTo(point).raw if not NumericUtils.equivalent(pair['distance'] + delta, dist, machineEpsilonFactor=1000.0): self.stage.logger.write([ '[ERROR]: Forward adjust failure in CurveSeries.adjustPositionForward', 'TRACK: %s [%s]' % (pair['track'].fingerprint, pair['track'].uid), 'EXPECTED: %s' % (pair['distance'] + delta), 'ACTUAL: %s' % dist, 'DELTA: %s' % delta]) pair['line'].start.copyFrom(point) track = pair['track'] pair['distance'] = dist if not self.saveToAnalysisTracks: return at = track.getAnalysisPair(self.stage.analysisSession) at.curvePosition = segment.offset + dist at.segmentPosition = dist
def echo(self, asciiLabel=False): """echo doc...""" return '(%s, %s)' % (NumericUtils.toValueUncertainty( self.x, self.xUnc, asciiLabel=asciiLabel).rawLabel, NumericUtils.toValueUncertainty( self.y, self.yUnc, asciiLabel=asciiLabel).rawLabel)
def print_track(track, aSession): """ @param track: @param aSession: @return: """ limb_id = "{}{}".format("l" if track.left else "r", "p" if track.pes else "m") print(track.echoForVerification()) print( " size: (%s, %s) | field (%s, %s)" % (track.width, track.length, track.widthMeasured, track.lengthMeasured) ) aTrack = track.getAnalysisPair(aSession) print( " curve[#%s -> %s]: %s (%s)" % ( aTrack.curveIndex, aTrack.curveSegment, NumericUtils.roundToSigFigs(aTrack.segmentPosition, 4), NumericUtils.roundToSigFigs(aTrack.curvePosition, 4), ) ) print(" snapshot: {}\n".format(DictUtils.prettyPrint(track.snapshotData))) return dict(limb_id=limb_id, track=track, aTrack=aTrack)
def project(self, track, data =None): """ Tests the specified segment and modifies the data dictionary with the results of the test if it was successful. """ data = self._initializeData(data, track) position = track.positionValue debugItem = {'TRACK':self.track.fingerprint if self.track else 'NONE'} debugData = {} data['debug'].append({'print':debugItem, 'data':debugData}) # Make sure the track resides in a generally forward direction relative to # the direction of the segment. The prevents tracks from matching from behind. angle = self.line.angleBetweenPoint(position) if abs(angle.degrees) > 100.0: debugItem['CAUSE'] = 'Segment position angle [%s]' % angle.prettyPrint return # Calculate the closest point on the line segment. If the point and line are not # properly coincident, the testPoint will be None and the attempt should be aborted. testPoint = self.line.closestPointOnLine(position, contained=True) if not testPoint: debugItem['CAUSE'] = 'Not aligned to segment' return testLine = LineSegment2D(testPoint, position.clone()) # Make sure the test line intersects the segment line at 90 degrees, or the # value is invalid. angle = testLine.angleBetweenPoint(self.line.end) if not NumericUtils.equivalent(angle.degrees, 90.0, 2.0): debugItem['CAUSE'] = 'Projection angle [%s]' % angle.prettyPrint debugData['testLine'] = testLine debugData['testPoint'] = testPoint return # Skip if the test line length is greater than the existing test line length = data.get('projectionLength', 1.0e10) if testLine.length.raw > length: debugItem['CAUSE'] = 'Greater length [%s > %s]' % ( NumericUtils.roundToSigFigs(length, 5), NumericUtils.roundToSigFigs(testLine.length.raw, 5) ) debugData['testLine'] = testLine debugData['testPoint'] = testPoint return # Populate the projection values if the projection was successful p = testPoint.clone() # p.xUnc = position.xUnc # p.yUnc = position.yUnc data['segment'] = self data['projectionLength'] = position.distanceTo(p).raw data['line'] = LineSegment2D(p, position) data['distance'] = self.line.start.distanceTo(p).raw debugData['distance'] = data['distance'] return data
def _postAnalyze(self): """_postAnalyze doc...""" self._csv.save() meanDiff = NumericUtils.getMeanAndDeviation(self._diffs) self.logger.write('Rotation %s' % meanDiff.label) self._paths.append(self._makePlot( label='Rotation Differences', data=self._diffs, histRange=[-180, 180])) self._paths.append(self._makePlot( label='Rotation Differences', data=self._diffs, histRange=[-180, 180], isLog=True)) circs = [] circsUnc = [] diffs = [] diffsUnc = [] entries = self.owner.getStage('lengthWidth').entries for entry in entries: track = entry['track'] if track.uid not in self.deviations: # Skip those tracks with no deviation value (solo tracks) continue diffDeg = self.deviations[track.uid] diffs.append(abs(diffDeg.value)) diffsUnc.append(diffDeg.uncertainty) # Compute the circularity of the track from its aspect ratio. If # the aspect is less than or equal to 1.0 use the aspect value # directly. However, if the value is greater than one, take the # reciprocal so that large and small aspect ratios can be compared # equally. aspect = entry['aspect'] if aspect.value > 1.0: a = 1.0/aspect.raw aspect = NumericUtils.toValueUncertainty(a, a*(aspect.rawUncertainty/aspect.raw)) circs.append(abs(aspect.value - 1.0)) circsUnc.append(aspect.uncertainty) pl = self.plot self.owner.createFigure('circular') pl.errorbar(x=circs, y=diffs, xerr=circsUnc, yerr=diffsUnc, fmt='.') pl.xlabel('Aspect Circularity') pl.ylabel('Rotation Deviation') pl.title('Rotation Deviation and Aspect Circularity') self._paths.append(self.owner.saveFigure('circular')) self.mergePdfs(self._paths) self._paths = []
def __unicode__(self): isPy2 = bool(sys.version < '3') return '<%s (%s, %s)>' % ( self.__class__.__name__, NumericUtils.toValueUncertainty( self.x, self.xUnc, asciiLabel=isPy2).label, NumericUtils.toValueUncertainty( self.y, self.yUnc, asciiLabel=isPy2).label)
def test_weightedAverage(self): """ doc... """ values = [ NumericUtils.toValueUncertainty(11.0, 1.0), NumericUtils.toValueUncertainty(12.0, 1.0), NumericUtils.toValueUncertainty(10.0, 3.0) ] result = NumericUtils.weightedAverage(*values) self.assertEqual(result.value, 11.4, 'Value Match') self.assertEqual(result.uncertainty, 0.7, 'Value Match')
def test_toValueUncertainty(self): """test_toValueUncertainty doc...""" value = NumericUtils.toValueUncertainty(math.pi, 0.00456) self.assertEqual(value.value, 3.142, 'Values do not match %s' % value.label) self.assertEqual(value.uncertainty, 0.005, 'Uncertainties do not match %s' % value.label) value = NumericUtils.toValueUncertainty(100.0*math.pi, 42.0) self.assertEqual(value.value, 310.0, 'Values do not match %s' % value.label) self.assertEqual(value.uncertainty, 40.0, 'Uncertainties do not match %s' % value.label) value = NumericUtils.toValueUncertainty(0.001*math.pi, 0.000975) self.assertEqual(value.value, 0.003, 'Values do not match %s' % value.label) self.assertEqual(value.uncertainty, 0.001, 'Uncertainties do not match %s' % value.label)
def makePlot(label, tracks): tracks = tracks.copy() xBounds = [ NumericUtils.roundToOrder(tracks.length.min() - 0.05, -1, math.floor), NumericUtils.roundToOrder(tracks.length.max() + 0.05, -1, math.ceil)] yBounds = [ NumericUtils.roundToOrder(tracks.width.min() - 0.05, -1, math.floor), NumericUtils.roundToOrder(tracks.width.max() + 0.05, -1, math.ceil)] fig = plotlyTools.make_subplots( rows=1, cols=2, subplot_titles=('Length vs Width','Aspect Ratios'), print_grid=False) traces = [] for site in tracks.site.unique(): color = PlotConfigs.SITE_SPECS[site]['color'] siteSlice = tracks[tracks.site == site] traces.append(plotlyGraph.Scatter( name=site, mode='markers', xaxis='x1', yaxis='y1', marker=plotlyGraph.Marker(color=color), x=siteSlice.length, y=siteSlice.width)) traces.append(plotlyGraph.Box( name=site, y=siteSlice.length/siteSlice.width, marker=plotlyGraph.Marker(color=color), xaxis='x2', yaxis='y2')) fig['data'] += plotlyGraph.Data(traces) fig['layout'].update( title='%s Length & Width by Tracksite' % label, xaxis1=plotlyGraph.XAxis( title='Length (m)', range=xBounds, autorange=False ), yaxis1=plotlyGraph.YAxis( title='Width (m)', range=yBounds, autorange=False )) url = plotly.plot( filename='A16/%s-Length-Width' % label, figure_or_data=fig, auto_open=False) print('PLOT[%s]:' % label, PlotlyUtils.toEmbedUrl(url))
def _processGaugeData(self, bundle, trackway, data): pesCount = bundle.leftPes.count + bundle.rightPes.count record = {'name':trackway.name, 'count':pesCount} gaugeData = data['gauges'] try: value = NumericUtils.getWeightedMeanAndDeviation(gaugeData.abs) record['abs'] = value.value record['absUnc'] = value.uncertainty self._trackwayGauges.abs.append((pesCount, value)) except ZeroDivisionError: return widthValue = NumericUtils.getWeightedMeanAndDeviation(gaugeData.width) record['width'] = widthValue.value record['widthUnc'] = widthValue.uncertainty self._trackwayGauges.width.append((pesCount, widthValue)) if gaugeData.pace: value = NumericUtils.getWeightedMeanAndDeviation(gaugeData.pace) record['pace'] = value.value record['paceUnc'] = value.uncertainty self._trackwayGauges.pace.append((pesCount, value)) else: record['pace'] = '' record['paceUnc'] = '' if gaugeData.stride: value = NumericUtils.getWeightedMeanAndDeviation(gaugeData.stride) record['stride'] = value.value record['strideUnc'] = value.uncertainty self._trackwayGauges.stride.append((pesCount, value)) else: record['stride'] = '' record['strideUnc'] = '' self._trackwayCsv.addRow(record) plot = ScatterPlot( data=data['points'], title='%s Width-Normalized Gauges (%s)' % (trackway.name, widthValue.label), xLabel='Track Position (m)', yLabel='Gauge (AU)') self._paths.append(plot.save(self.getTempFilePath(extension='pdf'))) analysisTrackway = trackway.getAnalysisPair(self.analysisSession) analysisTrackway.simpleGauge = widthValue.raw analysisTrackway.simpleGaugeUnc = widthValue.rawUncertainty
def rawLabel(self): if self._asciiLabels: return self.asciiRawLabel return '%s %s %s' % ( NumericUtils.roundToSigFigs(self.raw, 6), StringUtils.unichr(0x00B1), self.uncertainty)
def _plot(self): """_plot doc...""" x = [] y = [] yUnc = [] for value in self.data: entry = self._dataItemToValue(value) y.append(entry['y']) x.append(entry.get('x', len(x))) yUnc.append(entry.get('yUnc', 0.0)) if NumericUtils.equivalent(max(yUnc), 0.0): yUnc = None pl = self.pl pl.bar(x, y, yerr=yUnc, facecolor=self.color, edgecolor=self.strokeColor, log=self.isLog) pl.title(self.title) pl.xlabel(self.xLabel) pl.ylabel(self.yLabel) if self.xLimits: pl.xlim(*self.xLimits) if self.yLimits: pl.ylim(*self.yLimits) pl.grid(True)
def _drawMeasuredWidth(self, track, drawing): if NumericUtils.equivalent(track.widthMeasured, 0.0): return if track.uid in self.trackDeviations: data = self.trackDeviations[track.uid] if data['wSigma'] > 2.0: strokeWidth = 3.0 color = 'red' else: strokeWidth = 1.0 color = 'green' else: strokeWidth = 1.0 color = 'green' w = 100*track.widthMeasured rot = math.radians(track.rotation) x1 = w/2.0 x2 = -w/2.0 drawing.line( (track.x + x1*math.cos(rot), track.z - x1*math.sin(rot)), (track.x + x2*math.cos(rot), track.z - x2*math.sin(rot)), scene=True, stroke=color, stroke_width=strokeWidth)
def _drawMeasuredLength(self, track, drawing): if NumericUtils.equivalent(track.lengthMeasured, 0.0): return if track.uid in self.trackDeviations: data = self.trackDeviations[track.uid] if data['lSigma'] > 2.0: strokeWidth = 3.0 color = 'red' else: strokeWidth = 1.0 color = 'green' else: strokeWidth = 1.0 color = 'green' l = 100*track.lengthMeasured rot = math.radians(track.rotation) z1 = track.lengthRatio*l z2 = z1 - l drawing.line( (track.x + z1*math.sin(rot), track.z + z1*math.cos(rot)), (track.x + z2*math.sin(rot), track.z + z2*math.cos(rot)), scene=True, stroke=color, stroke_width=strokeWidth)
def _extrapolateByLength(self, lengthAdjust, pre =False): """_extrapolateByLength doc...""" length = self.length targetLengthSqr = (length.raw + lengthAdjust)**2 s = self.start e = self.end deltaX = e.x - s.x deltaY = e.y - s.y delta = lengthAdjust if NumericUtils.equivalent(deltaX, 0.0): # Vertical lines should invert delta if start is above the end delta *= -1.0 if deltaY < 0.0 else 1.0 elif deltaX < 0.0: # Other lines should invert delta if start is right of the end delta *= -1.0 if pre: delta *= -1.0 startY = s.y prevX = s.x point = self.end else: startY = e.y prevX = e.x point = self.start if NumericUtils.equivalent(deltaX, 0.0): return s.x, startY + delta i = 0 while i < 100000: x = prevX + delta y = s.y + deltaY*(x - s.x)/deltaX testLengthSqr = math.pow(x - point.x, 2) + math.pow(y - point.y, 2) if NumericUtils.equivalent(testLengthSqr/targetLengthSqr, 1.0, 0.000001): return x, y elif testLengthSqr > targetLengthSqr: delta *= 0.5 else: prevX = x i += 1 raise ValueError('Unable to extrapolate line segment to specified length')
def test_linearSpace(self): """test_linearSpace doc...""" result = NumericUtils.linearSpace(0.0, 1.0, 10) self.assertTrue(len(result) == 10) self.assertAlmostEqual(0, result[0]) self.assertAlmostEqual(1.0, result[-1]) result = NumericUtils.linearSpace(-25.0, 25.0, 51) self.assertTrue(len(result) == 51) self.assertAlmostEqual(-25.0, result[0]) self.assertAlmostEqual(25.0, result[-1]) try: self.assertTrue(result.index(0.0)) except Exception: self.fail('Unexpected linear spacing')
def angleBetween(self, position): """angleBetween doc...""" myLength = self.length posLength = position.length denom = myLength.raw * posLength.raw denomUnc = math.sqrt( myLength.rawUncertainty * myLength.rawUncertainty + posLength.rawUncertainty * posLength.rawUncertainty) if denom == 0.0: return Angle(radians=0.0, uncertainty=0.5 * math.pi) nom = self.x * position.x + self.y * position.y nomUnc = (abs(position.x) * self.xUnc + abs(self.x) * position.xUnc + abs(position.y) * self.yUnc + abs(self.y) * position.yUnc) / denom b = nom / denom bUnc = abs(1.0/denom)*nomUnc + \ abs(nom/math.pow(denom, 2))*denomUnc if NumericUtils.equivalent(b, 1.0): return Angle() try: if NumericUtils.equivalent(b, -1.0): a = math.pi else: a = math.acos(b) except Exception: print('[ERROR]: Unable to calculate angle between', b) return Angle() if NumericUtils.equivalent(a, math.pi): return Angle(radians=a, uncertainty=180.0) try: aUnc = abs(1.0 / math.sqrt(1.0 - b * b)) * bUnc except Exception: print('[ERROR]: Unable to calculate angle between uncertainty', b, a) return Angle() return Angle(radians=a, uncertainty=aUnc)
def angleBetween(self, position): """angleBetween doc...""" myLength = self.length posLength = position.length denom = myLength.raw*posLength.raw denomUnc = math.sqrt( myLength.rawUncertainty*myLength.rawUncertainty + posLength.rawUncertainty*posLength.rawUncertainty) if denom == 0.0: return Angle(radians=0.0, uncertainty=0.5*math.pi) nom = self.x*position.x + self.y*position.y nomUnc = (abs(position.x)*self.xUnc + abs(self.x)*position.xUnc + abs(position.y)*self.yUnc + abs(self.y)*position.yUnc)/denom b = nom/denom bUnc = abs(1.0/denom)*nomUnc + \ abs(nom/math.pow(denom, 2))*denomUnc if NumericUtils.equivalent(b, 1.0): return Angle() try: if NumericUtils.equivalent(b, -1.0): a = math.pi else: a = math.acos(b) except Exception: print('[ERROR]: Unable to calculate angle between', b) return Angle() if NumericUtils.equivalent(a, math.pi): return Angle(radians=a, uncertainty=180.0) try: aUnc = abs(1.0/math.sqrt(1.0 - b*b))*bUnc except Exception: print('[ERROR]: Unable to calculate angle between uncertainty', b, a) return Angle() return Angle(radians=a, uncertainty=aUnc)
def _analyzeTrack(self, track, series, trackway, sitemap): trackId = '%s (%s)' % (track.fingerprint, track.uid) if NumericUtils.equivalent(track.width, 0.0): self.logger.write('[ERROR]: Zero track width %s' % trackId) if NumericUtils.equivalent(track.widthUncertainty, 0.0): self.logger.write('[ERROR]: Zero track width uncertainty %s' % trackId) if NumericUtils.equivalent(track.length, 0.0): self.logger.write('[ERROR]: Zero track length %s' % trackId) if NumericUtils.equivalent(track.lengthUncertainty, 0.0): self.logger.write('[ERROR]: Zero track length uncertainty %s' % trackId) self._tracks.append(track) x = track.xValue self._uncs.append(x.uncertainty) z = track.zValue self._uncs.append(z.uncertainty)
def test_toValueUncertainty(self): """test_toValueUncertainty doc...""" value = NumericUtils.toValueUncertainty(math.pi, 0.00456) self.assertEqual(value.value, 3.142, 'Values do not match %s' % value.label) self.assertEqual(value.uncertainty, 0.005, 'Uncertainties do not match %s' % value.label) value = NumericUtils.toValueUncertainty(100.0 * math.pi, 42.0) self.assertEqual(value.value, 310.0, 'Values do not match %s' % value.label) self.assertEqual(value.uncertainty, 40.0, 'Uncertainties do not match %s' % value.label) value = NumericUtils.toValueUncertainty(0.001 * math.pi, 0.000975) self.assertEqual(value.value, 0.003, 'Values do not match %s' % value.label) self.assertEqual(value.uncertainty, 0.001, 'Uncertainties do not match %s' % value.label)
def test_orderOfMagnitude(self): """test_orderOfMagnitude doc...""" testOrder = -9 while testOrder < 10: for i in range(25): value = random.uniform(1.0, 9.9)*math.pow(10.0, testOrder) result = NumericUtils.orderOfMagnitude(value) msg = 'Invalid Order %s != %s (%s)' % (result, testOrder, value) self.assertEqual(testOrder, result, msg) testOrder += 1
def zValue(self): """ Returns the z value as an uncertainty named tuple in units of meters """ r = math.pi/180.0*float(self.rotation) rUnc = math.pi/180.0*float(self.rotationUncertainty) wUnc = self.widthUncertainty lUnc = self.lengthUncertainty zUnc = lUnc*abs(math.cos(r)) + wUnc*abs(math.sin(r)) \ + rUnc*abs(wUnc*math.cos(r) - lUnc*math.sin(r)) return NumericUtils.toValueUncertainty(0.01*float(self.z), zUnc)
def test_orderOfMagnitude(self): """test_orderOfMagnitude doc...""" testOrder = -9 while testOrder < 10: for i in range(25): value = random.uniform(1.0, 9.9) * math.pow(10.0, testOrder) result = NumericUtils.orderOfMagnitude(value) msg = 'Invalid Order %s != %s (%s)' % (result, testOrder, value) self.assertEqual(testOrder, result, msg) testOrder += 1
def _processAspectRatios(self): """_processAspectRatios doc...""" aspects = [] pesAspects = [] manAspects = [] for entry in self.entries: value = entry['aspect'].value aspects.append(value) if entry['track'].pes: pesAspects.append(value) else: manAspects.append(value) self.logger.write('%s\nASPECT RATIO' % ('='*80)) self.logger.write('Total: %s' % NumericUtils.getMeanAndDeviation(aspects).label) self.logger.write('Pes: %s' % NumericUtils.getMeanAndDeviation(pesAspects).label) self.logger.write('Manus: %s' % NumericUtils.getMeanAndDeviation(manAspects).label) h = Histogram(data=aspects, color='green') h.title = 'Aspect Ratios' h.yLabel = 'Count' h.xLabel = 'Aspect Ratio (width/length)' self._paths.append(h.save(self.getTempFilePath(extension='pdf'))) h = Histogram(data=pesAspects, color='green') h.title = 'Aspect Ratios (Pes)' h.yLabel = 'Count' h.xLabel = 'Aspect Ratio (width/length)' self._paths.append(h.save(self.getTempFilePath(extension='pdf'))) h = Histogram(data=manAspects, color='green') h.title = 'Aspect Ratios (Manus)' h.yLabel = 'Count' h.xLabel = 'Aspect Ratio (width/length)' self._paths.append(h.save(self.getTempFilePath(extension='pdf')))
def slope(self): """ Returns the slope of the line as a ValueUncertainty named tuple. """ s = self.start e = self.end deltaX = e.x - s.x deltaY = e.y - s.y try: slope = deltaY/deltaX unc = abs(1.0/deltaX)*(s.yUnc + e.yUnc) + abs(slope/deltaX)*(s.xUnc + e.xUnc) return NumericUtils.toValueUncertainty(slope, unc) except Exception: return None
def _postAnalyze(self): """_postAnalyze doc...""" label = 'Both' lows, mids, highs, tsValues, twValues, totals = self._processSparsenessResults(None) self._paths.append(self._scatterSparseness(label, lows, mids, highs)) self._paths.append(self._histogramSeriesSparseness(label, tsValues)) self._paths.append(self._histogramTrackwaySparseness(label, twValues)) totalAve = NumericUtils.weightedAverage(*totals) self.logger.write('Total Average Spareness: %s' % totalAve.label) label = 'Pes' lows, mids, highs, tsValues, twValues, totals = self._processSparsenessResults('pes') self._paths.append(self._scatterSparseness(label, lows, mids, highs)) self._paths.append(self._histogramSeriesSparseness(label, tsValues)) self._paths.append(self._histogramTrackwaySparseness(label, twValues)) totalAve = NumericUtils.weightedAverage(*totals) self.logger.write('Total Average Pes Spareness: %s' % totalAve.label) label = 'Manus' lows, mids, highs, tsValues, twValues, totals = self._processSparsenessResults('manus') self._paths.append(self._scatterSparseness(label, lows, mids, highs)) self._paths.append(self._histogramSeriesSparseness(label, tsValues)) self._paths.append(self._histogramTrackwaySparseness(label, twValues)) totalAve = NumericUtils.weightedAverage(*totals) self.logger.write('Total Average Manus Spareness: %s' % totalAve.label) self.mergePdfs(self._paths, 'Trackway-Curve-Stats.pdf') # Add the reference series to the session object for storage in the Analysis_Trackway # table. This data persists because it is used later to rebuild track curves in other # analyzers. for uid, data in DictUtils.iter(self.data): trackway = data['trackway'] result = trackway.getAnalysisPair(self.analysisSession, createIfMissing=True) result.curveSeries = data['dense'].firstTrackUid if data['dense'] else ''
def _calculateAverageSpacing(cls, series): """ Determines the average spacing of the tracks in the track series for use as a comparative measure of sparseness to the other track series in the trackway. If the series is not ready or does not have a sufficient number of tracks, this method will return None. :param: series | TrackSeries The series on which to determine the average spacing. :return: ValueUncertainty A value uncertainty instance that represents the average spacing of the series, or None if it's the calculation is aborted. """ if not series.isReady: # Skip trackways with invalid series return None tracks = series.tracks if not tracks or len(tracks) < 2: # Ignore series with less than two tracks return None length = 0.0 uncs = [] for i in ListUtils.range(len(tracks) - 1): line = LineSegment2D( start=tracks[i].positionValue, end=tracks[i + 1].positionValue) spacing = line.length length += spacing.value uncs.append(spacing.uncertainty) unc = NumericUtils.sqrtSumOfSquares(*uncs) return NumericUtils.toValueUncertainty( value=length/float(len(tracks)), uncertainty=unc/float(len(tracks)) )
def getNormalityColor(normality, goodChannel, badChannel): if NumericUtils.equivalent(normality, -1.0, 0.01): return ColorValue({'r':100, 'g':100, 'b':100}) test = min(1.0, max(0.0, normality)) limit = NORMAL_THRESHOLD slope = 1.0/(1.0 - limit) intercept = -slope*limit test = min(1.0, max(0.0, slope*test + intercept)) color = dict(r=0.0, b=0.0, g=0.0) color[badChannel] = max(0, 255.0*min(1.0, 1.0 - 1.0*test)) color[goodChannel] = max(0, min(255, 255.0*test)) return ColorValue(color)
def _processSparsenessResults(self, key): """_processSparsenessResults doc...""" index = 0 means = [] totals = [] twValues = [] tsValues = [] lows = dict(x=[], y=[], error=[], color='#666666') mids = dict(x=[], y=[], error=[], color='#33CC33') highs = dict(x=[], y=[], error=[], color='#CC3333') for uid, entry in DictUtils.iter(self.data): # For each test list in track ratings process the data and filter it into the correct # segments for plotting. data = (entry['pes'] + entry['manus']) if not key else entry[key] data = ListUtils.sortObjectList(data, 'value') index += 1 if len(data) < 2: continue average = NumericUtils.weightedAverage(*data[1:]) means.append(average) totals.extend(data[1:]) twValues.append(average.value) maxVal = data[0] for v in data[1:]: if v.value > maxVal.value: maxVal = v if maxVal.value < 15.0: target = lows elif maxVal.value < 50.0: target = mids else: target = highs for v in data[1:]: tsValues.append(v.value) target['x'].append(index) target['y'].append(v.value) target['error'].append(v.uncertainty) return lows, mids, highs, tsValues, twValues, totals
def getDebugReport(self): out = ['\nTRACKWAY[%s]:' % self.trackway.name] for segment in self.segments: out.append( ' TRACK: %s' % (segment.track.fingerprint if segment.track else 'NONE')) for item in segment.pairs: out.append( ' * %s (%s)' % ( item['track'].fingerprint, NumericUtils.roundToSigFigs(item['distance'], 5) )) for debugItem in item['debug']: out.append(' - %s' % DictUtils.prettyPrint(debugItem['print'])) return '\n'.join(out)
def _drawWidth(self, track, drawing, color ='orange', strokeWidth =0.5): if NumericUtils.equivalent(track.widthMeasured, 0.0): return w = 100*track.width rot = math.radians(track.rotation) x1 = w/2.0 x2 = -w/2.0 drawing.line( (track.x + x1*math.cos(rot), track.z - x1*math.sin(rot)), (track.x + x2*math.cos(rot), track.z - x2*math.sin(rot)), scene=True, stroke=color, stroke_width=strokeWidth)
def test_roundToOrder(self): """test_roundToOrder doc...""" self.assertAlmostEqual(123.3, NumericUtils.roundToOrder(123.345, -1)) # Using the round operator, which rounds 5 up when odd, down when even self.assertAlmostEqual(123.34, NumericUtils.roundToOrder(123.345, -2)) self.assertAlmostEqual(123.36, NumericUtils.roundToOrder(123.355, -2)) self.assertAlmostEqual(123, NumericUtils.roundToOrder(123.345, 0)) self.assertAlmostEqual(120, NumericUtils.roundToOrder(123.345, 1)) self.assertAlmostEqual(100, NumericUtils.roundToOrder(123.345, 2))
def distanceTo(self, position): """distanceBetween doc...""" xDelta = self.x - position.x yDelta = self.y - position.y distance = math.sqrt(xDelta * xDelta + yDelta * yDelta) # Use the absolute value because the derivatives in error propagation are always # absolute values xDelta = abs(xDelta) yDelta = abs(yDelta) try: error = (xDelta * (self.xUnc + position.xUnc) + yDelta * (self.yUnc + position.yUnc)) / distance except ZeroDivisionError: error = 1.0 return NumericUtils.toValueUncertainty(distance, error)
def __str__(self): return '<%s %s>' % (self.__class__.__name__, NumericUtils.roundToSigFigs(self.degrees, 3))
def test_sqrtSumOfSquares(self): """test_sqrtSumOfSquares doc...""" self.assertEqual(1.0, NumericUtils.sqrtSumOfSquares(-1.0)) self.assertEqual(math.sqrt(2), NumericUtils.sqrtSumOfSquares(1.0, 1.0)) self.assertEqual(math.sqrt(4.25), NumericUtils.sqrtSumOfSquares(2.0, 0.5))
def test_equivalent(self): """test_equivalent doc...""" self.assertTrue(NumericUtils.equivalent(1.0, 1.001, 0.01)) self.assertFalse(NumericUtils.equivalent(1.0, 1.011, 0.01))
def xValue(self): return NumericUtils.toValueUncertainty(self.x, self.xUnc)
def value(self): return NumericUtils.toValueUncertainty(self.radians, self.uncertainty)
def yValue(self): return NumericUtils.toValueUncertainty(self.y, self.yUnc)
def rawLabel(self): if self._asciiLabels: return self.asciiRawLabel return '%s %s %s' % (NumericUtils.roundToSigFigs( self.raw, 6), StringUtils.unichr(0x00B1), self.uncertainty)
def value(self): uncertainty = self.uncertainty order = NumericUtils.orderOfLeastSigFig(uncertainty) return NumericUtils.roundToOrder(self._raw, order)
def uncertainty(self): return NumericUtils.roundToSigFigs(abs(self._rawUncertainty), 1)
def prettyPrint(self): return StringUtils.toText(NumericUtils.roundToSigFigs(self.degrees, 3))
def asciiRawLabel(self): return '%s +/- %s' % (NumericUtils.roundToSigFigs(self.raw, 6), self.uncertainty)
def valueDegrees(self): return NumericUtils.toValueUncertainty(self.degrees, self.uncertaintyDegrees)