phetsims / projectile-data-lab

"Projectile Data Lab" is an educational simulation in HTML5, by PhET Interactive Simulations.
GNU General Public License v3.0
0 stars 0 forks source link

Standard deviation and standard error are not zero with one data point #156

Closed matthew-blackman closed 7 months ago

matthew-blackman commented 7 months ago

Our sim currently shows value of zero for standard deviation and standard error when there is only one data point. This is inconsistent with CODAP, which does not show anything. It is also inconsistent with Google Sheets and Excel, which show a divide by zero error. Discussing this with @catherinecarter and @samreid, we agreed to try omitting the values and display for standard deviation and standard error when there are fewer than 2 data points.

samreid commented 7 months ago

The N-1 commit sneaked in with https://github.com/phetsims/projectile-data-lab/commit/3b5f4f700dd2499e6663bed1dc622baa722ebfa5

samreid commented 7 months ago

Good patch to continue with:

```diff Subject: [PATCH] Update projectile landing sounds, see https://github.com/phetsims/projectile-data-lab/issues/140 --- Index: js/measures/view/MeasuresHistogramNode.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/js/measures/view/MeasuresHistogramNode.ts b/js/measures/view/MeasuresHistogramNode.ts --- a/js/measures/view/MeasuresHistogramNode.ts (revision 26598006bac2fe90bffc59bed60e8ec2747ce28b) +++ b/js/measures/view/MeasuresHistogramNode.ts (date 1707843338461) @@ -77,6 +77,8 @@ return nullableNumber === null ? '' : Utils.toFixed( nullableNumber, 2 ); } ); + const isNonNullProperty = new DerivedProperty( [ standardDeviationProperty ], standardDeviation => standardDeviation !== null ); + const dataLabels = [ new PDLText( new PatternStringProperty( ProjectileDataLabStrings.meanXBarEqualsValueMPatternStringProperty, { value: roundedStringProperty( meanProperty ) } ), { @@ -84,11 +86,13 @@ } ), new PDLText( new PatternStringProperty( ProjectileDataLabStrings.standardDeviationEqualsValueMPatternStringProperty, { value: roundedStringProperty( standardDeviationProperty ) } ), { - font: PDLConstants.HISTOGRAM_PANEL_FONT + font: PDLConstants.HISTOGRAM_PANEL_FONT, + visibleProperty: isNonNullProperty } ), new PDLText( new PatternStringProperty( ProjectileDataLabStrings.standardErrorOfXBarEqualsValueMPatternStringProperty, { value: roundedStringProperty( standardErrorProperty ) } ), { - font: PDLConstants.HISTOGRAM_PANEL_FONT + font: PDLConstants.HISTOGRAM_PANEL_FONT, + visibleProperty: isNonNullProperty } ) ]; Index: js/measures/model/MeasuresField.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/js/measures/model/MeasuresField.ts b/js/measures/model/MeasuresField.ts --- a/js/measures/model/MeasuresField.ts (revision 26598006bac2fe90bffc59bed60e8ec2747ce28b) +++ b/js/measures/model/MeasuresField.ts (date 1707843137764) @@ -87,8 +87,9 @@ this.projectileLandedEmitter.addListener( () => { this.meanDistanceProperty.value = _.mean( this.landedProjectiles.map( landedProjectile => landedProjectile.x ) ); - this.standardDeviationDistanceProperty.value = this.getStandardDeviationDistance(); - this.standardErrorDistanceProperty.value = this.getStandardDeviationDistance() / Math.sqrt( this.landedProjectiles.length ); + const standardDeviation = this.getStandardDeviationDistance(); + this.standardDeviationDistanceProperty.value = standardDeviation; + this.standardErrorDistanceProperty.value = standardDeviation === null ? null : standardDeviation / Math.sqrt( this.landedProjectiles.length ); } ); // if the user changes the mystery launcher, set the launcher property to the corresponding launcher @@ -107,7 +108,7 @@ } ); } - private getStandardDeviationDistance(): number { + private getStandardDeviationDistance(): number | null { let sum = 0; let count = 0; const average = _.mean( this.landedProjectiles.map( landedProjectile => landedProjectile.x ) ); @@ -116,7 +117,7 @@ sum += Math.pow( landedProjectile.x - average, 2 ); count++; } ); - return count > 1 ? Math.sqrt( sum / ( count - 1 ) ) : 0; + return count > 1 ? Math.sqrt( sum / ( count - 1 ) ) : null; } public override clearProjectiles(): void { ```
samreid commented 7 months ago

@matthew-blackman and I fixed it up. Closing.