// Numbas version: exam_results_page_options {"name": "Fill in a table of values which is automatically plotted", "extensions": ["jsxgraph", "sheets"], "custom_part_types": [{"source": {"pk": 242, "author": {"name": "Christian Lawson-Perfect", "pk": 7}, "edit_page": "/part_type/242/edit"}, "name": "Spreadsheet", "short_name": "spreadsheet", "description": "

An editable spreadsheet. Ranges of cells can be disabled, and you can specify ranges of cells to be marked. A cell is marked correct if its value is equal to the value in the expected answer spreadsheet.

", "help_url": "", "input_widget": "spread-sheet", "input_options": {"correctAnswer": "settings[\"correct_answer\"]", "hint": {"static": true, "value": ""}, "initial_sheet": {"static": false, "value": "disable_cells(settings[\"initial_sheet\"], settings[\"disable_ranges\"])"}}, "can_be_gap": true, "can_be_step": true, "marking_script": "correctAnswer:\nsettings[\"correct_answer\"]\n\nmark:\nif(sum(mark_ranges)=0,\n incorrect(),\n apply(mark_ranges)\n)\n\ninterpreted_answer:\nstudentAnswer\n\nrange_cells:\nmap(parse_range(ref),ref,values(settings[\"mark_ranges\"]))\n\ntotal_cells:\nlen(flatten(range_cells))\n\nrange_weights:\nswitch(\n settings[\"marking_method\"]=\"per_cell\",\n map(len(r)/total_cells, r, range_cells),\n // otherwise, mark per range\n repeat(1/len(range_cells), len(range_cells))\n)\n\nmark_ranges:\nmap(\n let(\n range_credit,\n sum(map(\n let(\n correctCellString, correctAnswer[c],\n correctCellNumber, parsenumber(correctCellString, notation_styles),\n studentCellString, studentAnswer[c],\n studentCellNumber, parsenumber(studentCellString, notation_styles),\n award(\n 1/len(cells), \n if(isnan(correctCellNumber) and correctCellString<>\"\",\n lower(correctCellString) = lower(studentCellString),\n abs(studentCellNumber - if(isnan(correctCellNumber),0,correctCellNumber)) <= settings[\"tolerance\"]\n )\n )\n ),\n c,\n cells\n )),\n message,\n switch(\n range_credit=0,\n if(len(cells)=1, \"This entry is incorrect.\", \"All entries in this range are incorrect.\"),\n range_credit=1,\n if(len(cells)=1, \"This entry is correct.\", \"All entries in this range are correct.\"),\n //otherwise\n \"Some entries in this range are correct.\"\n ),\n assert(len(cells)=0, add_credit(range_credit*w, \"{name}: \"+message)); \n range_credit\n ),\n [cells,w,name],\n zip(range_cells, range_weights, keys(settings[\"mark_ranges\"]))\n)\n\nnotation_styles:\n[\"plain\",\"si-en\"]", "marking_notes": [{"name": "correctAnswer", "description": "

A spreadsheet representing the expected answer.

", "definition": "settings[\"correct_answer\"]"}, {"name": "mark", "description": "This is the main marking note. It should award credit and provide feedback based on the student's answer.", "definition": "if(sum(mark_ranges)=0,\n incorrect(),\n apply(mark_ranges)\n)"}, {"name": "interpreted_answer", "description": "A value representing the student's answer to this part.", "definition": "studentAnswer"}, {"name": "range_cells", "description": "

For each range to be marked, the addresses of the cells in that range.

", "definition": "map(parse_range(ref),ref,values(settings[\"mark_ranges\"]))"}, {"name": "total_cells", "description": "

The total number of cells to be marked. Cells in overlapping ranges will be counted once for each range they're in.

", "definition": "len(flatten(range_cells))"}, {"name": "range_weights", "description": "

The weight of each range, as a proportion of the available credit.

", "definition": "switch(\n settings[\"marking_method\"]=\"per_cell\",\n map(len(r)/total_cells, r, range_cells),\n // otherwise, mark per range\n repeat(1/len(range_cells), len(range_cells))\n)"}, {"name": "mark_ranges", "description": "

Mark each of the ranges specified by the question author.

", "definition": "map(\n let(\n range_credit,\n sum(map(\n let(\n correctCellString, correctAnswer[c],\n correctCellNumber, parsenumber(correctCellString, notation_styles),\n studentCellString, studentAnswer[c],\n studentCellNumber, parsenumber(studentCellString, notation_styles),\n award(\n 1/len(cells), \n if(isnan(correctCellNumber) and correctCellString<>\"\",\n lower(correctCellString) = lower(studentCellString),\n abs(studentCellNumber - if(isnan(correctCellNumber),0,correctCellNumber)) <= settings[\"tolerance\"]\n )\n )\n ),\n c,\n cells\n )),\n message,\n switch(\n range_credit=0,\n if(len(cells)=1, \"This entry is incorrect.\", \"All entries in this range are incorrect.\"),\n range_credit=1,\n if(len(cells)=1, \"This entry is correct.\", \"All entries in this range are correct.\"),\n //otherwise\n \"Some entries in this range are correct.\"\n ),\n assert(len(cells)=0, add_credit(range_credit*w, \"{name}: \"+message)); \n range_credit\n ),\n [cells,w,name],\n zip(range_cells, range_weights, keys(settings[\"mark_ranges\"]))\n)"}, {"name": "notation_styles", "description": "

Accepted number notation styles for a value in an individual cell.

", "definition": "[\"plain\",\"si-en\"]"}], "settings": [{"name": "initial_sheet", "label": "Initial sheet", "help_url": "", "hint": "A spreadsheet object giving the initial state of the sheet that the student should fill in.", "input_type": "code", "default_value": "", "evaluate": true}, {"name": "correct_answer", "label": "Correct answer", "help_url": "", "hint": "A spreadsheet object representing a correct answer to the part.", "input_type": "code", "default_value": "", "evaluate": true}, {"name": "disable_ranges", "label": "Ranges to disable", "help_url": "", "hint": "A list of cell or range references, denoting the cells that should not be editable.", "input_type": "code", "default_value": "[]", "evaluate": true}, {"name": "mark_ranges", "label": "Ranges to mark", "help_url": "", "hint": "A dictionary of cell or range references, mapping names to ranges of cells, denoting the cells that should be compared for equality with the expected answer.", "input_type": "code", "default_value": "dict()", "evaluate": true}, {"name": "marking_method", "label": "Marking method", "help_url": "", "hint": "", "input_type": "dropdown", "default_value": "per_cell", "choices": [{"value": "per_cell", "label": "Each cell has the same weight"}, {"value": "per_range", "label": "Each range has the same weight"}]}, {"name": "tolerance", "label": "Allowed margin of error", "help_url": "", "hint": "", "input_type": "code", "default_value": "0", "evaluate": true}], "public_availability": "always", "published": true, "extensions": ["sheets"]}], "resources": [], "navigation": {"allowregen": true, "showfrontpage": false, "preventleave": false, "typeendtoleave": false}, "question_groups": [{"pickingStrategy": "all-ordered", "questions": [{"name": "Fill in a table of values which is automatically plotted", "tags": [], "metadata": {"description": "

The student is given a quadratic formula and asked to fill in a table of values of $f(x)$ for a given range of $x$.

\n

There is also a plot of the points, which updates when the table is filled in, or the student can move the points to fill in the table.

\n

The table uses the spreadsheet and JSXgraph extensions.

", "licence": "Creative Commons Attribution 4.0 International"}, "statement": "

Let $f(x) = \\simplify[all, !noLeadingMinus]{{a}x^2 + {b}x + {c}}$.

", "advice": "", "rulesets": {}, "extensions": ["jsxgraph", "sheets"], "builtin_constants": {"e": true, "pi,\u03c0": true, "i": true}, "constants": [], "variables": {"empty_table": {"name": "empty_table", "group": "Ungrouped variables", "definition": "spreadsheet([[\"$x$\", \"$f(x)$\"]])\n|> disable_cells([\"A1:B1\", x_range])\n|> update_range(\"A1:B1\", font_style(\"bold\") |> border(\"bottom\",\"medium\"))\n|> fill_range(x_range,xs)", "description": "

The table of values with only the $x$ values filled in.

", "templateType": "anything", "can_override": false}, "xs": {"name": "xs", "group": "Ungrouped variables", "definition": "-3 .. 3#1", "description": "

The values of $x$ that the student must fill in.

", "templateType": "range", "can_override": false}, "ys": {"name": "ys", "group": "Ungrouped variables", "definition": "map(a*x^2 + b*x + c, x, xs)", "description": "

$f(x)$ for each $x$.

", "templateType": "anything", "can_override": false}, "filled_table": {"name": "filled_table", "group": "Ungrouped variables", "definition": "fill_range(empty_table, y_range, ys)", "description": "

The table with the $f(x)$ values filled in.

", "templateType": "anything", "can_override": false}, "x_range": {"name": "x_range", "group": "Ungrouped variables", "definition": "encode_range(0, 1, 0, int(len(xs)))", "description": "

The range of cells in the table representing the $x$ values.

", "templateType": "anything", "can_override": false}, "y_range": {"name": "y_range", "group": "Ungrouped variables", "definition": "encode_range(1,1,1,int(len(ys)))", "description": "

The range of cells in the table representing the $y$ values.

", "templateType": "anything", "can_override": false}, "plot": {"name": "plot", "group": "Ungrouped variables", "definition": "jsxgraph(600,300, [min(xs)-1, y_limit+5, max(xs)+1, -y_limit-5],\n dict(\n flatten(map(\n [\n [\"l{i}\",\n [\"line\",\n [[xs[i],0],[xs[i],1]],\n [\"id\": \"l{i}\", \"withLabel\": false, \"visible\": false, \"fixed\": true]\n ]\n ],\n [\"p{i}\",\n [\"glider\",\n [xs[i],0,\"l{i}\"],\n [\"id\": \"p{i}\", \"withLabel\": false, \"snapToGrid\": true]\n ]\n ]\n ], i, 0..(len(ys)-1)\n ))\n )\n)", "description": "", "templateType": "anything", "can_override": false}, "y_limit": {"name": "y_limit", "group": "Ungrouped variables", "definition": "max(map(abs(y),y,ys))", "description": "

The absolute value of the $y$ value furthest from the origin. The plot will show values

", "templateType": "anything", "can_override": false}, "a,b,c": {"name": "a,b,c", "group": "Ungrouped variables", "definition": "repeat(random(-3..3 except 0), 3)", "description": "", "templateType": "anything", "can_override": false}}, "variablesTest": {"condition": "", "maxRuns": 100}, "ungrouped_variables": ["a,b,c", "xs", "ys", "x_range", "y_range", "empty_table", "filled_table", "y_limit", "plot"], "variable_groups": [], "functions": {}, "preamble": {"js": "", "css": ""}, "parts": [{"type": "spreadsheet", "useCustomName": false, "customName": "", "marks": "7", "scripts": {}, "customMarkingAlgorithm": "student_ys: map(parsenumber(x,\"plain\"),[x],studentAnswer[y_range])\n\npoints: map(plot[\"p{i}\"], i, 0..len(ys)-1)\n\njxg_input:\n flatten(map(\n [ jxg_show(p, not isnan(y)),\n jxg_set_position(p, vector(x,y))\n ],\n [p,x,y],\n zip(points,xs,student_ys)\n ))\n\nplot_ys: map(jxg_position(p)[1], p, points)\n\njxg_output (Fill in the answer widget when the board changes):\n empty_table\n |> fill_range(y_range, map(dpformat(py,0),py,plot_ys))", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "prompt": "

Fill in the table of values below, or move the points in the plot.

\n

{plot}

", "settings": {"initial_sheet": "empty_table", "correct_answer": "filled_table", "disable_ranges": "[]", "mark_ranges": "[\"$f(x)$ values\": y_range]", "marking_method": "per_cell", "tolerance": "0"}}], "partsMode": "all", "maxMarks": 0, "objectives": [], "penalties": [], "objectiveVisibility": "always", "penaltyVisibility": "always", "contributors": [{"name": "Christian Lawson-Perfect", "profile_url": "https://numbas.mathcentre.ac.uk/accounts/profile/7/"}]}]}], "contributors": [{"name": "Christian Lawson-Perfect", "profile_url": "https://numbas.mathcentre.ac.uk/accounts/profile/7/"}]}