@@ -338,14 +338,10 @@ nv.addGraph(function() {
338
338
return chart;
339
339
});
340
340
341
-
342
341
// ////////////////////////////////////
343
342
// Submissions over time
344
- // stacked graph of correct, runtime-error, wrong-answer, compiler-error, timelimit, etc
345
- // x-axis is contest time
346
- // y axis is # of submissions
347
343
348
- var submission_stats = [
344
+ const submission_stats = [
349
345
{% for result in [' correct' , ' wrong-answer' , ' timelimit' , ' run-error' , ' compiler-error' , ' no-output' ] %}
350
346
{
351
347
key: " {{result}}" ,
@@ -354,8 +350,8 @@ var submission_stats = [
354
350
},
355
351
{% endfor %}
356
352
];
357
-
358
353
const contest_start_time = {{ current_contest .starttime }};
354
+ const contest_duration_seconds = {{ (current_contest .endtime - current_contest .starttime ) | round(0 , ' ceil' ) }};
359
355
const submissions = [
360
356
{% for submission in submissions %}
361
357
{
@@ -364,98 +360,7 @@ const submissions = [
364
360
}{{ loop .last ? ' ' : ' ,' }}
365
361
{% endfor %}
366
362
];
367
-
368
- const min_bucket_count = 30 ;
369
- const max_bucket_count = 301 ;
370
- const units = [
371
- {' name' : ' seconds' , ' convert' : 1 , ' step' : 60 },
372
- {' name' : ' minutes' , ' convert' : 60 , ' step' : 15 },
373
- {' name' : ' hours' , ' convert' : 60 * 60 , ' step' : 6 },
374
- {' name' : ' days' , ' convert' : 60 * 60 * 24 , ' step' : 7 },
375
- {' name' : ' weeks' , ' convert' : 60 * 60 * 24 * 7 , ' step' : 1 },
376
- {' name' : ' years' , ' convert' : 60 * 60 * 24 * 365 , ' step' : 1 }
377
- ];
378
- let unit = units[0 ];
379
-
380
- let contest_duration = {{ (current_contest .endtime - current_contest .starttime ) | round(0 , ' ceil' ) }};
381
- for (let u of units) {
382
- const new_duration = Math .ceil (contest_duration / u .convert );
383
- if (new_duration > min_bucket_count) {
384
- unit = u;
385
- } else {
386
- break ;
387
- }
388
- }
389
- contest_duration = Math .ceil (contest_duration / unit .convert );
390
- const bucket_count = Math .min (contest_duration + 1 , max_bucket_count);
391
- // Make sure buckets have whole unit
392
- const seconds_per_bucket = Math .ceil (contest_duration / (bucket_count - 1 )) * unit .convert ;
393
-
394
- submission_stats .forEach (stat => {
395
- stat .values = Array .from ({ length: bucket_count }, (_ , i ) => [i * seconds_per_bucket / unit .convert , 0 ]);
396
- });
397
-
398
- const statMap = submission_stats .reduce ((map , stat ) => {
399
- map[stat .key ] = stat;
400
- return map;
401
- }, {});
402
-
403
- submissions .forEach (submission => {
404
- const submission_bucket = Math .floor ((submission .submittime - contest_start_time) / seconds_per_bucket);
405
- const stat = statMap[submission .result ];
406
- if (stat && submission_bucket >= 0 && submission_bucket < bucket_count) {
407
- stat .values [submission_bucket][1 ]++ ;
408
- }
409
- });
410
-
411
- let max_submissions_per_bucket = 1
412
- for (let bucket = 0 ; bucket < bucket_count; bucket++ ) {
413
- let sum = 0 ;
414
- submission_stats .forEach (stat => {
415
- sum += stat .values [bucket][1 ];
416
- });
417
- max_submissions_per_bucket = Math .max (max_submissions_per_bucket, sum);
418
- }
419
-
420
- // Pick a nice round tickDelta and tickValues based on the step size of units.
421
- // We want whole values in the unit, and the ticks MUST match a corresponding bucket otherwise the resulting
422
- // coordinate will be NaN.
423
- const convert_factor = seconds_per_bucket / unit .convert ;
424
- const maxTicks = Math .min (bucket_count, contest_duration / unit .step , min_bucket_count)
425
- const tickDelta = convert_factor * Math .ceil (contest_duration / (maxTicks * convert_factor));
426
- const ticks = Math .floor (contest_duration / tickDelta) + 1 ;
427
- const tickValues = Array .from ({ length: ticks }, (_ , i ) => i * tickDelta);
428
-
429
- nv .addGraph (function () {
430
- var chart = nv .models .multiBarChart ()
431
- // .margin({left: 100}) //Adjust chart margins to give the x-axis some breathing room.
432
- // .useInteractiveGuideline(true) //We want nice looking tooltips and a guideline!
433
- // .transitionDuration(350) //how fast do you want the lines to transition?
434
- // .showLegend(true) //Show the legend, allowing users to turn on/off line series.
435
- .showControls (false )
436
- .stacked (true )
437
- .x (function (d ) { return d[0 ] }) // We can modify the data accessor functions...
438
- .y (function (d ) { return d[1 ] }) // ...in case your data is formatted differently.
439
- .showYAxis (true ) // Show the y-axis
440
- .showXAxis (true ) // Show the x-axis
441
- .reduceXTicks (false )
442
- ;
443
- chart .xAxis // Chart x-axis settings
444
- .axisLabel (` Contest Time (${ unit .name } )` )
445
- .ticks (tickValues .length )
446
- .tickValues (tickValues)
447
- .tickFormat (d3 .format (' d' ));
448
- chart .yAxis // Chart y-axis settings
449
- .axisLabel (' Total Submissions' )
450
- .tickFormat (d3 .format (' d' ));
451
-
452
- d3 .select (' #graph_submissions svg' )
453
- .datum (submission_stats)
454
- .call (chart);
455
- nv .utils .windowResize (chart .update );
456
- return chart;
457
- });
458
-
363
+ createSubmissionGraph (submission_stats, contest_start_time, contest_duration_seconds, submissions);
459
364
460
365
</script >
461
366
{% include ' jury/analysis/download_graphs.html.twig' %}
0 commit comments