-
Notifications
You must be signed in to change notification settings - Fork 0
Home
This package helps you to generate a number of personalized question sheets in HTML files, which will be distributed over the network. Students will find answers to their questions and submit their text files with answers. Once the whole set of text files are arrived, this package helps you to score them at once.
QG stands for Question Group
- Start a new python file, provided that package, html4quiz, is already installed, and copy the script below to it and save the file.
import html4quiz as h4q
QGs = []
Q = ['Submit the sum of the two integers {%vA%} and {%vB%}.',
'Subtract {%vA%} from {%vB%} and submit your answer.']
A = '''data=[]
vA=random.randint(10,30)
vB=random.randint(10,30)
answer=[vA+vB, vB-vA]'''
QGs.append([Q, A, ('chap1', 'qg1'), 'short'])
flagPreview = True
flagChoice = False
flagShuffling = False
figures = {}
STDs = {'12345678': 'abc def'}
a = h4q.work('checkups1', 'Testing', STDs, QGs, flagPreview, flagChoice, flagShuffling, figures)- If you run the python file, a webpage will be opened as:
- If it is the first time you work with Python, please stick to what is shown.
- If you know some Python, you can recognize some variables and values associated with them.
- The webpage shown above is an example of question sheet in HTML.
- Because we have only one student and one question group (QG), we have one link in the HTML file, "index.html".
- The QG consists of 2 questions and we have 2 buttons of "Q-1" and "Q-2", as shown below, if you click the link.
- The 2 questions also corresponds to the 2 item in variable, answer.
- The actual question displayed as an webpage above can be identified as the first string element of the variable Q of the first element of QGs, with the strings "{%vA%}" and "{%vB%}" being replaced with 18 and 11, respectively.
- The replacement was executed according to the code provided as a string of variable A.
- This is the key mechanism of the heart of this package.
- If the value for the variable flagChoice is changed to True as:
flagChoice = True- The question turns into a multiple-choices question with the choices randomly chosen, as:
- This is another key mechanism of the heart of this package.
- In order to get the list of students, you need to prepare a csv file with at least 2 columns of names and identification numbers.
- The order of the 2 columns is not important.
- If you prefer Microsoft Excel file, instead of csv, you can do so easily with a help from internet.
- You need to install one of many Python packages, for example openpyxl, to do so, which will not be discussed in the document.
- The value of STDs is a dictionary object the identification numbers as keys and names as corresponding values, both being strings.
- The script below is all you need.
STDs=h4q._common.getStudList([csv file name], [identification heading], [name heading])- Do not forget the underscore (_) in front of word "common".
- The method function is hidden and it cannot be called without the underscore.
- The function getStudList requires 3 input arguments, csv file name, identification heading, and name heading, all being strings.
- You must provide all 3 items to proceed smoothly.
- In order to consider further, it would be better to have more QGs than 1.
- More QGs can be easily done.
- Use your creativity to make more QGs and append them to the variable QGs as:
# Q = [...]
# A = "..."
QGs.append([Q, A, ('????', '???'), 'short'])- Since you have more QGs than 1, you have an option to generate question sheets, whether every question sheet is in the same order or they are shuffled.
- The flag, flagShuffling, does the job right; True for shuffling and False for same order.
- Try them to feel the difference.
- Since version 0.0.22, this is done automatically, and there is nothing to worry about.
- Question sheets in HTML files and corresponding answer files are saved in folder, named in those provided as the first argument when an instance of the class work is called.
- If the value of the variable flagPreview is True instead of question sheets in HTML files, preview for questions will be displayed as a HTML file.
- When each question sheet in a HTML file is opened, a few parts can be identified as 2 parts; bottom part being the question itself and top part being the title indicating the student identification number, a combination of a
and a text area for answers, and a series of buttons
for questions. - As each question button is clicked, the corresponding question will be displayed.
- For multiple choice questions, user simply click the choice then the corresponding choice number will be entered in the text area.
- Clicking different choice changes the choice number accordingly in the text area.
- Choice numbers can be manually and directly edited to the text area.
- For short-answer questions, answer must be manually and directly edited to the text area or edited to a downloaded file later.
- If the "orange" button is clicked, a file will be "downloaded" to local drive, usually "download" folder.
- Files can be downloaded as many times as they want.
- "downloaded" files are already named accordingly by student identification number.
- The number of downloaded will be added to the file name.
- The files can also be edited as students wish with any text file editor.
- Scoring the answers is very simple task with entering a few string and a few key-strokes.
- To demonstrate it, we need a set of text files, yes text files, of the answers student submitted over the network.
- Generating text files is also easy, you simply pretend as students to answer questions for a few students and save them to text files, which are all identified in names with students identification numbers.
- Save the text files in a folder with any name you want, for example, "checkups1_text".
- Open a new Python file, copy the script below to ti, change some strings accordingly, and run it.
- It seems nothing happens apparently.
import html4quiz as h4q
a=h4q.scoreAnswerFiles('checkups1/checkups1Work.pickle', 'checkups1_text')
#a.scoreThem() do not need this since 0.0.22
#a.saveResults() do not need this since 0.0.22- Go to the folder of "checkups1_text", where all students text files are saved.
- A new text file with a name of "checkups1Score.txt" and a csv file with the same name with "csv" extension will be found.
- Nowadays, many schools have one of many available learning management systems and it is good place to use to distribute the question sheets over the network.
- However, if it is not available to you, one of best solutions is to join GitHub and use the site to distribute them.
- One of many advantages they provide is the easiness to upload files.
- The software, GitHub Desktop, helps you do do so.
- If learning management system is available, it is the best place to guide students to submit to.
- If it is not available, a few solutions are possible.
- One is to use Dropbox, I personally recommend strongly for the sake of easiness.
- Just make one sharing folder and share it with students.
- Because every question sheet is different, it is not a problem the answer files is open to a whole class.
- Another solution might be the Google drive, I have not used it fully but I know it is possible.
After some trials, the procedure to upload/download Javascript codes for figures has been finalized.
- All Javascript scripts will be uploaded to a folder with names corresponding to variable names.
- The scripts are saved in JSON files, not Python files.
- The following python script can be used to download Json file and to get the Javascript code,
- For example, to download the Javascript script of "clock",
figures = {'clock': h4q._common.getResource('clock')}- Alternatively, the following python script will get you the Javascript of "clock" in json file:
import json
from urllib.request import urlopen
url = 'https://generateNscore.github.io/html4quiz/res/clock.json'
figures['clock'] = json.loads(urlopen(url).read())- 1. Getting started
- 2. Specifying method of converting a short-answer to a set of choices
- 3. Multiple-choice questions:
- 4. Adding a mathematical expression to question text
- 5. Making choices with equations
- 6. Adding a figure to question
- 7. Adding a personalized figure to questions
- 8. Adding figures in choices
- 9. Using user defined functions
This package was originally developed for short-answer questions and several mechanisms were added to convert a number to a set of choices.
- Unless you make a script for a set of choices, you can enjoy the mechanisms to convert questions by changing the flag, flagChoice, from False to True.
- To get the list of mechanisms, run the script below in Shell:
h4q.makeChoices.fns- The results are:
['variation0', 'variation2', 'variation0_int', 'variation0_int_2', 'variation0_int_2Add', 'variation0_int_3Add', 'variation0_int_5Add']- Before selecting various number choices, the value to be used is rounded off to a value having only 3 most significant digits.
- Examples are 123000 for 123333 and 0.0123 for 0.01233333.
- The actual performance can be confirmed by a script below:
h4q._common.round2MSF(123456.7890123) # 123000- For floating numbers,
- Then one of 2 tracks is randomly selected.
- One track is to change the digits randomly, via 'variation0', and the other is to multiply or to divide by 10, via 'variation2'.
- For integers,
- 'variation0_int': each digit of the most significant 3 digits is randomly changed.
- 'variation0_int_2': integer is varied by either multiplied by 2 or divided by 2 randomly.
- 'variation0_int_2Add': integer is varied by either adding or subtracting even numbers randomly.
- 'variation0_int_3Add': integer is varied by either adding or subtracting a multiplication of 3 randomly.
- 'variation0_int_3Add': integer is varied by either adding or subtracting a multiplication of 5 randomly.
- To specify a method, among the methods listed above, the answer must be ...
answer=[{'choices':None, 'ans':vA+vB, 'fn': 'variation0_int'}]- Yes, the answer must be a dictionary type, instead of a number object.
- The dictionary object is much similar to the one that will be discussed for multiple-choice questions next.
- There are 3 keys, 'choices', 'ans', and 'fn'.
- The value for the key 'choices' should be None.
- The value for the key 'ans' is much similar to one we have been used so far.
- The value for the key 'fn' is one of the methods listed above.
- 1. Getting started
- 2. Specifying method of converting a short-answer to a set of choices
- 3. Multiple-choice questions:
- 4. Adding a mathematical expression to question text
- 5. Making choices with equations
- 6. Adding a figure to question
- 7. Adding a personalized figure to questions
- 8. Adding figures in choices
- 9. Using user defined functions
So far every question mentioned above requires an answer in a number, either integer or floating number. If the flagChoice sets True, then the package calls one of prepared methods to generate randomly chosen a set of choices. We can discuss how to specify a certain method later.
- Sometimes, we want to use a set of special choices, such as equations, figures, or some other ways.
- This section helps you to achieve what you want by using another key mechanism.
- So, you have a set of choices, either by editing scripts for those directly for the string of A or by using a user defined function (udf) in another file saved in the same folder.
- Here is an example for the case.
Q = ['Submit the sum of the two integers {%vA%} and {%vB%}.',
'Subtract {%vA%} from {%vB%} and submit your answer.']
A='''data=[]
choices=[(random.randint(10,30), random.randint(10,30)) for _ in range(10)]
choice=random.choice(range(len(choices)))
ans=choices[choice]
vA, vB = ans
answer=[{'choices': [a+b for a, b in choices], 'ans': vA+vB}, {'choices': [b-a for a, b in choices], 'ans': vB-vA}]'''
QGs.append([Q, A, ('chap3', 'choices'), 'short'])- Can you see the difference between the scripts in the previous example and those above?
- They are exactly equal.
- The only difference in recent script is the choices that are provided to begin with./li>
- The choices are prepared in the values of the variable, choices.
- Now, the questions in this QG are not short-answer questions but multiple-choices questions.
- As you can see them in the script above, answer must be a dictionary object with 2 specific keys, "choices" and "ans", with corresponding values.
- As the name of keys and values literally, the value of "choices" is a list of choices to be used to select from and the value of "ans" is the correct answer among the choices.
- The key mechanism randomly shuffles choices before selection and it even discard the correct answer to make question without answer.
- Among 2 questions in the current QG, one can be remained as it is and the other can be what it was.
- 1. Getting started
- 2. Specifying method of converting a short-answer to a set of choices
- 3. Multiple-choice questions:
- 4. Adding a mathematical expression to question text
- 5. Making choices with equations
- 6. Adding a figure to question
- 7. Adding a personalized figure to questions
- 8. Adding figures in choices
- 9. Using user defined functions
A mathematical expression can be inserted into question. The string, Latex expression, enclosed by a pair of tags of "EQ%" and "%EQ" is sent to http://latex.codecogs.com to get an image of the expression.
- The Latex expression must follow all syntax of Latex, or error messages will occur.
Q=['Submit the greater of the two roots of the following quadratic equation:<br>{%eq%}',
'Submit the smaller of the two roots of the following quadratic equation:<br>{%eq%}']
A='''data=[]
vRoot1=random.choice([-9,-8,-7,-6,-5,-4,-3,-2,-1, 1, 2, 3, 4, 5, 6, 7, 8, 9])
vRoot2=random.choice([-9,-8,-7,-6,-5,-4,-3,-2,-1, 1, 2, 3, 4, 5, 6, 7, 8, 9])
term1=lambda v: '+ x' if v==1 else '- x' if v==-1 else f'+ {v}x' if v>0 else f'- {-v}x' if v<0 else ''
term2=lambda v: f'+ {v}' if v>0 else f'- {-v}' if v<0 else ''
eq = f'EQ% x^2 {term1(vRoot1+vRoot2)} {term2(vRoot1*vRoot2)} %EQ'
answer=[max(vRoot1, vRoot2), min(vRoot1, vRoot2)]'''
QG = [Q, A, ('chap10', 'qg1'), 'short']
- 1. Getting started
- 2. Specifying method of converting a short-answer to a set of choices
- 3. Multiple-choice questions:
- 4. Adding a mathematical expression to question text
- 5. Making choices with equations
- 6. Adding a figure to question
- 7. Adding a personalized figure to questions
- 8. Adding figures in choices
- 9. Using user defined functions
Choices with equation is not a hard task. All you need to do is to make choices with latex expression enclosed by the pair of tags described above.
- One example is given below:
Q=['What function has roots of {%ansV[0]%} and {%ansV[1]%}?']
A='''data=[]
roots=[(random.choice([-4, -3,-2,-1, 0, 1, 2, 3, 4]), random.choice([-4, -3,-2,-1, 0, 1, 2, 3, 4])) for _ in range(10)]
indx=random.choice(range(len(roots)))
ansV=roots[indx]
term1=lambda v: '+ x' if v==1 else '- x' if v==-1 else f'+ {v}x' if v>0 else f'- {-v}x' if v<0 else ''
term2=lambda v: f'+ {v}' if v>0 else f'- {-v}' if v<0 else ''
eqs = []
for r1, r2 in roots: eqs.append(f'EQ% x^2 {term1(r1+r2)} {term2(r1*r2)} %EQ')
answer=[{'choices':eqs, 'ans':eqs[indx]}]'''
- 1. Getting started
- 2. Specifying method of converting a short-answer to a set of choices
- 3. Multiple-choice questions:
- 4. Adding a mathematical expression to question text
- 5. Making choices with equations
- 6. Adding a figure to question
- 7. Adding a personalized figure to questions
- 8. Adding figures in choices
- 9. Using user defined functions
Just consider a case that question has a figure fixed, like an image.
- An image can be used as a figure
- The image must be converted to a certain format.
- Although it is possible, we are not going to consider this possibility for a while.
- Instead, the package is limited to figures that are generated by a Javascript script that is provided as well as other parameters
- Here is an example python script:
clock='''var argsFromMain=null;function init(prms) {argsFromMain=prms;}//init();
if (argsFromMain == null) {argsFromMain=[300, 10, 10];}const width= argsFromMain[0];cnvs.width=width;cnvs.height=width;ctx.clearRect(0,0, cnvs.width, cnvs.height);var radius = width/2;ctx.translate(radius, radius);radius = radius * 0.90;
function drawFace(ctx, radius) { ctx.beginPath(); ctx.arc(0, 0, radius, 0, 2*Math.PI); ctx.fillStyle = "white"; ctx.fill(); ctx.strokeStyle = "black"; ctx.stroke();}function drawNumbers(ctx, radius) { var ang; var num; ctx.font = radius*0.15 + "px arial"; ctx.textBaseline="middle"; ctx.fillStyle = "black"; ctx.textAlign="center"; for(num = 1; num < 13; num++){ ang = num * Math.PI / 6; ctx.rotate(ang); ctx.translate(0, -radius*0.85); ctx.rotate(-ang); ctx.fillText(num.toString(), 0, 0); ctx.rotate(ang); ctx.translate(0, radius*0.85); ctx.rotate(-ang); }}
function drawHand(ctx, pos, length, width) { ctx.beginPath(); ctx.lineWidth = width; ctx.lineCap = "round"; ctx.moveTo(0, 0); ctx.rotate(pos); ctx.lineTo(0,-length); ctx.stroke(); ctx.rotate(-pos);}
drawFace(ctx, radius);drawNumbers(ctx, radius);var hour=argsFromMain[1];var minute=argsFromMain[2];hour=hour%12;hour=hour*Math.PI/6 + minute*Math.PI/(6*60);drawHand(ctx, hour, radius*0.5, radius*0.04);minute=(minute*Math.PI/30);drawHand(ctx, minute, radius*0.8, radius*0.02);'''
figures={'clock':clock}
Q=['What time is the clock shown below?figure(clock)']
A='''data=[]
times = [f'{random.choice(range(1,12))}:{random.choice(range(5,60,5))}' for _ in range(15)]
times.append('10:10')
ans = '10:10'
answer=[{'choices':times, 'ans':ans}]'''
QGs.append([Q, A, ('chap3', 'clock0'), 'short'])- First of all, the Javascript script for the figure to be included should be available when the question is in use.
- Coding Javascript is beyond the scheme of this document.
- One warning: Please do not try to unfold the Javascript script, unless you know exactly what you are doing. Javascript does not care the indentation like Python. But there is some catches you should be aware, which is beyond the scheme.
- Unfolded code can be found here.
- Secondly, the variable that associated with the Javascript script must be included as an item of dictionary object, named in "figures", which has been empty up until now.
- Thirdly, the format for including a figure is a string that starts with figure followed by the name of variable for the actual figure, for example "figure(clock)", as used in the script above.
- Figures are always displayed at the end of the question text, as shown in the script above
1. Getting started
- 1. Getting started
- 2. Specifying method of converting a short-answer to a set of choices
- 3. Multiple-choice questions:
- 4. Adding a mathematical expression to question text
- 5. Making choices with equations
- 6. Adding a figure to question
- 7. Adding a personalized figure to questions
- 8. Adding figures in choices
- 9. Using user defined functions
Although personalizing questions have pros and cons in many aspects, one thing clear to achieve is to have security while assessing learning performance.
- The script below is almost the same as the previous script except a few lines.
- First of all, a string of "init({%prms%});" is added at the end of the question text.
- Readers who have read so far will understand easily that the mechanism of the personalization is due to the usage of variable, "prms".
- The semicolon symbol (;) must not be neglected. It is part of the format string to connect Python script to Javascript script which will use the value of the variable to draw a figure accordingly.
- Secondly, the actual value for the variable, prms, has to be randomly assigned.
- A few lines at the end of the answer string is there for the just that purpose.
- The first element of the variable prms, 300, is the pixel size to draw the figure with.
Q=['What time is the clock shown below?figure(clock)init({%prms%});']
A='''data=[]
times = [f'{random.choice(range(1,12))}:{random.choice(range(5,60,5))}' for _ in range(15)]
ans=random.choice(times)
answer=[{'choices':times, 'ans':ans}]
vH, vM=[int(s) for s in ans.split(':')]
prms=[300, vH, vM]'''
QGs.append([Q, A, ('chap3', 'clock1'), 'short'])- 1. Getting started
- 2. Specifying method of converting a short-answer to a set of choices
- 3. Multiple-choice questions:
- 4. Adding a mathematical expression to question text
- 5. Making choices with equations
- 6. Adding a figure to question
- 7. Adding a personalized figure to questions
- 8. Adding figures in choices
- 9. Using user defined functions
Q=['What clock shows the time of {%ans%}?figure(clock)']
A='''data=[]
times = [f'{random.choice(range(1,12))}:{random.choice(range(5,60,5))}' for _ in range(15)]
indx=random.choice(range(len(times)))
ans=times[indx]
prms=[f'[200, {int(choice.split(":")[0])}, {int(choice.split(":")[1])}]' for choice in times]
answer=[{'choices':prms, 'ans':prms[indx], 'cols':prms}]'''
QGs.append([Q, A, ('chap3', 'clock2'), 'short'])- To achieve the layout as it is now, a few extra requirements in formatting string has been implemented as needed.
- First of all, to make figures in choices different from each other, the corresponding parameters to be conveyed to Javascript must be varied. That is why the variable, prms, is now a list of lists (it was a list of 3 integers).
- Secondly, the variable, answer, has extra key-value item, and the key is "cols" with the value being the list of parameters, prms, which is the same as the value of the key "choices".
- Lastly, the string of "figure(clock)" does not mean to intend to draw figure at the end of question text, but it means the Javascript for "clock" will be used in figures of choices.
- 1. Getting started
- 2. Specifying method of converting a short-answer to a set of choices
- 3. Multiple-choice questions:
- 4. Adding a mathematical expression to question text
- 5. Making choices with equations
- 6. Adding a figure to question
- 7. Adding a personalized figure to questions
- 8. Adding figures in choices
- 9. Using user defined functions
You deserve a word, "Congrat!" if you read this far.
- I think one of obstacles for user to use this package is the fear, such as "how can I code the answer in python?" or "how do I know if it works as expected without any errors?"
- One cure for those fears is to use "User defined function" as it follows:
- Open another new Python file with any name you want (for example "userfunction.py" for explanation).
- Save the file in the same folder that you use to generate question sheets.
- In the file, create a function with a name you want (for example "func" for explanation).
- If you do not know how to create a function, do not worry and just copy script below.
- Save the file.
- Can you recognize the contents of the function? It is the same script that we used in the very first example at the beginning of the documentation.
- If you run this file, you will have a tuple of randomly chosen 2 integers.
import random
def func(choices=None, ans=None):
vA=random.randint(10,30)
vB=random.randint(10,30)
return vA, vB
if __name__ == '__main__':
print(func())- Let us make another Python as usual with the script below
- Python will read and execute the python file, userfunction.py automatically, when running the script below.
- The result will be the exactly same as before.
Q = ['Submit the sum of the two integers {%vA%} and {%vB%}.',
'Subtract {%vA%} from {%vB%} and submit your answer.']
A = '''data=[]
from userfunction import func
vA, vB = func()
answer=[vA+vB, vB-vA]'''
QGs.append([Q, A, ('chap1', 'qg1'), 'short'])- This script certainly reduces your fear on writing string for Answer
- There is alternative way, too. But it is a bit complicate, thus I will put it off until when...
- 1. Getting started
- 2. Specifying method of converting a short-answer to a set of choices
- 3. Multiple-choice questions:
- 4. Adding a mathematical expression to question text
- 5. Making choices with equations
- 6. Adding a figure to question
- 7. Adding a personalized figure to questions
- 8. Adding figures in choices
- 9. Using user defined functions
... in progress ...