Graphical Output

When working with a particular congruence subgroup it is often useful to be able to produce a picture of a fundamental domain of the group. Also when considering images of geodesics in Hh * it can be useful to draw the images. The following graphics functions provide a useful tool for this purpose.

DisplayPolygons(P,file) : SeqEnum, MonStgElt ->
    Colours: SeqEnum                    Default: [1,1,0]
    Outline: BoolElt                    Default: true
    Fill: BoolElt                       Default: true
    Show: BoolElt                       Default: false
    Labels: SeqEnum                     Default: {[0,1]}
    Fontsize: RngIntElt                 Default: 2
    Size: SeqEnum                       Default: [ ]
    Pixels: RngIntElt                   Default: 300
    Overwrite: BoolElt                  Default: false
    Radius: FldReElt                    Default: 0.5
    PenColours: SeEnum                  Default: [0,0,0]
Given a sequence of polygons, each of which is defined by a sequence of points in the upper half plane, produce the postscript drawing of these polygons, and write the result to the named file. The function returns a sequence of 4 real numbers, [x0,x1,h,S], where (x0,0) are the coordinates of the lower left corner, (x1,h) are the coordinates of the upper right corner, and the scale is such that there are S pixels per unit. These values are either given by the user, or computed automatically.
Colours : Either a sequence of 3 numbers, or a sequence of such sequences, one for each polygon in the sequence of polygons given. A colour is represented by 3 real numbers between 0 and 1, giving the red, green and blue components of the colour. This colour is used for the filling of the polygon.
PenColours : A sequence of 3 numbers, or a sequence of such sequences, one for each polygon in the sequence of polygons given. A colour is represented by 3 real numbers between 0 and 1, giving the red, green and blue components of the colour. This colour is used for drawing the outline of the polygon.
Labels : A sequence of elements of type SetCspElt, FldRatElt or RngIntElt, which will be labeled on the real axis in the diagram.
Fontsize : The size of the font used in labeling the diagram.
Pixels : When using Autoscale, the scale is computed so that the width of the resulting diagram is given by Pixels in pixels, plus a 20 pixel border. The minimal possible value for Pixels is 10, and if any smaller value is given it will be set to 10.
Size : If Size is not the empty sequence, the values in the sequence Size are used to determine the size of the image. When Size is given by [x0,x1,y,S], the picture is draw with coordinates (x0,0) in the lower left corner, (x1,h) in the upper right corner, and the scale is such that there are S pixels per unit. If Size is not given, then an appropriate size for the image is computed automatically.
Overwrite : If Overwrite is set to true, then if the name of the file given names a file which already exists, it will be overwritten. Otherwise the user will be asked whether they want to overwrite the file or not.
Show : If Show is set to true a System command is issued to make a window pop up showing the file just created. The system command is System("gv file &"). In future other options may be possible. If Show is false then
Fill : A boolean or sequence of booleans, determining whether the polygon is drawn filled in with a colour, the colour coming from the sequence Colours. If both Fill and Outline are set to false outline is reset to true.
Outline : A boolean or sequence of booleans, determining whether the polygon is drawn with an outline. If both Fill and Outline are set to false outline is reset to true.
Radius : A real number giving the radius of points marked on the diagram. A point will be marked for any polygon given by a single point.
DisplayFareySymbolDomain(FS,file) : SymFry, MonStgElt -> SeqEnum
DisplayFareySymbolDomain(G,file) : GrpPSL2, MonStgElt -> SeqEnum
    Colour: SeqEnum                     Default: [1,1,0]
    Show: BoolElt                       Default: false
    Fontsize: RngIntElt                 Default: 2
    Labelsize: RngIntElt                Default: 3
    Autoscale: BoolElt                  Default: true
    Size: SeqEnum                       Default: []
    Pixels: RngIntElt                   Default: 300
    Overwrite: BoolElt                  Default: false
    ShowInternalEdges: BoolElt          Default: false
Display: a fundamental domain corresponding to the Farey Symbol FS, or a group G, for which the Farey symbol will be computed, with edge identifications and cusps labeled. This function returns a sequence of 4 real numbers, [x0,x1,h,S], where (x0,0) are the coordinates of the lower left corner, (x1,h) are the coordinates of the upper right corner, and the scale is such that there are S pixels per unit. These values are either given by the user, or computed automatically. A polygon can be a sequence of any number of points of type HypSpcElt or SetCspElt. When at least 3 points are given a polygon is drawn. For two points, a geodesic between them is drawn. For one point a small circle is drawn to mark the point.
Colour: This colour is used in colouring the domain drawn. A colour is represented by a sequence of 3 real numbers between 0 and 1, giving the red, green and blue components of the colour.
Fontsize : The size of the font used in labeling the cusps on the diagram.
Labelsize : The size of the font used in labeling the identification labels on the diagram.
Autoscale : If true, the scale is computed and the file is created so that all the polygons listed can be seen in the diagram, if this is feasible. if Autoscale is set to false, then the variable Size must be given.
Pixels : When using Autoscale, the scale is computed so that the width of the resulting diagram is given by Pixels in pixels, plus a 20 pixel border. The minimal possible value for Pixels is 10, and if any smaller value is given it will be set to 10.
Size : When Autoscale is false, the values in the sequence Size are used to determine the size of the image. When Size is given by [x0,x1,y,S], the picture is draw with coordinates (x0,0) in the lower left corner, (x1,h) in the upper right corner, and the scale is such that there are S pixels per unit.
Overwrite : If Overwrite is set to true, then if the name of the file given names a file which already exists, it will be overwritten. Otherwise the user will be asked whether they want to overwrite the file or not.
Show : If Show is set to true a System command is issued to make a window pop up showing the file just created. The system command is System("gv file &"). In future other options may be possible. If Show is false then
ShowInternalEdges : If this is set to true then internal edges are drawn dividing the domain into fundamental domains for Γ0(2).

Example GrpPSL2_Graphics (H139E9)

In the first example we draw a fundamental domain for Γ0(12).
> G := Gamma0(24);
> FS := FareySymbol(G);
> C := Cusps(FS);
> Domain := FundamentalDomain(G);
> red := [1,0,0];
> DisplayPolygons(Domain,"/tmp/Gamma0N12.ps":
> Colours := red, Labels := C, Show := true, Fontsize := 1);
[ 0.E-28, 1.000000000000000000000000000, 1.500000000000000000000000000, 300 ]

The user could write a procedure as follows for drawing the fundamental domain as a union of fundamental domains for PSL2(Z).

> procedure draw_fundamental_domain(Group,file)
>     cosets := CosetRepresentatives(Group);
>     H<i,r> := UpperHalfPlaneWithCusps();
>     tri := [H|Infinity(),0,r];
>     red := [1,0,0];
>     yellow := [1,1,0];
>     cyan := [0,1,1];
>     cols := &cat[[red,yellow,cyan] : i in [1..(Ceiling(#cosets/3))]];
>     trans := [g*tri : g in cosets];
>     Outlines := [false : g in cosets];
>     DisplayPolygons(trans,file:
>         Colours := cols, Outline := Outlines, Show := true);
> end procedure;
>
> // use the procedure to draw a domain for Gamma_0(19):
> draw_fundamental_domain(Gamma0(19),"/tmp/gamma019.ps");
[ 0.E-28, 1.000000000000000000000000000, 1.500000000000000000000000000, 300 ]

In the following example, we use the cosets of Γ0(11) to draw a fundamental domain for Γ0(11), divided up into fundamental domains for the group of automorphisms of Hh * generated by PSL2(Z) together with the map z |-> - /line(z).

> G := Gamma0(11);
> H<i,rho> := UpperHalfPlaneWithCusps();
> tri := [H|Infinity(),i,rho];
> tri1 := [H|0,i,rho];
> C11 := CosetRepresentatives(G);
> Colours := [[0.6,0.2,0.9] : i in [1..#C11]] cat [[1,1,0] : i in [1..#C11]];
> triangles := [g*tri : g in C11] cat [g*tri1 : g in C11];
> DisplayPolygons(triangles,"/tmp/Gamma_0_11.ps":
> Colours := Colours, Show := false);
[ 0.E-57, 1.000000000000000000000000000, 1.500000000000000000000000000, 300 ]

Continuing from the above example, we can take any other polygon we wish, and look at it's translates under the action of the cosets of Γ0(11).

> tri2 := [H|Infinity(),2*i + 1,i,rho];
> DisplayPolygons([g*tri2 : g in C11],"/tmp/pic.ps":
> Colours := Colours, Show := true);
[ 0.E-57, 1.000000000000000000000000000, 2.500000000000000000000000000, 300 ]

In the next example we define three different triangles. Each of these is a fundamental domain for Γ0(2), though Magma currently does not verify this. For each choice we use a set of generators of Γ0(2) to draw a partial tiling of the upper half plane with equivalent fundamental domains.

> G := CongruenceSubgroup(4,2);
> H<i,r> := UpperHalfPlaneWithCusps();
> generators := Generators(G);
> M := generators cat [g^(-1) : g in generators] cat [G!1];
> tri1 := [H|Infinity(),r-1,0,r,r+1];
> tri2 := [H|Infinity(),i-1,0,i+1];
> tri3 := FundamentalDomain(G);
> X := [1..#M];
> L := [G!m : m in Set([Matrix(M[i]*M[j]*M[k]) : i in X, j in X, k in X])];
> DisplayPolygons([g*tri1 : g in L],"/tmp/picture1.ps": Show := true);
[ -4.000000000000000000000000000, 3.500000000000000000000000000,
1.500000000000000000000000000, 200 ]
> DisplayPolygons([g*tri2 : g in L],"/tmp/picture2.ps": Show := true);
[ -4.000000000000000000000000000, 3.000000000000000000000000000,
1.500000000000000000000000000, 200 ]
> DisplayPolygons([g*tri3 : g in L],"/tmp/picture3.ps": Show := true);
[ -4.000000000000000000000000000, 3.000000000000000000000000000,
1.500000000000000000000000000, 200 ]

Edges and Polygons with different numbers of sides can be included in the same picture, as in the following example.

> H<i,r> := UpperHalfPlaneWithCusps();
> cosets := CosetRepresentatives(Gamma0(19));
> polygons := [g*tri : g in cosets, tri in [[H|i,r],[H|i,2*r,3*r-1]]];
> outlines := [true : i in cosets] cat [false : i in cosets];
> cyan := [0,1,1];
> DisplayPolygons(polygons,"/tmp/pic.ps":
> Colours := cyan, Outline := outlines, Labels := [], Show := false);
[ 0.E-57, 1.000000000000000000000000000, 3.098076211353315940291169512, 300 ]

In the following example a function is defined to determine the colouring of the polygons in terms of which Farey sequence pairs of end points of the polygons belong to.

> frac := func<a | a[1]/a[2]>;
>
> function FareyValue(m)
>   mat := Matrix(m);
>   Denominators := [mat[2,1],mat[2,2],mat[2,1]+mat[2,2]];
>   values := [Abs(v) : v in Denominators];
>   return &+ContinuedFraction(frac(Sort(values)));
> end function;
>
> procedure drawDomain(cosets)
>    H<i,r> := UpperHalfPlaneWithCusps();
>    tri := [H|Infinity(),0,r];
>    cols := [[0.5,0.2*FareyValue(c),1-0.2*FareyValue(c)] : c  in cosets];
>    trans := [g*tri : g in cosets];
>    DisplayPolygons(trans,"/tmp/pic.ps":
>        Outline := false, Colours := cols, Show := true);
> end procedure;
>
> // Now we can use the above functions and procedure, for example
> // take the cosets as follows:
> C := CosetRepresentatives(Gamma0(41));
> // Then draw the picture:
> drawDomain(C);
[ 0.E-28, 1.000000000000000000000000000, 1.500000000000000000000000000, 300 ]

Example GrpPSL2_more-graphics (H139E10)

Functions are provided for drawing pictures coming from Farey symbols and fundamental domains. These functions provide short cuts for producing some of the pictures in the previous examples, but are not so flexible.
> G := CongruenceSubgroup(5);
> FS := FareySymbol(G);
> FS;
[ 2, 2, 7, 8, 8, 10, 9, 3, 3, 9, 4, 1, 1, 4, 5, 5, 10, 11, 11, 7, 6, 6 ]
[ oo, 0, 1/5, 2/9, 1/4, 3/11, 5/18, 2/7, 1/3, 3/8, 5/13, 2/5, 1/2, 3/5, 5/8, 2/3,
5/7, 8/11, 3/4, 7/9, 4/5, 1, oo ]
> // The following command graphically displays the information contained in FS:
> DisplayFareySymbolDomain(FS,"/tmp/Gamma5b.ps": Show := false);
[ 0, 1.0000, 0.50000, 800 ]
> // This picture represents a modular curve with genus 0:
> Genus(G);
0

Example GrpPSL2_Graphics (H139E11)

In the following example we show how to create a postscript file and include the resulting file in a latex file.

The example in question is Γ0(37). A simple question is to find what is the fundamental domain, and to give a list of inequivalent elliptic points of the group, and display this information graphically. First we create the group and find the information we are interested in:

> G := Gamma0(37);
> // To draw a picture of the fundamental domain we need to define
> // the upper half plane.
> H<i,r> := UpperHalfPlaneWithCusps();
> D := FundamentalDomain(G,H);
> E := EllipticPoints(G,H);

We can now take a look at the picture:

> // We need to make sure the polygons we want to display all
> // have the same type, so we have t create the following object:
> HH:=Parent(D);
> // now we make a list of polygons and points:
> P1:=[HH|D] cat [HH|[e] : e in E];
> // we take a look at the default picture of the situation:
> DisplayPolygons(P1,"/tmp/pic.ps": Show := true);
[ 0.E-28, 1.0000, 1.5000, 300 ]

The points have been displayed in yellow, the default colour, but we'd prefer a different colour. Also the picture is not quite the right size. It has been shown with the real axis shown from 0 to 1, which is reasonable, but we'd prefer less height, and the scale 300 could be changed, as in this example:

> // use different colours:
> yellow := [1,1,0];
> red := [1,0,0];
> green := [0,1,0];
> cyan := [0,1,1];
> black := [0,0,0];
> Colours := [yellow] cat [red : e in E];
> // use a different size and scale:
> Size := [0,1,0.2,400];
> // view the result:
> DisplayPolygons(P1,"/tmp/pic.ps":
> Show := true, Colours := Colours, Size := Size);
[ 0, 1, 0.1999999999999999999999999999, 400 ]
After more experimenting we reach the following:
> // We use a slightly different list of polygons, to show more
> // structure.
> tri := [H|Infinity(),0,H.2];
> cosets := CosetRepresentatives(G);
> P := [HH|g*tri : g in cosets] cat [HH|[e] : e in E] cat [HH|D];
> // Choosing some colours:
> LotsOfColours := &cat[[yellow,green,cyan] : c in cosets];
> Colours := [LotsOfColours[i] : i in [1..#cosets]]
>            cat [black]
>            cat [red : e in E];
> // choose which polygons are filled, and which have outlines:
> outlines := [false : i in cosets] cat [false : i in E] cat [true];
> fill := [true : i in cosets] cat [true : i in E] cat [false];
> labels := Cusps(FareySymbol(G));
> // Create a file of the result:
> DisplayPolygons(P,"/tmp/pic.ps":
> Colours := Colours, Show := false, Size := [0,1,1,200],
> Labels := labels, Outline := outlines, Fill := fill,
> Fontsize := 1, Radius := 0.3);
[ 0, 1, 1, 200 ]

If we are satisfied with the resulting picture then we can include the resulting picture in a latex file as in the following example, where we use the Latex graphicx package to include the diagram.

\documentclass{article}
\usepackage[dvips]{graphicx}
\begin{document}
Here is a picture of a
fundamental domain for $Γ_0(37)$:
$${\includegraphics{/tmp/pic.ps}}$$
In the picture we have marked $4$ inequivalent
elliptic points.
\end{document}

Note that currently, given a list of points to draw, the postscript file will include all of the points, even if they are not in the area of the bounding box, which can produce bad results some times. This should be changed in a future version. Sometimes using the Fundamental domain function can produce results in a more reliable way, as in the following example, which produces a similar picture to the above, and a latex file can be written in the same way.

> G := Gamma0(37);
> H<i,r> := UpperHalfPlaneWithCusps();
> D := FundamentalDomain(G,H);
> HH:=Parent(D);
> E := EllipticPoints(G,H);
> P:=[HH|D] cat [HH|[e] : e in E];
> labels := Cusps(FareySymbol(G));
> yellow := [1,1,0];
> red := [1,0,0];
> Colours := [yellow] cat [red : e in E];
> DisplayPolygons(P,"/tmp/pic.ps":
> Colours := Colours, Show := false, Size := [0,1,0.2,200],
> Labels := labels,
> Fontsize := 1, Radius := 0.3);
[ 0, 1, 0.1999999999999999999999999999, 200 ]
V2.28, 13 July 2023