def get_sequential_open_distrib(course_id, enrollment): """ Returns the number of students that opened each subsection/sequential of the course `course_id` the course ID for the course interested in `enrollment` the number of students enrolled in this course. Outputs a dict mapping the 'module_id' to the number of students that have opened that subsection/sequential. """ sequential_open_distrib = {} non_student_list = get_non_student_list(course_id) if enrollment <= settings.MAX_ENROLLEES_FOR_METRICS_USING_DB or not settings.ANALYTICS_DATA_URL: # Aggregate query on studentmodule table for "opening a subsection" data queryset = models.StudentModule.objects.filter( course_id__exact=course_id, module_type__exact='sequential', ).exclude(student_id__in=non_student_list).values( 'module_state_key').annotate( count_sequential=Count('module_state_key')) for row in queryset: module_id = course_id.make_usage_key_from_deprecated_string( row['module_state_key']) sequential_open_distrib[module_id] = row['count_sequential'] else: # Retrieve course object down to subsection course = modulestore().get_course(course_id, depth=2) # Connect to analytics data client client = Client(base_url=settings.ANALYTICS_DATA_URL, auth_token=settings.ANALYTICS_DATA_TOKEN) for section in course.get_children(): for subsection in section.get_children(): module = client.modules(course_id, subsection.location) try: sequential_open = module.sequential_open_distribution() except NotFoundError: pass else: sequential_open_distrib[ subsection.location] = sequential_open[0]['count'] return sequential_open_distrib
def get_sequential_open_distrib(course_id, enrollment): """ Returns the number of students that opened each subsection/sequential of the course `course_id` the course ID for the course interested in `enrollment` the number of students enrolled in this course. Outputs a dict mapping the 'module_id' to the number of students that have opened that subsection/sequential. """ sequential_open_distrib = {} non_student_list = get_non_student_list(course_id) if enrollment <= settings.MAX_ENROLLEES_FOR_METRICS_USING_DB or not settings.ANALYTICS_DATA_URL: # Aggregate query on studentmodule table for "opening a subsection" data queryset = models.StudentModule.objects.filter( course_id__exact=course_id, module_type__exact='sequential', ).exclude(student_id__in=non_student_list).values('module_state_key').annotate(count_sequential=Count('module_state_key')) for row in queryset: module_id = course_id.make_usage_key_from_deprecated_string(row['module_state_key']) sequential_open_distrib[module_id] = row['count_sequential'] else: # Retrieve course object down to subsection course = modulestore().get_course(course_id, depth=2) # Connect to analytics data client client = Client(base_url=settings.ANALYTICS_DATA_URL, auth_token=settings.ANALYTICS_DATA_TOKEN) for section in course.get_children(): for subsection in section.get_children(): module = client.modules(course_id, subsection.location) try: sequential_open = module.sequential_open_distribution() except NotFoundError: pass else: sequential_open_distrib[subsection.location] = sequential_open[0]['count'] return sequential_open_distrib
def get_problem_grade_distribution(course_id, enrollment): """ Returns the grade distribution per problem for the course `course_id` the course ID for the course interested in `enrollment` the number of students enrolled in this course. Output is 2 dicts: 'prob-grade_distrib' where the key is the problem 'module_id' and the value is a dict with: 'max_grade' - max grade for this problem 'grade_distrib' - array of tuples (`grade`,`count`). 'total_student_count' where the key is problem 'module_id' and the value is number of students attempting the problem """ non_student_list = get_non_student_list(course_id) prob_grade_distrib = {} total_student_count = defaultdict(int) if enrollment <= settings.MAX_ENROLLEES_FOR_METRICS_USING_DB or not settings.ANALYTICS_DATA_URL: # Aggregate query on studentmodule table for grade data for all problems in course queryset = models.StudentModule.objects.filter( course_id__exact=course_id, grade__isnull=False, module_type__in=PROB_TYPE_LIST, ).exclude(student_id__in=non_student_list).values( 'module_state_key', 'grade', 'max_grade').annotate(count_grade=Count('grade')) # Loop through resultset building data for each problem for row in queryset: curr_problem = course_id.make_usage_key_from_deprecated_string( row['module_state_key']) # Build set of grade distributions for each problem that has student responses if curr_problem in prob_grade_distrib: prob_grade_distrib[curr_problem]['grade_distrib'].append( (row['grade'], row['count_grade'])) if ((prob_grade_distrib[curr_problem]['max_grade'] != row['max_grade']) and (prob_grade_distrib[curr_problem]['max_grade'] < row['max_grade'])): prob_grade_distrib[curr_problem]['max_grade'] = row[ 'max_grade'] else: prob_grade_distrib[curr_problem] = { 'max_grade': row['max_grade'], 'grade_distrib': [ (row['grade'], row['count_grade']), ], } # Build set of total students attempting each problem total_student_count[curr_problem] += row['count_grade'] else: # Retrieve course object down to problems course = modulestore().get_course(course_id, depth=4) # Connect to analytics data client client = Client(base_url=settings.ANALYTICS_DATA_URL, auth_token=settings.ANALYTICS_DATA_TOKEN) for section in course.get_children(): for subsection in section.get_children(): for unit in subsection.get_children(): for child in unit.get_children(): if child.location.category not in PROB_TYPE_LIST: continue problem_id = child.location problem = client.modules(course_id, problem_id) try: grade_distribution = problem.grade_distribution() except NotFoundError: grade_distribution = [] for score in grade_distribution: total_student_count[problem_id] += score['count'] if problem_id in prob_grade_distrib: if prob_grade_distrib[problem_id][ 'max_grade'] < score['max_grade']: prob_grade_distrib[problem_id][ 'max_grade'] = score['max_grade'] prob_grade_distrib[problem_id][ 'grade_distrib'].append( (score['grade'], score['count'])) else: prob_grade_distrib[problem_id] = { 'max_grade': score['max_grade'], 'grade_distrib': [ (score['grade'], score['count']), ], } return prob_grade_distrib, total_student_count
def get_problem_set_grade_distrib(course_id, problem_set, enrollment): """ Returns the grade distribution for the problems specified in `problem_set`. `course_id` the course ID for the course interested in `problem_set` an array of UsageKeys representing problem module_id's. `enrollment` the number of students enrolled in this course. Requests from the database the a count of each grade for each problem in the `problem_set`. Returns a dict, where the key is the problem 'module_id' and the value is a dict with two parts: 'max_grade' - the maximum grade possible for the course 'grade_distrib' - array of tuples (`grade`,`count`) ordered by `grade` """ non_student_list = get_non_student_list(course_id) prob_grade_distrib = {} if enrollment <= settings.MAX_ENROLLEES_FOR_METRICS_USING_DB or not settings.ANALYTICS_DATA_URL: # Aggregate query on studentmodule table for grade data for set of problems in course queryset = models.StudentModule.objects.filter( course_id__exact=course_id, grade__isnull=False, module_type__in=PROB_TYPE_LIST, module_state_key__in=problem_set, ).exclude(student_id__in=non_student_list).values( 'module_state_key', 'grade', 'max_grade', ).annotate(count_grade=Count('grade')).order_by( 'module_state_key', 'grade') # Loop through resultset building data for each problem for row in queryset: problem_id = course_id.make_usage_key_from_deprecated_string( row['module_state_key']) if problem_id not in prob_grade_distrib: prob_grade_distrib[problem_id] = { 'max_grade': 0, 'grade_distrib': [], } curr_grade_distrib = prob_grade_distrib[problem_id] curr_grade_distrib['grade_distrib'].append( (row['grade'], row['count_grade'])) if curr_grade_distrib['max_grade'] < row['max_grade']: curr_grade_distrib['max_grade'] = row['max_grade'] else: # Connect to analytics data client client = Client(base_url=settings.ANALYTICS_DATA_URL, auth_token=settings.ANALYTICS_DATA_TOKEN) for problem in problem_set: module = client.modules(course_id, problem) try: grade_distribution = module.grade_distribution() except NotFoundError: grade_distribution = [] for score in grade_distribution: if problem in prob_grade_distrib: if prob_grade_distrib[problem]['max_grade'] < score[ 'max_grade']: prob_grade_distrib[problem]['max_grade'] = score[ 'max_grade'] prob_grade_distrib[problem]['grade_distrib'].append( (score['grade'], score['count'])) else: prob_grade_distrib[problem] = { 'max_grade': score['max_grade'], 'grade_distrib': [(score['grade'], score['count'])], } return prob_grade_distrib
def get_problem_grade_distribution(course_id, enrollment): """ Returns the grade distribution per problem for the course `course_id` the course ID for the course interested in `enrollment` the number of students enrolled in this course. Output is 2 dicts: 'prob-grade_distrib' where the key is the problem 'module_id' and the value is a dict with: 'max_grade' - max grade for this problem 'grade_distrib' - array of tuples (`grade`,`count`). 'total_student_count' where the key is problem 'module_id' and the value is number of students attempting the problem """ non_student_list = get_non_student_list(course_id) prob_grade_distrib = {} total_student_count = defaultdict(int) if enrollment <= settings.MAX_ENROLLEES_FOR_METRICS_USING_DB or not settings.ANALYTICS_DATA_URL: # Aggregate query on studentmodule table for grade data for all problems in course queryset = models.StudentModule.objects.filter( course_id__exact=course_id, grade__isnull=False, module_type__in=PROB_TYPE_LIST, ).exclude(student_id__in=non_student_list).values('module_state_key', 'grade', 'max_grade').annotate(count_grade=Count('grade')) # Loop through resultset building data for each problem for row in queryset: curr_problem = course_id.make_usage_key_from_deprecated_string(row['module_state_key']) # Build set of grade distributions for each problem that has student responses if curr_problem in prob_grade_distrib: prob_grade_distrib[curr_problem]['grade_distrib'].append((row['grade'], row['count_grade'])) if ((prob_grade_distrib[curr_problem]['max_grade'] != row['max_grade']) and (prob_grade_distrib[curr_problem]['max_grade'] < row['max_grade'])): prob_grade_distrib[curr_problem]['max_grade'] = row['max_grade'] else: prob_grade_distrib[curr_problem] = { 'max_grade': row['max_grade'], 'grade_distrib': [(row['grade'], row['count_grade']), ], } # Build set of total students attempting each problem total_student_count[curr_problem] += row['count_grade'] else: # Retrieve course object down to problems course = modulestore().get_course(course_id, depth=4) # Connect to analytics data client client = Client(base_url=settings.ANALYTICS_DATA_URL, auth_token=settings.ANALYTICS_DATA_TOKEN) for section in course.get_children(): for subsection in section.get_children(): for unit in subsection.get_children(): for child in unit.get_children(): if child.location.category not in PROB_TYPE_LIST: continue problem_id = child.location problem = client.modules(course_id, problem_id) try: grade_distribution = problem.grade_distribution() except NotFoundError: grade_distribution = [] for score in grade_distribution: total_student_count[problem_id] += score['count'] if problem_id in prob_grade_distrib: if prob_grade_distrib[problem_id]['max_grade'] < score['max_grade']: prob_grade_distrib[problem_id]['max_grade'] = score['max_grade'] prob_grade_distrib[problem_id]['grade_distrib'].append((score['grade'], score['count'])) else: prob_grade_distrib[problem_id] = { 'max_grade': score['max_grade'], 'grade_distrib': [(score['grade'], score['count']), ], } return prob_grade_distrib, total_student_count
def get_problem_set_grade_distrib(course_id, problem_set, enrollment): """ Returns the grade distribution for the problems specified in `problem_set`. `course_id` the course ID for the course interested in `problem_set` an array of UsageKeys representing problem module_id's. `enrollment` the number of students enrolled in this course. Requests from the database the a count of each grade for each problem in the `problem_set`. Returns a dict, where the key is the problem 'module_id' and the value is a dict with two parts: 'max_grade' - the maximum grade possible for the course 'grade_distrib' - array of tuples (`grade`,`count`) ordered by `grade` """ non_student_list = get_non_student_list(course_id) prob_grade_distrib = {} if enrollment <= settings.MAX_ENROLLEES_FOR_METRICS_USING_DB or not settings.ANALYTICS_DATA_URL: # Aggregate query on studentmodule table for grade data for set of problems in course queryset = models.StudentModule.objects.filter( course_id__exact=course_id, grade__isnull=False, module_type__in=PROB_TYPE_LIST, module_state_key__in=problem_set, ).exclude(student_id__in=non_student_list).values( 'module_state_key', 'grade', 'max_grade', ).annotate(count_grade=Count('grade')).order_by('module_state_key', 'grade') # Loop through resultset building data for each problem for row in queryset: problem_id = course_id.make_usage_key_from_deprecated_string(row['module_state_key']) if problem_id not in prob_grade_distrib: prob_grade_distrib[problem_id] = { 'max_grade': 0, 'grade_distrib': [], } curr_grade_distrib = prob_grade_distrib[problem_id] curr_grade_distrib['grade_distrib'].append((row['grade'], row['count_grade'])) if curr_grade_distrib['max_grade'] < row['max_grade']: curr_grade_distrib['max_grade'] = row['max_grade'] else: # Connect to analytics data client client = Client(base_url=settings.ANALYTICS_DATA_URL, auth_token=settings.ANALYTICS_DATA_TOKEN) for problem in problem_set: module = client.modules(course_id, problem) try: grade_distribution = module.grade_distribution() except NotFoundError: grade_distribution = [] for score in grade_distribution: if problem in prob_grade_distrib: if prob_grade_distrib[problem]['max_grade'] < score['max_grade']: prob_grade_distrib[problem]['max_grade'] = score['max_grade'] prob_grade_distrib[problem]['grade_distrib'].append((score['grade'], score['count'])) else: prob_grade_distrib[problem] = { 'max_grade': score['max_grade'], 'grade_distrib': [(score['grade'], score['count'])], } return prob_grade_distrib