If you're just trying to display four images in a tabular form, I would use a layout table instead of trying to put it into a math equation. I think something like the following would work.
loadMacros("niceTables.pl"); @figs = ( image("H1_1_1.png"), image("H1_1_2.png"), image("H1_1_3.png"), image("H1_1_4.png") ); BEGIN_PGML [@ LayoutTable( [ [ $figs[0], $figs[1] ], [ $figs[2], $figs[3] ] ] ) @]* END_PGML
More information about the LayoutTable command is at http://webwork.maa.org/wiki/Tables.
Gavin[: :]
produces typeset mathematics using algebra notation as the input. The Array()
function is for creating arrays of mathematics. The algebra notation does not include a mechanism for including images in the displayed mathematics, and even if it did, that would not be an appropriate means of doing the table you are looking for. The LayoutTable()
that Gavin proposes is the right way to do it.Also, it is not really appropriate to use mathematics for spacing purposes outside of mathematics, so
[: quad quad :]
is not really very good either. You could have used pre-formatted layout if you wanted spacing to count. That is initiated by a colon with three spaces.
But LayoutTable() is a macro in niceTables.pl, to be distinguished from DataTable(). If your reason for making a "table" is purely to position things in a grid, and the x- and y-positions of the elements don't really matter, then using LayoutTable() will be better for accessibility reasons. In HTML output, instead of making an HTML table, it uses divs with special table-like styling. This is preferred by users with screen readers, because the HTML table structure is too rich. The screen readers would give the reader all the information about where each of your images are in the (nth row, mth column) form, and that's usually unnecessary and distracting.
Meanwhile in hard copy output, LayoutTable() and DataTable() both use tabular.
For more details on options for using LayoutTable(), see all the commentary on the top of the file here: https://github.com/openwebwork/pg/blob/master/macros/niceTables.pl
Try:
where I've added a space character and used the concatenation operator (period) to glue the image to the label. I'm not 100% sure this will give you what you want, as far as positioning goes. You might want to try things like:
Also, we have used a more elaborate method for similar questions to this that you might mimic: https://github.com/openwebwork/webwork-open-problem-library/blob/master/OpenProblemLibrary/PCC/BasicAlgebra/GraphingPointsAndLines/GraphLinearEquationByIntercepts10.pg
Is this your WeBWorK server?
http://webwork.xula.edu/webwork2/
If so, it looks like the version of WeBWorK is a bit old, maybe 2.7. Some issues you may be experiencing with PGML and array indices may (or may not) have been resolved in PGML by now.
>http://webwork.xula.edu/webwork2/
'A '.$fig[0]
. Note that you could also do "A $fig[0]"
instead, if you wish.
For (2), it turns out that the image()
macro includes a lot of extra spaces and some line breaks, so those are being included in the reformatted display.
One way around that is to remove them via regular expression substitution. Here is an example:
loadMacros("PGML.pl","PGgraphmacros.pl"); sub IMAGE { my $out = image(@_); $out =~ s/~~s*([~~n~~t]+~~s*)+|^~~s+|~~s+$//g; return $out; } $fig[0] = IMAGE("http://www.math.union.edu/random/pix/Folding-Cube.gif"); $fig[1] = IMAGE("http://www.math.union.edu/random/pix/helicoid.gif"); $fig[2] = IMAGE("http://www.math.union.edu/random/pix/Saddle-Slice.gif"); $fig[3] = IMAGE("http://www.math.union.edu/random/pix/TFB-2.gif"); BEGIN_PGML : A [$fig[0]]* B [$fig[1]]* : : C [$fig[2]]* D [$fig[3]]* END_PGMLHere, I define a new
IMAGE()
macro to handle removing the unwanted spaces and newlines.
There are also several alternatives. You could use the imageRow()
macro to generate a table with images and captions:
loadMacros("PGML.pl"); $fig[0] = "http://www.math.union.edu/random/pix/Folding-Cube.gif"; $fig[1] = "http://www.math.union.edu/random/pix/helicoid.gif"; $fig[2] = "http://www.math.union.edu/random/pix/Saddle-Slice.gif"; $fig[3] = "http://www.math.union.edu/random/pix/TFB-2.gif"; BEGIN_PGML [@ imageRow([ $fig[0], $fig[1] ], ["A","B"]) @]* [@ imageRow([ $fig[2], $fig[3] ], ["C","D"]) @]* END_PGMLFinally, there are some extensions of the choice macros that make image selection lists in the Union macro library. These handle things like randomizing the order of questions and answers, but are more complicated to use.
loadMacros("PGML.pl","imageChoice.pl","contextABCD.pl","unionImage.pl"); $name = "http://www.math.union.edu/random/pix/Folding-Cube.gif"; $ml = new_image_match_list( link => 0, # don't link to separate image size => [100,100], # image size in pixels border => 0, # image already includes a border ); $ml->{separation} = 3; # separation for questions in the list $ml->qa( # set the questions and answers "A Folding Cube", "http://www.math.union.edu/random/pix/Folding-Cube.gif", "A Helicoid", "http://www.math.union.edu/random/pix/helicoid.gif", "A Saddle Surface sliced by a plane", "http://www.math.union.edu/random/pix/Saddle-Slice.gif", "Projection of a torus from four-space", "http://www.math.union.edu/random/pix/TFB-2.gif", ); $ml->choose(4); # select all of them BEGIN_PGML [@ $ml->print_q @]* [@ $ml->print_a @]* END_PGML Context("ABCD"); ANS(string_cmp($ml->ra_correct_ans)); $showPartialCorrectAnswers = 0; install_problem_grader(~~&std_problem_grader);
Finally, for (3), the issue with array section within PGML was fixed around two years ago, so you are probably using an old version of PGML.pl. If you update, that should allow you to use [$fig[$i]]
. For now, however, you can use [$fig[ $i ]]
(note the space between [
and $i
).
The first line uses the image()
function and calls it with all the parameters passed to IMAGE()
. For any subroutine, the @_
array is the array of arguments that it received, and image(@_)
simply passes those on to image()
. It stores the result in a local variable $out
(the my
means that variable is local to the IMAGE()
subroutine).
The last line returns the value of $out
so the only thing left to understand is the second line. That line performs a "regular expression" substitution. Regular expressions (or regex) are pattern matching expressions that are used to locate specific patterns within a string, and (in this case) replace them with other values. Many programming languages include them, so they have a fairly well-know syntax, but Perl regular expressions are documented here.
This is where the PG-specific item comes into play. Regular expressions have a means of indicating special characters (like newlines and tabs) or collections of characters (like "white space" in general), and this method uses backslashes to indicate them. But PG handles backslashes specially (because they are used in TeX code) and in such a way that they don't work properly in regular expressions within a PG file. So PG provides an alternative, which is ~~
.
Every ~~
you see in the IMAGE()
function should be a \
in normal Perl code. So the regular expression on the second line is actually
$out =~ s/\s*([\n\t]+\s*)+|^\s+|\s+$//g;The
=~
says apply the substitution on the right to the variable on the left (i.e., modify $out
by the regex). The s/
indicates a substitution (as opposed to just a matching operation) is to be performed. The stuff up to the next (unescaped) /
is the matching regular expression, and the stuff between that an the next /
is what to replace it by. (So a substitution usually looks like s/regex/replacement/
.
In this case, the regex is \s*([\n\t]+\s*)+|^\s+|\s+$
, which I will explain in a moment, and the replacement string is empty (the material between the slashes in //
). The trailing g
means the substitution is global, meaning every substring that matches the regex will be replaced (not just the first one).
So the upshot is that anything the matches the regex will be removes from the string (since the replacement string is empty).
So what matches this particular regex? This is where the reference I cite above comes in, but I'll explain this one now. The first thing to know is that |
is used to separate sub-expressions, any one of which is allowed to be matched. So this means that there are three things that we are looking for, any one of which can be matched (i.e., all occurrences of these three patterns will be removed).
The three subexpressions are \s*([\n\t]+\s*)+
, ^\s+
,and \s+$
. I will explain the last two first.
The caret (^
) indicates the start of the string, so ^\s+
only will match something at the beginning of the string. Similarly, the dollar sign ($
) matches the end of the string, so \s+$
only matches something at the end of the string. The \s
indicates any white-space character (space, tab, non-breaking space, etc.), and +
means that the preceding item must appear one or more times in a row. That is, ^\s+
matches all the spaces at the beginning of the string, while \s+$
matches all the spaces at the end of the string.
The regex \s*([\n\t]+\s*)+
starts with \s*
. We already know \s
matches while space; here the *
means the preceding can match zero or more times. So this is zero or more spaces. The next part uses parentheses to group the regex [\n\t]+\s*
so that +
applies to that whole thing. That means one or more occurrences of stuff that matches [\n\t]+\s*
. So this is [\n\t]+
followed by zero or more spaces.
The brackets are used to enclose a list of characters to match (e.g., [aeiou]
would match one of the vowels), and in this case, we are matching \n
and \t
. These are the newline (\n
) and tab (\t
). So [\n\t]+
means one or more newlines or tabs, and [\n\t]+\s*
means one or more newlines or tabs followed by optional spaces. Finally, ([\n\t]+\s*)+
means any number of those in a row (but at least one), and \s*([\n\t]+\s*)+
means optional spaces followed by newlines and tabs followed by optional spaces, repeated at least once.
Anything that matches any of those three patterns will be removed. So the upshot is that the second pattern removes any leading whitespace in the string, the third one removes any trailing whitespace in the string, and the first pattern removes any line breaks and the whitespace surrounding them.
So the upshot is to remove any line breaks and the whitespace around them, and any whitespace at the beginning or end of the string. This was the whitespace that was causing problems when the image was included in the pre-formatted output, since in pre-formatted output, multiple spaces and newlines are respected, while in regular formatted HTML they are collapsed to a single space.
Hope that helps.