-
Notifications
You must be signed in to change notification settings - Fork 9.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
plots: dashboard - identify variance over lighthouse versions #2520
Conversation
…nto plots-better-out
…nto plots-dashboard
…nto plots-dashboard
Codecov Report
@@ Coverage Diff @@
## master #2520 +/- ##
==========================================
- Coverage 84.52% 83.68% -0.84%
==========================================
Files 169 177 +8
Lines 5614 5780 +166
Branches 774 801 +27
==========================================
+ Hits 4745 4837 +92
- Misses 855 923 +68
- Partials 14 20 +6
Continue to review full report at Codecov.
|
@patrickhulce @paulirish - please take a look. |
plots/dashboard/dashboard.css
Outdated
color: white; | ||
padding: 15px; | ||
font-size: 16px; | ||
background-color: #3367d6; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wanna put any of these colors in same vars? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
plots/dashboard/dashboard.js
Outdated
let currentMetric = metrics[0]; | ||
let numberOfBatchesToShow = 0; | ||
|
||
function main() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this file is kinda hard to follow and grok, wdyt about grouping some of these into classes/objects/sections by usage? i.e. event handlers, rendering, init, etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
plots/dashboard/index.html
Outdated
<html> | ||
|
||
<head> | ||
<script src="https://cdn.plot.ly/plotly-1.25.2.min.js"></script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blocking script in head! 😱 :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bumped down to body.
{ | ||
"main": "index.js", | ||
"scripts": { | ||
"measure": "node measure.js", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aw I liked yarn measure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the reason why I removed it is because passing flags through yarn or npm can be unintuitive (e.g. yarn measure -- --flag
) and I'm guessing most of the time we're using these scripts with flags. In a f/u PR, I can look into using npm link
and then we could have something like (plots measure --out out-hi
) but I think we should cross that bridge later (e.g. when plots becomes useful outside of the core team).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah sgtm
|
||
const renderingScheduler = new RenderingScheduler(); | ||
const charts = new Charts(renderingScheduler); | ||
const dashboard = new Dashboard(metrics, charts); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
niiiiice muuuuch easier to follow!
minor nit, personally I like to separate the rendering logic from a constructor to an explicit render()
method so it's clear what attaches to the DOM and what does basic setup and whatnot (if there's no need to keep instance variables at all some could even be static and the classes just used for logical grouping but totally up to you)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks, done. I'll keep the instance variables (otherwise I think I'd need to use singletons or global variables).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh yeah wasn't implying that you should make them static, just that if it shook out without the need for instance variables didn't have to keep em that way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, please take another look.
plots/dashboard/dashboard.css
Outdated
color: white; | ||
padding: 15px; | ||
font-size: 16px; | ||
background-color: #3367d6; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
plots/dashboard/index.html
Outdated
<html> | ||
|
||
<head> | ||
<script src="https://cdn.plot.ly/plotly-1.25.2.min.js"></script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bumped down to body.
{ | ||
"main": "index.js", | ||
"scripts": { | ||
"measure": "node measure.js", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the reason why I removed it is because passing flags through yarn or npm can be unintuitive (e.g. yarn measure -- --flag
) and I'm guessing most of the time we're using these scripts with flags. In a f/u PR, I can look into using npm link
and then we could have something like (plots measure --out out-hi
) but I think we should cross that bridge later (e.g. when plots becomes useful outside of the core team).
plots/dashboard/dashboard.js
Outdated
let currentMetric = metrics[0]; | ||
let numberOfBatchesToShow = 0; | ||
|
||
function main() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
|
||
const renderingScheduler = new RenderingScheduler(); | ||
const charts = new Charts(renderingScheduler); | ||
const dashboard = new Dashboard(metrics, charts); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks, done. I'll keep the instance variables (otherwise I think I'd need to use singletons or global variables).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking good.
I haven't looked carefully enough to answer this for myself: That Note: null results are treated as 0
note, does that include when calculating percentiles?
@@ -0,0 +1,41 @@ | |||
<!doctype html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
license header
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
<script src="./dashboard.js"></script> | ||
</body> | ||
|
||
</html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -0,0 +1,119 @@ | |||
* { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
license
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
plots/README.md
Outdated
$ node generate-dashboard.js --input-root dir-with-subdirectories | ||
|
||
# Or you can specify each input directory explicitly | ||
$ node generated-dashboard.js --inputs out-1 out-2 out-3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
generated => generate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup
plots/generate-dashboard.js
Outdated
.example('node $0 --input-root dir-with-subdirectories') | ||
.example('node $0 --inputs out-1 out-2 out-3') | ||
.describe({ | ||
'inputs': 'paths to out directory generated by measure.js', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we instead have a single --input
? (And tbh, at that point, you might as well skip the arg).
It'd look like this:
node generate-dashboard out-a out-b out-x
node generate-dashboard outParentFolder
Take the directory or its children, depending on the contents
plots/generate-dashboard.js
Outdated
for (const inputPath of inputPaths) { | ||
childProcess.execSync(`node analyze.js ${inputPath}`, { | ||
env: Object.assign({}, process.env, { | ||
CI: '1' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a comment that this is to prevent opn() from running.
and collapse this Obj.assign into one line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brendankenny - yeah, null is treated as 0 in when calculating the percentiles.
@paulirish - ptal. thanks!
plots/README.md
Outdated
$ node generate-dashboard.js --input-root dir-with-subdirectories | ||
|
||
# Or you can specify each input directory explicitly | ||
$ node generated-dashboard.js --inputs out-1 out-2 out-3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup
@@ -0,0 +1,119 @@ | |||
* { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -0,0 +1,41 @@ | |||
<!doctype html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
<script src="./dashboard.js"></script> | ||
</body> | ||
|
||
</html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
plots/generate-dashboard.js
Outdated
for (const inputPath of inputPaths) { | ||
childProcess.execSync(`node analyze.js ${inputPath}`, { | ||
env: Object.assign({}, process.env, { | ||
CI: '1' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
can they be filtered out before calculating? Adding 0s to the sample will bring the median downward when usually (but not always) missing results come from what would be much higher values. For the time being we could filter nulls out and then in the future add something like a warning that there were too many missing values in a |
@brendankenny I tried out your suggestion and ran into an issue when all the runs for a particular batch of results for a site have a null value. Essentially plotly gets confused about where to plot. I think we can go with treating null as 0 for now and then figuring out a better solution in a f/u PR. Before (treating null as 0)After (filtering null) |
hmm, if nulls are filtered out of the array before calling (unless that's what you did and I'm missing the step that's messing up the graph) |
@brendankenny updated it so it retuns 0 if the array is empty (before if the array was empty it was returning undefined). |
plots/dashboard/dashboard.js
Outdated
if (array.length === 0) { | ||
return 0; | ||
} | ||
if (percentile <= 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't it need to be sorted before these?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep - fixed.
plots/dashboard/dashboard.js
Outdated
if (percentile >= 1) { | ||
return array[array.length - 1]; | ||
} | ||
const sorted = array.slice().sort((a, b) => a - b).filter(x => x !== null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: if it does filter()
first it can ditch the slice()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
plots/dashboard/dashboard.js
Outdated
return sorted[lower] || 0; | ||
} | ||
return sorted[lower] * (1 - weight) + sorted[upper] * weight; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how do you feel about
calculatePercentile(array, percentile) {
const sorted = array.filter(x => x !== null).sort((a, b) => a - b);
if (sorted.length === 0) {
return 0;
}
if (sorted.length === 1 || percentile <= 0) {
return sorted[0];
}
if (percentile >= 1) {
return sorted[sorted.length - 1];
}
const index = (sorted.length - 1) * percentile;
const lower = Math.floor(index);
const upper = lower + 1;
const weight = index % 1;
return sorted[lower] * (1 - weight) + sorted[upper] * weight;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good.
…nto plots-dashboard
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brendankenny thanks - updated per your comments.
plots/dashboard/dashboard.js
Outdated
if (array.length === 0) { | ||
return 0; | ||
} | ||
if (percentile <= 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep - fixed.
plots/dashboard/dashboard.js
Outdated
if (percentile >= 1) { | ||
return array[array.length - 1]; | ||
} | ||
const sorted = array.slice().sort((a, b) => a - b).filter(x => x !== null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
plots/dashboard/dashboard.js
Outdated
return sorted[lower] || 0; | ||
} | ||
return sorted[lower] * (1 - weight) + sorted[upper] * weight; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Updated code: please review the code :)
Example:
![screenshot from 2017-06-29 14 40 29](https://user-images.githubusercontent.com/7344640/27711747-f2dfd1ce-5cd8-11e7-9e3c-994d990d2a80.png)
If you need some dummy data, you can copy this file into
plots/out/dashboard-results.js
and then opendashboard/index.html
or I can show you the demo in person.addresses part of: #2413