11
$\begingroup$

I teach several in-person university courses in which my lecture slides are in Mathematica (SlideShow environment), projected for all students to see. These slides are also distributed before class to students. Thus students have these slides on their laptops, computing along with me during class... plotting curves, solving equations, performing integration and differentiation, and so on. During class, I'll give students time to change a problem of their choice, type in their own text notes, and so forth. After class, the students then keep their slides with their own results with personal annotations. I find students learn a great deal this way... actively programming while learning.

Online communication and collaboration tools such as Zoom, Google Hangout, Microsoft Teams, and so on offer online direct polling. Thus the host (here, professor) can post a question with sample answers (e.g., A, B, C, or D), each student clicks on their answer (anonymously) on their own laptop, and a bar-chart tally appears on the host computer.

I'd like to incorporate that functionality into my lectures; however, I don't want to use a collaboration tool such as Zoom. I'm wondering if this functionality can be provided entirely within the Mathematica slide deck itself.

In short, my question is this:

  • Is there a way in which every student's Mathematica slide deck can have a simple interface (on a few chosen slides), each interface with buttons for response to a question (A, B, C, or D), and the host's (professor's) Mathematica slides have a simple barchart tallying the students' responses?

Assume all computers have access to the internet (or university intranet), the email addresses are known, Databin is available, and any other support information that will make this functionality possible.

I know you can email directly from a Mathematica notebook, but I could not find any documentation relevant to supporting this kind of polling function.


Added for clarity in offering a bounty (tomorrow):

To collect the bounty, you'll need to provide:

  • Mathematica code for the host (professor's) slide deck creating a one-time Databin for a single lecture.
  • Code for a sample question that will appear on professor's slide deck and (surely code different from the professor's) that will appear on each student's slide deck. Example: "Question 1: What will happen to the power in the circuit? A. It will go up. B. It will go down. C. It will stay the same. D. I don't know." There should be a simple button interface for each answer.
  • A similar template for additional questions. Example: "Question 2: What will happen to the phase? A. It will increase. B. It will decrease. C. It will not change. D. I don't know." Each lecture could have several such questions (I envision ten, at most, but that shouldn't affect the coding problem.)
  • Code on the professor's slide deck that displays a histogram of student responses for each individual question in real time (or after each refresh of the interface by the professor). Thus on one page there will be a histogram for responses to Question 1, on a different slide there will be a histogram for responses to Question 2, and so on.
  • If possible, there should be only a single Databin created per lecture... so student responses to all questions are posted to that single Databin (but somehow indexed so that only the proper data is tallied in each histogram, of course).
  • Assume a list of student email addresses is available. What code is required to give the student class list (and nobody else) permission to post to the Databin?

I'm not wedded to using a Databin. If there is another way to achieve the desired functionality, great!

Again... I think our community would profit greatly from such code.

$\endgroup$
1
  • $\begingroup$ An idea. In the student's notebook capture the answer and a student id in a Databin. In the professor's notebook read the data from the databin and present the results as a barchart. $\endgroup$ May 25, 2023 at 15:13

1 Answer 1

14
+50
$\begingroup$

Here is a simple implementation which does not connect to the internet and can be run locally, but has the following requirements:

  • All computers (teacher and students) are connected to the same network (internet connection does not matter)
  • Nothing prevents them from accessing the addresses we're going to use
  • All have Mathematica 12.3 or higher (the teacher can have a lower requirement)

Mathematica introduces a greater range of network functions in 12.* versions which coincide with the introduction of the questioning framework. Combining these two features allow us to create a local server on the teacher's computer, and use the questioning framework (which is still experimental!) on students to assess the question in a polly way ;)

Before we start, we have to find the address of your computer (teacher/server) in the network, this can be done with the following code:

HostLookup[$MachineName]

(* Out: {IPAddress["192.168.1.11"]} *)

Remember the output of your machine certainly differs from mine. For this reason, you have to change the following code before just executing them.

Then we choose a port and run our server on that, there may be specifications by your organization. Here I choose 5000 as our port. So the address is the following:

192.168.1.11:5000

Now we have two codes to run:

  1. Code that runs on the teacher's notebook (server)
  2. Code that runs on the student's notebook (client)

Teacher (Server)

ClearAll[UpdateStats, ReadQuery, GenerateSimpleResponse, ShowPoll, 
  responses];
(* Used to store the answers with their *)
responses = <||>;

(* Used to show the result dynamically *)
ShowPoll[questionID_String] := 
 Dynamic[Refresh[
   BarChart[
    Counts@Values@KeySelect[responses, MatchQ@{_, questionID}], 
    ChartLabels -> Placed[Automatic, Axis, Rotate[#, 90 Degree] &]]]]

(* Internally used - will generate a simple HTTP response *)
GenerateSimpleResponse[message_] := "HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: " <> ToString[StringLength[ToString@message]] <> 
  "\n\n" <> ToString[message] <> "\n\n"

(* Internally used - will parse the http response and return the \
query *)
ReadQuery[response_String] := 
 URLParse[StringSplit[HTTPResponse[response]["Body"], " "][[2]]][
  "Query"]

(* Internally used - will be called whenever a request is sent to the \
server *)
UpdateStats[data_] := 
 Block[{temp = ReadQuery@data["Data"], machineID, questionID, answer, 
   client = data["SourceSocket"]},
  questionID = "q" /. temp;
  answer = "answer" /. temp;
  machineID = "id" /. temp;
  If[answer === "answer" && questionID === "q" && machineID === "id",
   (* Invalid response *)
   WriteString[client, GenerateSimpleResponse[0]];,
   
   (* Valid response *)
   responses[{machineID, questionID}] = answer;
   WriteString[client, GenerateSimpleResponse[1]];
   ];
  Close[client];
  ]

To terminate the server run usually DeleteObject[server] will work but if it didn't you can also close all the sockets Mathematica used by:

Quiet[DeleteObject[server];
  Close /@ Sockets[];];

Student (client)

ClearAll[CustomAssessment, CreatePoll];
(* Will be used as the question ID, if it's in the CreateAssessment \
arguments - will be auto-incremented *)
$QuestionIndex = 0;

(* Internally used - will be called the server whenever the user clicks \
submit *)
CustomAssessment[questionID_String][answer_] := 
 Quiet[URLRead[
     HTTPRequest[
      "192.168.1.11:5000/", <|
       "Query" -> {"answer" -> answer, "id" -> $MachineID, 
         "q" -> questionID}|>], TimeConstraint -> 5]["Body"] === "1"]

(* Will create the polling *)
CreatePoll[question_, answers_List] := 
 CreatePoll[question, answers, ToString[$QuestionIndex++]]

CreatePoll[question_, answers_List, questionIndex_String] := 
 QuestionObject[question, 
  AssessmentFunction[
   answers, <|
    "Selector" -> (If[CustomAssessment[questionIndex][#2], #2, 
        Missing] &)|>]]

Example

Run the server first by:

server = SocketListen["192.168.1.11:5000", UpdateStats]

Create a poll by:

CreatePoll["What will happen to the power in the circuit?", 
{"It will go up.", "It will go down", "It will stay the same.", 
  "I don't know."}]

Output:

enter image description here

Demo

Here is a demo of 3 students with a small modification to be multiple students at the same time:

enter image description here

Notes:

  • responses (an Association) stores the votes for all the questions for all the students which can be saved and analyzed further
  • When you use CreatePoll, the third argument is optional to provide question_id, if it's not provided $QuestionIndex will be used + incremented
  • If the student's answer is received and counted, he/she will get a green tick mark like the demo otherwise a red cross
  • $MachineID was used to distinguish the students, preventing them from voting multiple types and allowing them to refine their choices
  • In some parts of code, I require the inputs to be some type (for example _String) even though it could be any type, to create a consistent interface, using other types can lead to surprises.
  • I think the same solution can be implemented online in order to lift some of the restrictions.
  • Due to simplicity, the answer can't be "answer", question_id can't be "q", and student_id can't be "id" (using an Association can lift this limitation - inside UpdateStats)

Bonus:

  • They can vote with their phone or any other gadget by entering the following URL: 192.168.1.11:5000/?answer=1&q=2&id=1234 which says the answer is 1, the question's id is 2, and the student's id is 1234 (can be abused with fake student id)

Ideas for further improvement:

  • have activation/deactivation, so by calling a function in the teacher's notebook, polling for a specific question begins/ends
  • date functions can be used to automate the beginnings/endings of the polls
  • the questioning framework can be used further to provide the student with a score after each question or at the end
  • Limiting the student ids that can vote by using their Email or ...

I'm not sure whether it'll work in your enviroment, so please share the result once you've tested it.

$\endgroup$
2
  • 3
    $\begingroup$ Wow... a lot of work... and a great demo! This is so valuable that I'd like to wait 11 hours and post this with a 50 point bounty and accept your answer as such. You deserve the points for this much work. Return in 11 hours! I think the community will use this code, as I know I will. $\endgroup$ May 26, 2023 at 16:11
  • 1
    $\begingroup$ @DavidG.Stork Thank you for the kind words and bonus. I hope it works in your environment. I can't wait to hear the result. $\endgroup$
    – Ben Izd
    May 28, 2023 at 3:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.