diff --git a/demos/dot-and-numericalsgps.ipynb b/demos/dot-and-numericalsgps.ipynb
new file mode 100644
index 0000000..63d77b3
--- /dev/null
+++ b/demos/dot-and-numericalsgps.ipynb
@@ -0,0 +1,828 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# NumericalSgps and dot\n",
+ "\n",
+ "Some examples of `JupyterSplashDot` combined with the package [NumericalSgps](https://gap-packages.github.io/numericalsgps/).\n",
+ "\n",
+ "We start by loading the package `NumericalSgps`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "vscode": {
+ "languageId": "gap"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "true"
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {
+ "text/plain": ""
+ },
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "LoadPackage(\"num\");"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`DotBinaryRelation` can be used to produce a dot (graphviz) string from a binary relation."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "vscode": {
+ "languageId": "gap"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "digraph NSGraph{rankdir = TB; edge[dir=back];\n",
+ "1 [label=\"1\"];\n",
+ "2 [label=\"2\"];\n",
+ "2 -> 1;\n",
+ "}"
+ ]
+ }
+ ],
+ "source": [
+ "br:=BinaryRelationByElements(Domain([1,2]), [DirectProductElement([1,2])]);;\n",
+ "Print(DotBinaryRelation(br));"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The output binary relation can be visualized with `JupyterSplashDot`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "vscode": {
+ "languageId": "gap"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {
+ "image/svg+xml": {
+ "height": 500,
+ "width": 500
+ }
+ },
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "JupyterSplashDot(DotBinaryRelation(br));"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We can also visualize the Hasse diagram of the set of gaps (with respect to the ordering induced by the semigroup)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "vscode": {
+ "languageId": "gap"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {
+ "image/svg+xml": {
+ "height": 500,
+ "width": 500
+ }
+ },
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "s:=NumericalSemigroup(3,5,7);;\n",
+ "hs:=HasseDiagramOfNumericalSemigroup(s,Gaps(s));;\n",
+ "JupyterSplashDot(DotBinaryRelation(hs));"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The Hasse diagram of the oversemigroups (with respect to inclusion) of a numerical semigroup can be drawn as follows."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "vscode": {
+ "languageId": "gap"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {
+ "image/svg+xml": {
+ "height": 500,
+ "width": 500
+ }
+ },
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "JupyterSplashDot(DotOverSemigroups(s));"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Or the ways a numerical semigroup decomposes as gluings of numerical semigroups."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "vscode": {
+ "languageId": "gap"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {
+ "image/svg+xml": {
+ "height": 500,
+ "width": 500
+ }
+ },
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "JupyterSplashDot(DotTreeOfGluingsOfNumericalSemigroup( NumericalSemigroup(4,6,9)));\t"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We can also depict the factorization graph of an integer with respect to a set of non-negative integers; edges are labelled with distances between nodes and the red ones are a minimal spanning tree."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "vscode": {
+ "languageId": "gap"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {
+ "image/svg+xml": {
+ "height": 500,
+ "width": 500
+ }
+ },
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "f:=FactorizationsIntegerWRTList(20,[3,5,7]);;\n",
+ "JupyterSplashDot(DotFactorizationGraph(f));"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We can have a look at the Hasse diagram of the Apéry set of a numerical semigroup (with respect to the ordering induced by the semigroup)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "vscode": {
+ "languageId": "gap"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {
+ "image/svg+xml": {
+ "height": 500,
+ "width": 500
+ }
+ },
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "JupyterSplashDot(DotBinaryRelation(HasseDiagramOfAperyListOfNumericalSemigroup(NumericalSemigroup(10,13,15,27))));"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Other examples can be found on the Dot Functions chapter of the `numbericalsgps` package documentation."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "GAP 4",
+ "language": "gap",
+ "name": "gap-4"
+ },
+ "language_info": {
+ "codemirror_mode": "gap",
+ "file_extension": ".g",
+ "mimetype": "text/x-gap",
+ "name": "GAP 4",
+ "nbconvert_exporter": "",
+ "pygments_lexer": "gap",
+ "version": "4.12.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/demos/tikz-and-intpic.ipynb b/demos/tikz-and-intpic.ipynb
new file mode 100644
index 0000000..2bf5631
--- /dev/null
+++ b/demos/tikz-and-intpic.ipynb
@@ -0,0 +1,191 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# IntPic\n",
+ "\n",
+ "This is a notebook showing some drawings related to numerical semigroups produced with the package [IntPic](https://www.gap-system.org/Packages/intpic.html) and the help of `JupyterSplashTikZ`.\n",
+ "\n",
+ "We start by loading the package and setting the scale to 1.5, so that the pictures show bigger in the notebook."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "vscode": {
+ "languageId": "gap"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "true"
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {
+ "text/plain": ""
+ },
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "LoadPackage(\"IntPic\");\n",
+ "IP_TikzDefaultOptionsForArraysOfIntegers.scale:=\"1.5\";;"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Next we emphasize the \"small elements\" of the numerical semigroup $\\langle 5,7\\rangle$."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "vscode": {
+ "languageId": "gap"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "
"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ns:=NumericalSemigroup(13,15,17);;\n",
+ "tkz := TikzCodeForNumericalSemigroup(ns,[\"small_elements\"]);;\n",
+ "JupyterSplashTikZ(tkz);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We can modify the options to display the semigroup on a table instead."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "vscode": {
+ "languageId": "gap"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "
"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ns := NumericalSemigroup(5,7);; \n",
+ "opts:=rec(ns_table := true,negatives:=false);;\n",
+ "tkz := TikzCodeForNumericalSemigroup(ns,[\"small_elements\"],opts);;\n",
+ "JupyterSplashTikZ(tkz);"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "vscode": {
+ "languageId": "gap"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "
"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "opts := rec(ns_table:=true,colors:=[\"blue\", \"red!70\", \"-red\", \"black!40\"]);;\n",
+ "highlights := [\"conductor\", \"min_generators\", \"small_elements\"];;\n",
+ "tkz := TikzCodeForNumericalSemigroup(ns,highlights,opts);;\n",
+ "JupyterSplashTikZ(tkz);"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {
+ "scrolled": true,
+ "vscode": {
+ "languageId": "gap"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "
"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ns := NumericalSemigroup(7,11,38,41);;\n",
+ "highlights := [\"conductor\", \"min_generators\", \"small_elements\"];;\n",
+ "options := rec(ns_table:=true,colors:=[\"blue\", \"red!70\", \"-red\", \"black!40\"],negatives:=false);;\n",
+ "tkz := TikzCodeForNumericalSemigroup(ns,highlights,options);;\n",
+ "JupyterSplashTikZ(tkz);"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "GAP 4",
+ "language": "gap",
+ "name": "gap-4"
+ },
+ "language_info": {
+ "codemirror_mode": "gap",
+ "file_extension": ".g",
+ "mimetype": "text/x-gap",
+ "name": "GAP 4",
+ "nbconvert_exporter": "",
+ "pygments_lexer": "gap",
+ "version": "4.12.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/doc/_Chapter_Jupyter_Kernel.xml b/doc/_Chapter_Jupyter_Kernel.xml
new file mode 100644
index 0000000..9d0448f
--- /dev/null
+++ b/doc/_Chapter_Jupyter_Kernel.xml
@@ -0,0 +1,35 @@
+
+
+
+
+Jupyter Kernel
+
+
+ A Jupyter Kernel is an object that can handles the Jupyter Protocol.
+
+
+Functions
+
+
+
+
+
+ Opens a file that is used to log all jupyter protocol
+ messages.
+
+
+
+
+
+
+
+ Closes the protocol log.
+
+
+
+
+
+
+
+
+
diff --git a/doc/_Chunks.xml b/doc/_Chunks.xml
new file mode 100644
index 0000000..e69de29
diff --git a/doc/_entities.xml b/doc/_entities.xml
new file mode 100644
index 0000000..9ae54c0
--- /dev/null
+++ b/doc/_entities.xml
@@ -0,0 +1,8 @@
+crypting'>
+json'>
+uuid'>
+https://jupyter.org'>
+https://zeromq.org'>
+IO'>
+ZeroMQInterface'>
+JupyterKernel'>
diff --git a/gap/JupyterRenderable.gd b/gap/JupyterRenderable.gd
index 8c56c7c..4b65aaa 100644
--- a/gap/JupyterRenderable.gd
+++ b/gap/JupyterRenderable.gd
@@ -42,6 +42,7 @@ DeclareOperation("JupyterRenderable", [IsObject, IsObject] );
#! Method that provides rich viewing experience if
#! code used inside Jupyter
DeclareOperation("JupyterRender", [IsObject]);
+DeclareOperation("JupyterRender", [IsRecord]);
#! @Description
#! Accessor for data in a JupyterRenderable
diff --git a/gap/JupyterRenderable.gi b/gap/JupyterRenderable.gi
index 6543b33..61866b9 100644
--- a/gap/JupyterRenderable.gi
+++ b/gap/JupyterRenderable.gi
@@ -34,3 +34,8 @@ function(data, metadata)
return Objectify( JupyterRenderableType
, rec( data := data, metadata := metadata ) );
end);
+
+InstallMethod( JupyterRender, "for a record", [ IsRecord ],
+ r -> Objectify( JupyterRenderableType
+ , rec( data := rec( text\/plain := String(r) )
+ , metadata := rec() ) ) );
diff --git a/gap/JupyterUtil.gd b/gap/JupyterUtil.gd
index 79e3075..b76a96f 100644
--- a/gap/JupyterUtil.gd
+++ b/gap/JupyterUtil.gd
@@ -1,5 +1,9 @@
#! @Chapter Jupyter Utility Functions
-#! @Section Functions
+#!
+#! Several utility functions for GAP Jupyter Kernel
+#!
+#! @Section Print and complete functions
+#!
#! @Description
#! Jupyter printing
DeclareGlobalFunction("JUPYTER_print");
@@ -28,3 +32,24 @@ DeclareGlobalFunction("JUPYTER_Inspect");
#! Don't trust this function.
DeclareGlobalFunction("ISO8601Stamp");
+#! @Description
+#! @Arguments dot
+#! The input is a dot (grpahviz) string.
+#!
+#! The output is the graph corresponding to the dot string.
+#!
+#! Examples can be found in the numericalsgps notebook in the demo folder
+#!
+#! Prerrequisites: dot must be installed in the system.
+DeclareGlobalFunction("JupyterSplashDot");
+
+#! @Description
+#! @Arguments tikz
+#! The input is a string containing a tikzfigure.
+#!
+#! The output is the figure corresponding to that tikzfigure.
+#!
+#! Examples can be found in the inpic notebook in the demo folder
+#!
+#! Prerrequisites: pdflatex, pdfinfo, pdftoppm, and base64 must be installed in the system.
+DeclareGlobalFunction("JupyterSplashTikZ");
diff --git a/gap/JupyterUtil.gi b/gap/JupyterUtil.gi
index c7937bb..78b0c5e 100644
--- a/gap/JupyterUtil.gi
+++ b/gap/JupyterUtil.gi
@@ -1,10 +1,5 @@
-InstallMethod( JupyterRender, [ IsRecord ],
- r -> Objectify( JupyterRenderableType
- , rec( data := rec( text\/plain := String(r) )
- , metadata := rec() ) ) );
-
# This is still an ugly hack, but its already much better than before!
-BindGlobal("JupyterSplashDot",
+InstallGlobalFunction("JupyterSplashDot",
function(dot)
local fn, fd, r;
@@ -43,13 +38,13 @@ function(group)
end);
# To show TikZ in a GAP jupyter notebook
-BindGlobal("JupyterSplashTikZ",
+InstallGlobalFunction("JupyterSplashTikZ",
function(tikz)
- local tmpdir, fn, header, ltx, svgfile, stream, svgdata, tojupyter, hasbp, img, b64file;
+ local tmpdir, fn, header, ltx, pngfile, stream, pngdata, tojupyter, hasbp, img, b64file, b64cmd, dims, dimsfile, pdffile, dimx;
- hasbp:=PositionSublist(tikz,"begin{tikzpicture}")<>fail;
+ hasbp:=PositionSublist(tikz,"begin[border=2pt]{tikzpicture}")<>fail;
- header:=Concatenation( "\\documentclass[crop,tikz]{standalone}\n",
+ header:=Concatenation( "\\documentclass[crop,tikz,border=2pt]{standalone}\n",
"\\usepackage{pgfplots}",
"\\makeatletter\n",
"\\batchmode\n",
@@ -75,40 +70,58 @@ function(tikz)
Concatenation( fn, ".tex" ), " > ", Concatenation( fn, ".log2" ) );
Exec( ltx );
- if not( IsExistingFile( Concatenation(fn, ".pdf") ) ) then
+ pdffile:=Concatenation(fn, ".pdf");
+ if not( IsExistingFile( pdffile ) ) then
tojupyter := rec( json := true, name := "stdout",
data := "No pdf was created; pdflatex is installed in your system?",metadata:=rec() );
+ Info(InfoWarning,1,"No pdf was created; pdflatex is installed in your system?");
return JupyterRenderable(tojupyter.data, tojupyter.metadata);
fi;
- svgfile := Concatenation( fn, ".svg" );
- b64file := Concatenation( fn, ".b64" );
- if ARCH_IS_MAC_OS_X() then
- ltx := Concatenation( "pdf2svg ", Concatenation( fn, ".pdf" ), " ",
- svgfile, "; base64 -i ", svgfile," >> ", b64file );
-
- else
- ltx := Concatenation( "pdf2svg ", Concatenation( fn, ".pdf" ), " ",
- svgfile, "; base64 ", svgfile," >> ", b64file );
- fi;
- Exec( ltx );
- if not( IsExistingFile( svgfile ) ) then
+ dimsfile:=Concatenation(fn, "-dims.txt");
+ ltx:=Concatenation("pdfinfo ",pdffile," | grep \"Page size\" > ",dimsfile);
+ Exec(ltx);
+ if not( IsExistingFile( dimsfile ) ) then
tojupyter := rec( json := true, name := "stdout",
- data := "No svg was created; pdf2svg is installed in your system?", metadata := rec());
+ data := "pdfinfo missing in your system",metadata:=rec() );
+ Info(InfoWarning,1,"No pdf was created; pdflatex is installed in your system?");
return JupyterRenderable(tojupyter.data, tojupyter.metadata);
fi;
- stream := InputTextFile( b64file );
- if stream <> fail then
- svgdata := ReadAll( stream );
- CloseStream( stream );
- else
+
+ stream := InputTextFile( dimsfile );
+ dims:= ReadAll( stream );
+ NormalizeWhitespace(dims);
+ CloseStream( stream );
+ dimx:=Float(NormalizedWhitespace(dims{[PositionSublist(dims,": ")+2..PositionSublist(dims," x")]}));
+
+ pngfile := Concatenation( fn, ".png" );
+ ltx := Concatenation( "pdftoppm -r 300 -png ", pdffile, " > ", pngfile);
+ Exec( ltx );
+
+ if not( IsExistingFile( pngfile ) ) then
tojupyter := rec( json := true, name := "stdout",
- data := Concatenation( "Unable to render ", tikz ), metadata := rec() );
+ data := "No png was created; pdftoppm is installed in your system?",metadata:=rec() );
+ Info(InfoWarning,1,"No png was created; are convert and pdftoppm installed in your system?");
return JupyterRenderable(tojupyter.data, tojupyter.metadata);
fi;
- img:=Concatenation("
");
- return Objectify( JupyterRenderableType, rec( data := rec( ("text/html") := img), metadata:=rec() ));
+ b64file := Concatenation( fn, ".b64" );
+ if ARCH_IS_MAC_OS_X() then
+ b64cmd:="base64 -i ";
+ else
+ b64cmd:="base64 ";
+ fi;
+
+ ltx := Concatenation( b64cmd, pngfile," > ", b64file );
+ Exec( ltx );
+ stream := InputTextFile( b64file );
+ pngdata:= ReadAll( stream );
+ CloseStream( stream );
+
+
+ img:=Concatenation("\n
");
+
+ return Objectify( JupyterRenderableType, rec( data := rec( ("text/html") := img), metadata:=rec( ) ));
end);
# This is really not what I should be doing here...