-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
5,606 additions
and
0 deletions.
There are no files selected for viewing
734 changes: 734 additions & 0 deletions
734
...ng_contest_problem/questions-PCPA-PROTOTYPE_programming_contest_problem-20210802-1645.xml
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
468 changes: 468 additions & 0 deletions
468
python3_html_gapfiller/questions-Quiz2021-PROTOTYPE_python3_html_gapfiller-20210802-1644.xml
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<div class="coderunner-test-results good"> | ||
<a class="btn btn-link coderunner-solution-link" style="background-color:#CFC">Show author's solution</a> | ||
</div> | ||
<div class="coderunner-authors-solution collapse" expanded="false" style="margin-bottom:8px"> | ||
<pre class="code-highlight">%s</pre> | ||
</div> | ||
<script> | ||
window.coderunner_solution_link_clicked = window.coderunner_solution_link_clicked || function(src) { | ||
var question = src.target.closest('div.specificfeedback'); | ||
var solution_div = question.getElementsByClassName('coderunner-authors-solution')[0]; | ||
var solution_link = question.getElementsByClassName('coderunner-solution-link')[0]; | ||
var code = question.getElementsByClassName('code-highlight')[0]; | ||
|
||
if (!code.classList.contains('has-highlight')) { | ||
var highlight = window.ace.require("ace/ext/static_highlight"); | ||
highlight(code, { | ||
mode: "ace/mode/python", | ||
showGutter: false | ||
}, function(highlighted) { | ||
code.getElementsByClassName('ace_static_highlight')[0].style['font-size'] = "14px"; | ||
}); | ||
code.classList.add('has-highlight'); | ||
} | ||
|
||
if (!$(solution_div).hasClass('collapsing')) { | ||
if ($(solution_div).attr("expanded") === "true") { | ||
solution_link.innerHTML = "Show author's solution"; | ||
$(solution_div).collapse('hide'); | ||
$(solution_div).attr("expanded", "false"); | ||
} else { | ||
solution_link.innerHTML = "Hide author's solution"; | ||
$(solution_div).collapse('show'); | ||
$(solution_div).attr("expanded", "true"); | ||
} | ||
} | ||
} | ||
var coderunner_all_links = document.getElementsByClassName('coderunner-solution-link'); | ||
|
||
for (var i = 0; i < coderunner_all_links.length; i++) { | ||
var el = coderunner_all_links[i]; | ||
if (!el.classList.contains('has-click-handler')) { | ||
el.addEventListener('click', window.coderunner_solution_link_clicked); | ||
el.classList.add('has-click-handler'); | ||
} | ||
} | ||
</script> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<div class="coderunner-test-results bad"> | ||
<a class="btn btn-link coderunner-scrambled-solution-link" style="background-color:#FCC">Show scrambled author's solution</a> | ||
</div> | ||
<div class="coderunner-scrambled-authors-solution collapse" expanded="false" style="margin-bottom:8px"> | ||
<pre class="code-highlight">%s</pre> | ||
</div> | ||
<script> | ||
window.coderunner_solution_link_clicked = window.coderunner_solution_link_clicked || function(src) { | ||
var question = src.target.closest('div.specificfeedback'); | ||
var solution_div = question.getElementsByClassName('coderunner-scrambled-authors-solution')[0]; | ||
var solution_link = question.getElementsByClassName('coderunner-scrambled-solution-link')[0]; | ||
var code = question.getElementsByClassName('code-highlight')[0]; | ||
|
||
if (!code.classList.contains('has-highlight')) { | ||
var highlight = window.ace.require("ace/ext/static_highlight"); | ||
highlight(code, { | ||
mode: "ace/mode/python", | ||
showGutter: false | ||
}, function(highlighted) { | ||
code.getElementsByClassName('ace_static_highlight')[0].style['font-size'] = "14px"; | ||
}); | ||
code.classList.add('has-highlight'); | ||
} | ||
|
||
if (!$(solution_div).hasClass('collapsing')) { | ||
if ($(solution_div).attr("expanded") === "true") { | ||
solution_link.innerHTML = "Show scrambled author's solution"; | ||
$(solution_div).collapse('hide'); | ||
$(solution_div).attr("expanded", "false"); | ||
} else { | ||
solution_link.innerHTML = "Hide scrambled author's solution"; | ||
$(solution_div).collapse('show'); | ||
$(solution_div).attr("expanded", "true"); | ||
} | ||
} | ||
} | ||
var coderunner_all_links = document.getElementsByClassName('coderunner-scrambled-solution-link'); | ||
|
||
for (var i = 0; i < coderunner_all_links.length; i++) { | ||
var el = coderunner_all_links[i]; | ||
if (!el.classList.contains('has-click-handler')) { | ||
el.addEventListener('click', window.coderunner_solution_link_clicked); | ||
el.classList.add('has-click-handler'); | ||
} | ||
} | ||
</script> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
"""The generic LanguageTask, subclasses of which manage compiling and executing | ||
code in a particular language. | ||
""" | ||
from datetime import datetime | ||
|
||
WATCHDOG_FREEBOARD = 1 | ||
|
||
class CompileError(Exception): | ||
def __init__(self, error_message): | ||
Exception.__init__(self, error_message) | ||
|
||
|
||
class RunError(Exception): | ||
def __init__(self, error_message=''): | ||
Exception.__init__(self, error_message) | ||
|
||
class LanguageTask: | ||
def __init__(self, params, code=None): | ||
"""Initialise the object, recording the parameters that will control compilation and | ||
running plus the code if supplied. Code may be alternatively be supplied later by | ||
calls to set_code. | ||
self.params is the dictionary of template & global parameters - language specific. | ||
""" | ||
self.params = params | ||
self.code = code | ||
self.executable_built = False | ||
self.compile_error_message = None | ||
self.error_message_offset = 0 | ||
self.stderr = '' | ||
self.stdout = '' | ||
self.start_time = datetime.now() | ||
self.timed_out = False | ||
if 'totaltimeout' not in params: | ||
self.params['totaltimeout'] = 30 # Secs | ||
|
||
def seconds_remaining(self): | ||
"""The number of seconds of execution time remaining before the watchdog timer goes off. | ||
The watchdog timer goes off 1 second before runguard kills the job (as determined by the 'timeout' parameter). | ||
""" | ||
t_elapsed = (datetime.now() - self.start_time).total_seconds() | ||
return self.params['totaltimeout'] - t_elapsed - WATCHDOG_FREEBOARD | ||
|
||
def set_code(self, code, error_message_offset=0): | ||
"""Set the code to be used for subsequent compiling and running. The optional error_message_offset | ||
is a number to be subtracted from any error messages generated by compile and run_code calls. | ||
Exactly how (or even 'if') it is used is language dependent. | ||
""" | ||
self.code = code | ||
self.error_message_offset = error_message_offset | ||
|
||
def compile(self, make_executable=False): | ||
"""Compile the currently set code, either to an object file or | ||
to an executable file depending on the given make_executable parameter. | ||
Adjust any error message by subtracting error_message_offset. | ||
Raise CompileError if the code does not | ||
compile, with the compilation error message within the exception | ||
and also recorded in self.compile_error_message. | ||
No return value. | ||
""" | ||
raise NotImplementedError("compile not implemented by concrete class") | ||
|
||
def discard_executable(self): | ||
"""Called if something breaks in the executable and it will need rebuilding | ||
(with different source, presumably) | ||
""" | ||
self.executable_built = False | ||
|
||
def run_code(self, standard_input=None, bash_command=None): | ||
"""Run the code in the executable program that a call to compile is assumed | ||
to have created, using the given standard input. | ||
If a bash_command is supplied it used as given. | ||
Otherwise the command to be executed is the compiled executable. | ||
Returns a tuple of the output from the | ||
run and a stderr (or a derivative thereof) string. Those two values | ||
are also recorded in self.stdout and self.stderr respectively. | ||
""" | ||
raise NotImplementedError("run_code not implemented by concrete class") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
"""Define support functions for testing of matplotlib questions. | ||
The main function is print_plot_info, which displays suitably formatted | ||
data about the current matplotlib plot. | ||
This module works only if imported *after* a call to matplotlibg.use("Agg") has | ||
been done. | ||
""" | ||
import numpy as np | ||
import matplotlib.pyplot as plt | ||
from matplotlib import colors as colors | ||
from scipy import interpolate | ||
|
||
MAX_LABEL_LENGTH = 60 # Use multiline display if the tick label string length exceeds this | ||
|
||
def my_interpolate(data, xs): | ||
"""Return the spline interpolated list of (x, y) values at abscissa xs, given | ||
a list of (x, y) pairs | ||
""" | ||
def linear(x, x0, y0, x1, y1): | ||
return y0 + (x - x0)/(x1 - x0) * (y1 - y0) | ||
|
||
if len(data[:,0]) == 2: | ||
x0, y0 = data[0][0], data[0][1] | ||
x1, y1 = data[-1][0], data[-1][1] | ||
return [(x, linear(x, x0, y0, x1, y1)) for x in xs] | ||
else: # cubic | ||
tck = interpolate.splrep(data[:,0], data[:,1], s=0) # Cubic spline interpolator | ||
return zip(xs, interpolate.splev(xs, tck)) # Evaluate at required x values | ||
|
||
|
||
def fmt_float_pair(p): | ||
"""A formatted point or other pair of floating-point numbers""" | ||
return f"({p[0]:.2f}, {p[1]:.2f})" | ||
|
||
|
||
def tick_fmt(tick): | ||
"""Format a tick label, which may be either a string or a float. If it's | ||
a float, try to format it as an int, otherwise format it to 2 decimal | ||
places. | ||
""" | ||
if isinstance(tick, str): | ||
return tick | ||
elif float(int(tick)) == tick: | ||
return str(int(tick)) | ||
else: | ||
return f"{tick:.2f}" | ||
|
||
|
||
def normalise_colour(colour): | ||
"""Given a matplotlib colour, convert to a standarised format""" | ||
rgb = colors.to_rgb(colour) | ||
return f"RGB({rgb[0]:0.2f}, {rgb[1]:0.2f}, {rgb[2]:0.2f})" | ||
|
||
|
||
def print_lines(subplot, x_samples, show_colour, has_legend): | ||
"""Print all lines in the plot showing y values interplolated at the given x sample points, | ||
if not None. Otherwise print just the first 5 and last 5 points. Also | ||
show line colours if show_colour is True. | ||
""" | ||
lines = subplot.get_lines() | ||
if len(lines) == 0: | ||
print("No plotted lines found") | ||
return | ||
multilines = len(lines) > 1 | ||
if multilines: | ||
print(f"{len(lines)} separate plots found") | ||
for i, line in enumerate(lines, 1): | ||
if multilines: | ||
print(f"Line {i}:") | ||
if show_colour: | ||
print("Color:", normalise_colour(line.get_color())) | ||
print("Marker:", line.get_marker()) | ||
print("Line style:", line.get_linestyle()) | ||
label = line.get_label() | ||
if has_legend and label: | ||
print("Label:", label) | ||
data = line.get_xydata() | ||
if x_samples is not None: | ||
print(f"First point: {fmt_float_pair(data[0])}") | ||
print(f"Last point: {fmt_float_pair(data[-1])}") | ||
print(f"Interpolating line at selected x values:") | ||
interpolated = my_interpolate(data, x_samples) | ||
for p in interpolated: | ||
print(fmt_float_pair(p)) | ||
else: | ||
print(f"Num points: {len(data)}") | ||
n = min(len(data), 5) | ||
points = '\n '.join(fmt_float_pair(p) for p in data[:n]) | ||
print(f"First {n} points:\n {points}") | ||
last_n = min(len(data) - n, 5) | ||
if last_n: | ||
points = '\n '.join(fmt_float_pair(p) for p in data[-last_n:]) | ||
print(f"Last {last_n} points:\n {points}") | ||
if multilines: | ||
print() | ||
|
||
|
||
def in_range(labels, limits): | ||
"""Return the list of axis labels, filtered to include only those within | ||
the given limits (min, max). If any of the axis labels are non-numeric | ||
the list is returned unchanged. | ||
""" | ||
try: | ||
clipped_labels = [] | ||
for s in labels: | ||
s_orig = s | ||
if isinstance(s, str): | ||
s = s.replace('−', '-') | ||
if limits[0] <= float(s) <= limits[1]: | ||
clipped_labels.append(s_orig) | ||
return clipped_labels | ||
except ValueError: | ||
return labels | ||
|
||
|
||
def print_bars(subplot, show_colour): | ||
"""Print a list of all bars""" | ||
print("Bars:") | ||
bars = subplot.patches | ||
if bars and show_colour: | ||
print(f"First bar colour: {normalise_colour(bars[0].get_facecolor())}") | ||
for i, bar in enumerate(subplot.patches): | ||
print(f"Bar{i}: x = {int(bar.get_xy()[0] + bar.get_width() / 2)} height = {bar.get_height():.2f}") | ||
|
||
|
||
def tick_label_text(labels): | ||
"""Return a string suitable for displaying tick labels""" | ||
label_text = ', '.join(labels) | ||
if len(label_text) > MAX_LABEL_LENGTH: | ||
label_text = '\n'.join(labels) | ||
return label_text | ||
|
||
|
||
def print_plot_info(data_type, x_samples=None, | ||
show_xlim=False, show_ylim=False, | ||
show_colour=False, | ||
show_xticklabels=None, # Default is True for bar chars, False otherwise | ||
show_yticklabels=False | ||
): | ||
"""Output key attributes of current plot, as defined by plt.gca(). | ||
data_type must be one of 'points', 'lines' or 'bars', to print the | ||
appropriate type of data. | ||
x_samples, meaningful only if data_type = 'lines', is a list of x values | ||
at which the graph y values should be printed | ||
""" | ||
try: | ||
axes = plt.gcf().get_axes() | ||
texts = plt.gcf().texts | ||
if len(axes) > 1: | ||
print(f"Figure has {len(axes)} subplots") | ||
if len(texts) != 0: | ||
print(f"Suptitle: {texts[0].get_text()}\n") | ||
for i, current_axes in enumerate(axes, 1): | ||
if len(axes) > 1: | ||
print(f"Subplot {i}\n---------") | ||
subplot = current_axes.axes | ||
has_legend = subplot.get_legend() is not None | ||
print("Plot title: '{}'".format(current_axes.title.get_text())) | ||
print("X-axis label: '{}'".format(subplot.get_xlabel())) | ||
print("Y-axis label: '{}'".format(subplot.get_ylabel())) | ||
xgridlines = subplot.get_xgridlines() | ||
ygridlines = subplot.get_ygridlines() | ||
gridx_on = len(xgridlines) > 0 and xgridlines[0].get_visible() | ||
gridy_on = len(ygridlines) > 0 and ygridlines[0].get_visible() | ||
print(f"(x, y) grid lines enabled: ({gridx_on}, {gridy_on})") | ||
xlim = subplot.get_xlim() | ||
ylim = subplot.get_ylim() | ||
if show_xlim: | ||
print(f"X-axis limits: {fmt_float_pair(xlim)}") | ||
if show_ylim: | ||
print(f"Y-axis limits: {fmt_float_pair(ylim)}") | ||
if data_type == 'points': | ||
print_lines(subplot, None, show_colour, has_legend) | ||
elif data_type == 'lines': | ||
print_lines(subplot, x_samples, show_colour, has_legend) | ||
elif data_type == 'bars': | ||
print_bars(subplot, show_colour) | ||
|
||
if show_xticklabels or (show_xticklabels is None and data_type == 'bars'): | ||
x_tick_labels = [label.get_text() for label in subplot.get_xticklabels()] | ||
if all(label.strip() == '' for label in x_tick_labels): | ||
x_tick_labels = [tick_fmt(pos) for pos in subplot.get_xticks()] | ||
x_tick_labels = in_range(x_tick_labels, xlim) | ||
print('\nX-axis tick labels:') | ||
print(tick_label_text(x_tick_labels)) | ||
|
||
if show_yticklabels: | ||
y_tick_labels = [label.get_text() for label in subplot.get_yticklabels()] | ||
if all(label.strip() == '' for label in y_tick_labels): | ||
y_tick_labels = [tick_fmt(pos) for pos in subplot.get_yticks()] | ||
y_tick_labels = in_range(y_tick_labels, ylim) | ||
print("\nY-axis tick labels:") | ||
print(tick_label_text(y_tick_labels)) | ||
|
||
if has_legend: | ||
print(f"Legend: True") | ||
|
||
if len(axes) > 1: | ||
print(40 * "=") | ||
print() | ||
|
||
|
||
except Exception as exception: | ||
print("Failed to get plot info:", str(exception)) |
Oops, something went wrong.