Skip to content

Commit

Permalink
Add multi metric leaderboard
Browse files Browse the repository at this point in the history
  • Loading branch information
Ram81 committed Jun 20, 2021
1 parent 978367b commit df0b6a9
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.2.13 on 2021-06-20 14:33

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("challenges", "0084_challenge_is_static_dataset_code_upload"),
]

operations = [
migrations.AddField(
model_name="challenge",
name="is_multi_metric_leaderboard",
field=models.BooleanField(default=False),
),
]
2 changes: 2 additions & 0 deletions apps/challenges/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ def __init__(self, *args, **kwargs):
desired_worker_instance = models.IntegerField(
null=True, blank=True, default=1
)
# Allow ordering leaderboard by all metrics
is_multi_metric_leaderboard = models.BooleanField(default=False)

class Meta:
app_label = "challenges"
Expand Down
8 changes: 8 additions & 0 deletions apps/challenges/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class Meta:
"cli_version",
"remote_evaluation",
"workers",
"is_multi_metric_leaderboard",
)


Expand Down Expand Up @@ -141,6 +142,7 @@ class ChallengePhaseSplitSerializer(serializers.ModelSerializer):

dataset_split_name = serializers.SerializerMethodField()
challenge_phase_name = serializers.SerializerMethodField()
leaderboard_schema = serializers.SerializerMethodField()

class Meta:
model = ChallengePhaseSplit
Expand All @@ -153,8 +155,13 @@ class Meta:
"visibility",
"show_leaderboard_by_latest_submission",
"show_execution_time",
"leaderboard_schema",
)

def get_leaderboard_schema(self, obj):
print(obj.leaderboard.schema)
return obj.leaderboard.schema

def get_dataset_split_name(self, obj):
return obj.dataset_split.name

Expand Down Expand Up @@ -258,6 +265,7 @@ class Meta:
"max_worker_instance",
"min_worker_instance",
"desired_worker_instance",
"is_multi_metric_leaderboard",
)


Expand Down
12 changes: 11 additions & 1 deletion apps/jobs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ def handle_submission_rerun(submission, updated_status):


def calculate_distinct_sorted_leaderboard_data(
user, challenge_obj, challenge_phase_split, only_public_entries
user, challenge_obj, challenge_phase_split, only_public_entries, order_by
):
"""
Function to calculate and return the sorted leaderboard data
Expand All @@ -253,13 +253,23 @@ def calculate_distinct_sorted_leaderboard_data(
leaderboard = challenge_phase_split.leaderboard

# Get the default order by key to rank the entries on the leaderboard
default_order_by = None
try:
default_order_by = leaderboard.schema["default_order_by"]
except KeyError:
response_data = {
"error": "Sorry, default_order_by key is missing in leaderboard schema!"
}
return response_data, status.HTTP_400_BAD_REQUEST
# Use order by field from request only if it is valid
try:
if order_by in leaderboard.schema["labels"]:
default_order_by = order_by
except KeyError:
response_data = {
"error": "Sorry, labels key is missing in leaderboard schema!"
}
return response_data, status.HTTP_400_BAD_REQUEST

# Exclude the submissions done by members of the host team
# while populating leaderboard
Expand Down
6 changes: 4 additions & 2 deletions apps/jobs/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ def change_submission_data_and_visibility(


@swagger_auto_schema(
methods=["get"],
methods=["get", "post"],
manual_parameters=[
openapi.Parameter(
name="challenge_phase_split_id",
Expand Down Expand Up @@ -574,7 +574,7 @@ def change_submission_data_and_visibility(
)
},
)
@api_view(["GET"])
@api_view(["GET", "POST"])
@throttle_classes([AnonRateThrottle])
def leaderboard(request, challenge_phase_split_id):
"""
Expand All @@ -592,6 +592,7 @@ def leaderboard(request, challenge_phase_split_id):
challenge_phase_split_id
)
challenge_obj = challenge_phase_split.challenge_phase.challenge
order_by = request.data.get("order_by")
(
response_data,
http_status_code,
Expand All @@ -600,6 +601,7 @@ def leaderboard(request, challenge_phase_split_id):
challenge_obj,
challenge_phase_split,
only_public_entries=True,
order_by=order_by,
)
# The response 400 will be returned if the leaderboard isn't public or `default_order_by` key is missing in leaderboard.
if http_status_code == status.HTTP_400_BAD_REQUEST:
Expand Down
27 changes: 21 additions & 6 deletions frontend/src/js/controllers/challengeCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@
vm.projectUrl = "";
vm.publicationUrl = "";
vm.isPublicSubmission = null;
vm.isMultiMetricLeaderboardEnabled = false;
vm.wrnMsg = {};
vm.page = {};
vm.isParticipated = false;
vm.isActive = false;
vm.phases = {};
vm.phaseSplits = {};
vm.orderLeaderboardBy = decodeURIComponent($stateParams.metric);
vm.phaseSplitLeaderboardSchema = {};
vm.submissionMetaAttributes = []; // Stores the attributes format and phase ID for all the phases of a challenge.
vm.metaAttributesforCurrentSubmission = null; // Stores the attributes while making a submission for a selected phase.
vm.selectedPhaseSplit = {};
Expand Down Expand Up @@ -309,6 +312,7 @@
vm.isRegistrationOpen = details.is_registration_open;
vm.approved_by_admin = details.approved_by_admin;
vm.isRemoteChallenge = details.remote_evaluation;
vm.isMultiMetricLeaderboardEnabled = details.is_multi_metric_leaderboard;
vm.getTeamName(vm.challengeId);

if (vm.page.image === null) {
Expand Down Expand Up @@ -825,6 +829,7 @@
vm.phaseSplits[i].showPrivate = true;
vm.showPrivateIds.push(vm.phaseSplits[i].id);
}
vm.phaseSplitLeaderboardSchema[vm.phaseSplits[i].id] = vm.phaseSplits[i].leaderboard_schema;
}
utilities.hideLoader();
},
Expand Down Expand Up @@ -879,8 +884,10 @@
vm.stopLeaderboard();
vm.poller = $interval(function() {
parameters.url = "jobs/" + "challenge_phase_split/" + vm.phaseSplitId + "/leaderboard/?page_size=1000";
parameters.method = 'GET';
parameters.data = {};
parameters.method = 'POST';
parameters.data = {
"order_by": vm.orderLeaderboardBy
};
parameters.callback = {
onSuccess: function(response) {
var details = response.data;
Expand Down Expand Up @@ -937,8 +944,10 @@
// Show leaderboard
vm.leaderboard = {};
parameters.url = "jobs/" + "challenge_phase_split/" + vm.phaseSplitId + "/leaderboard/?page_size=1000";
parameters.method = 'GET';
parameters.data = {};
parameters.method = 'POST';
parameters.data = {
"order_by": vm.orderLeaderboardBy
};
parameters.callback = {
onSuccess: function(response) {
var details = response.data;
Expand Down Expand Up @@ -1356,8 +1365,10 @@
vm.startLoader("Loading Leaderboard Items");
vm.leaderboard = {};
parameters.url = "jobs/" + "challenge_phase_split/" + vm.phaseSplitId + "/leaderboard/?page_size=1000";
parameters.method = 'GET';
parameters.data = {};
parameters.method = 'POST';
parameters.data = {
"order_by": vm.orderLeaderboardBy
};
parameters.callback = {
onSuccess: function(response) {
var details = response.data;
Expand Down Expand Up @@ -2634,6 +2645,10 @@
}
};

vm.encodeMetricURI = function(metric) {
return encodeURIComponent(metric);
}

}

})();
10 changes: 10 additions & 0 deletions frontend/src/js/route-config/route-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,15 @@
title: 'Leaderboard'
};

var challenge_phase_metric_leaderboard = {
name: "web.challenge-main.challenge-page.phase-metric-leaderboard",
url: "/leaderboard/:phaseSplitId/:metric",
controller: 'ChallengeCtrl',
controllerAs: 'challenge',
templateUrl: baseUrl + "/web/challenge/leaderboard.html",
title: 'Leaderboard'
};

var profile = {
name: "web.profile",
parent: "web",
Expand Down Expand Up @@ -503,6 +512,7 @@
$stateProvider.state(my_challenge_all_submission);
$stateProvider.state(leaderboard);
$stateProvider.state(challenge_phase_leaderboard);
$stateProvider.state(challenge_phase_metric_leaderboard);

// featured challenge details
$stateProvider.state(featured_challenge_page);
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/views/web/challenge/leaderboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ <h5 class="w-300">Leaderboard</h5>
</span>
</div>
</div>
<div class="row" ng-if="challenge.isMultiMetricLeaderboardEnabled">
<div class="col xs12 s6">
<span>
<md-select ng-model="challenge.orderLeaderboardBy" placeholder="Order by metric" class="rm-margin">
<md-option value="{{key}}" ui-sref="web.challenge-main.challenge-page.phase-metric-leaderboard({phaseSplitId:challenge.phaseSplitId, metric:challenge.encodeMetricURI(key)})"
ng-repeat="key in challenge.phaseSplitLeaderboardSchema[challenge.phaseSplitId].labels">
<span class="fs-16 w-300">{{key}}</span>
</md-select>
</span>
</div>
</div>
<div class="row">
<div class="horizontal-scroll">
<div class="col s12">
Expand Down
Loading

0 comments on commit df0b6a9

Please sign in to comment.