@@ -365,8 +365,6 @@ nv.addGraph(function() {
365
365
// x-axis is contest time
366
366
// y axis is # of submissions
367
367
368
- var max_submissions_per_minute = 0 ;
369
-
370
368
var submission_stats = [
371
369
{% for result in [' correct' , ' wrong-answer' , ' timelimit' , ' run-error' , ' compiler-error' , ' no-output' ] %}
372
370
{
@@ -377,20 +375,44 @@ var submission_stats = [
377
375
{% endfor %}
378
376
];
379
377
380
- var submissions = [
378
+ const contest_start_time = {{ current_contest .starttime }};
379
+ const submissions = [
381
380
{% for submission in submissions %}
382
381
{
383
382
result: " {{ submission.result }}" ,
384
383
submittime: {{ submission .submittime }},
385
- starttime: {{ current_contest .starttime }}
386
384
}{{ loop .last ? ' ' : ' ,' }}
387
385
{% endfor %}
388
386
];
389
387
390
- var contest_duration_minutes = Math .ceil (({{ current_contest .endtime }} - {{ current_contest .starttime }}) / 60 );
388
+ const min_bucket_count = 30 ;
389
+ const max_bucket_count = 301 ;
390
+ const units = [
391
+ {' name' : ' seconds' , ' convert' : 1 , ' step' : 60 },
392
+ {' name' : ' minutes' , ' convert' : 60 , ' step' : 15 },
393
+ {' name' : ' hours' , ' convert' : 60 * 60 , ' step' : 6 },
394
+ {' name' : ' days' , ' convert' : 60 * 60 * 24 , ' step' : 7 },
395
+ {' name' : ' weeks' , ' convert' : 60 * 60 * 24 * 7 , ' step' : 1 },
396
+ {' name' : ' years' , ' convert' : 60 * 60 * 24 * 365 , ' step' : 1 }
397
+ ];
398
+ let unit = units[0 ];
399
+
400
+ let contest_duration = {{ (current_contest .endtime - current_contest .starttime ) | round(0 , ' ceil' ) }};
401
+ for (let u of units) {
402
+ const new_duration = Math .ceil (contest_duration / u .convert );
403
+ if (new_duration > min_bucket_count) {
404
+ unit = u;
405
+ } else {
406
+ break ;
407
+ }
408
+ }
409
+ contest_duration = Math .ceil (contest_duration / unit .convert );
410
+ const bucket_count = Math .min (contest_duration + 1 , max_bucket_count);
411
+ // Make sure buckets have whole unit
412
+ const seconds_per_bucket = Math .ceil (contest_duration / (bucket_count - 1 )) * unit .convert ;
391
413
392
414
submission_stats .forEach (stat => {
393
- stat .values = Array .from ({ length: contest_duration_minutes + 1 }, (_ , i ) => [i, 0 ]);
415
+ stat .values = Array .from ({ length: bucket_count }, (_ , i ) => [i * seconds_per_bucket / unit . convert , 0 ]);
394
416
});
395
417
396
418
const statMap = submission_stats .reduce ((map , stat ) => {
@@ -399,27 +421,30 @@ const statMap = submission_stats.reduce((map, stat) => {
399
421
}, {});
400
422
401
423
submissions .forEach (submission => {
402
- let submission_minute = Math .floor ((submission .submittime - submission . starttime ) / 60 );
403
- let stat = statMap[submission .result ];
404
- if (stat && submission_minute >= 0 && submission_minute < contest_duration_minutes ) {
405
- stat .values [submission_minute ][1 ]++ ;
424
+ const submission_bucket = Math .floor ((submission .submittime - contest_start_time ) / seconds_per_bucket );
425
+ const stat = statMap[submission .result ];
426
+ if (stat && submission_bucket >= 0 && submission_bucket < bucket_count ) {
427
+ stat .values [submission_bucket ][1 ]++ ;
406
428
}
407
429
});
408
430
409
- for (let minute = 0 ; minute <= contest_duration_minutes; minute++ ) {
410
- let this_minute_submission_nums = 0 ;
431
+ let max_submissions_per_bucket = 1
432
+ for (let bucket = 0 ; bucket < bucket_count; bucket++ ) {
433
+ let sum = 0 ;
411
434
submission_stats .forEach (stat => {
412
- this_minute_submission_nums += stat .values [minute ][1 ];
435
+ sum += stat .values [bucket ][1 ];
413
436
});
414
- max_submissions_per_minute = Math .max (max_submissions_per_minute, this_minute_submission_nums );
437
+ max_submissions_per_bucket = Math .max (max_submissions_per_bucket, sum );
415
438
}
416
439
417
- // Pick a nice round tickDelta and tickValues
418
- var tickDelta = 15 ;
419
- while (contest_duration_minutes / tickDelta > 15 ) {
420
- tickDelta *= 2 ;
421
- }
422
- var tickValues = Array .from ({ length: Math .ceil (contest_duration_minutes / tickDelta) + 1 }, (_ , i ) => i * tickDelta);
440
+ // Pick a nice round tickDelta and tickValues based on the step size of units.
441
+ // We want whole values in the unit, and the ticks MUST match a corresponding bucket otherwise the resulting
442
+ // coordinate will be NaN.
443
+ const convert_factor = seconds_per_bucket / unit .convert ;
444
+ const maxTicks = Math .min (bucket_count, contest_duration / unit .step , min_bucket_count)
445
+ const tickDelta = convert_factor * Math .ceil (contest_duration / (maxTicks * convert_factor));
446
+ const ticks = Math .floor (contest_duration / tickDelta) + 1 ;
447
+ const tickValues = Array .from ({ length: ticks }, (_ , i ) => i * tickDelta);
423
448
424
449
nv .addGraph (function () {
425
450
var chart = nv .models .multiBarChart ()
@@ -436,7 +461,7 @@ nv.addGraph(function() {
436
461
.reduceXTicks (false )
437
462
;
438
463
chart .xAxis // Chart x-axis settings
439
- .axisLabel (' Contest Time(minutes) ' )
464
+ .axisLabel (` Contest Time ( ${ unit . name } ) ` )
440
465
.ticks (tickValues .length )
441
466
.tickValues (tickValues)
442
467
.tickFormat (d3 .format (' d' ));
0 commit comments