Building A Speed Grader for Writing Assignments with Python
Many instructors who teach college writing classes use writing rubrics of some sorts to grade their student assignments. Despite its obvious limits (e.g. lack of “personal touch” or “creativity”), a writing rubric is still a very powerful tool. It is an effective way to communicate with students the specific learning outcomes or expectations of each assignment. It is also an incredible time-saver for instructors who often experience decision fatigue, especially when they have tons of papers to grade. Without a writing rubric, instructors may often find themselves repeating the same piece of information in their written comments to address some common writing issues.
I have explored the possibility of using Python to integrate writing rubrics into grading. And there are many benefits to a speed grader program. First, it would be even more accurate and efficient than checking writing rubrics manually. Second, perhaps more importantly, it generates useful data for instructors to evaluate students’ overall performance. It also allows instructors to build a corpus of written comments and to share their insights with other educators.
Ideally, this speed grader should do three things:
- generate a general report based on an existing rubric
- identify specific writing issues from an existing corpus
- provide specific examples from the student writing
I. Preparation
As a data science enthusiast, I know little about front-end web development. I will be using Jupyter Notebook for the application. Jupyter Widgets is good enough for basic interactive interface, and Google Colab is good enough for sharing it. We need to first load all the libraries.
import pandas as pd
import ipywidgets as widgets
from ipywidgets import Label, Button, HBox, VBox, Layout
Then, import the writing rubric and writing issue directory as dataframes.
df = pd.read_csv('https://raw.githubusercontent.com/junting-huang/speed_grading/main/grading_rubric.csv')
df_issue = pd.read_csv('https://raw.githubusercontent.com/junting-huang/speed_grading/main/writing_issue.csv')
I found this grading rubric used by the American University of Rome online, but you can also use your own writing rubric as long as they are in csv format.
It is the same with the writing issue directory file. See below as an example.
One addition step here is to convert the writing issue dataframe to a Python dictionary, so we can later call the issue to return its definition.
issue_dict = df_issue.set_index('issue').to_dict()['notes']
def getList(dict):
return [*dict]dropdown_options = getList(issue_dict)
II. Widget Design
Now we need a few sets of widgets to build the application. To interact with the writing rubric, we use sliders to quickly evaluate the student’s overall performance.
sliders = []; left_items = []; left_metrics = []for i in range(len(df)):
slider = widgets.IntSlider(0, min=0, max=4)
sliders.append(slider)for i in range(len(df)):
left_metrics.append(df['Metric'][i])
left_items.append(sliders[i])labels = [Label(value=m) for m in left_metrics]
For the writing issue, we need both dropdown menus and text boxes. The former is to select a writing issue from the directory, and the latter is to provide specific examples from the student writing to contextualize the writing issues.
text_example = widgets.Textarea(placeholder='Copy Student Writings Here', description='Example:', disabled=False, layout=Layout(height='100%'))
issue_dropdown= widgets.Dropdown(options=dropdown_options, value=dropdown_options[0], description='Issue:',disabled=False,)
Finally, we need two buttons. One is to generate a general report based on the existing rubric, and the other is to identify specific writing issues with examples from the student writing.
def comment_generator(x):
for i in range(len(df)):
if sliders[i].value == 0:
pass
elif sliders[i].value !=0:
print(df['Metric'][i])
print(df.iloc[i][str(sliders[i].value)])
print()
print('---------------------------END---------------------------')def example_generator(y):
issue_notes = issue_dict[issue_dropdown.value]
print(f'For example, when you say "{text_example.value}," there is an issue of {issue_dropdown.value}. {issue_notes}')
print('---------------------------END---------------------------')
III. Layout Design
The last step is to put everything together. If you are familiar with HTML and CSS, you can certainly experiment with your layout ideas. But I simply turn to VBox
and HBox
in Jupyter Widgets to arrange the widgets in vertical and horizontal boxes.
title = widgets.HTML("<h1>Speed Grader</h1>")
credit = widgets.HTML("<p>Use the slider to select the issues of student writings (4 is excellent, 1 is poor, & 0 is not relevant). </p>")btn1 = widgets.Button(description='Generate Summary', button_style='success')
btn1.on_click(comment_generator)
btn2 = widgets.Button(description='Generate Example', button_style='success')
btn2.on_click(example_generator)
place_holder1 = widgets.Label(value=" ",layout=Layout(width='150px'))
place_holder2 = widgets.Label(value=" ",layout=Layout(width='285px'))label_box = widgets.VBox(labels)
left_box = widgets.VBox(left_items)
right_box = widgets.VBox([issue_dropdown,text_example])
body_boxes = widgets.HBox([label_box, left_box, right_box])
button_box = widgets.HBox([place_holder1,btn1,place_holder2,btn2])page = widgets.VBox([title,credit,body_boxes,button_box])
page
Here is the final result:
You can find this project on Github. To run it, select the “speed_grader.ipynb” file and click “Open in Colab.” Run the cell and follow its instructions.
If you are using writing rubrics and/or have a repository of student writing issues, you can contribute to this project by crowdsourcing these contents to improve and/or customize the tool for your own class. You can create an issue or pull request, or contact me at jh2358@cornell.edu. Use “grading_rubric.csv” and “writing_issue.csv” files as examples.