Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/GAP/pkg/jupyterviz/lib/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 16.7.2022 mit Größe 42 kB image not shown  

Quelle  main.gd   Sprache: unbekannt

 
############################################################################
##
##
#W  main.gd              JupyterViz Package                  Nathan Carter
##
##  Declaration file for functions of the JupyterViz package.
##
#Y  Copyright (C) 2018 University of St. Andrews, North Haugh,
#Y                     St. Andrews, Fife KY16 9SS, Scotland
##

#! @Chapter Function reference
#! @ChapterLabel funcref

#! @Section High-Level Public API

#! @Arguments various
#! @Returns one of two things, documented below
#! @Description
#!  If evaluated in a Jupyter Notebook, the result of this function, when
#!  rendered by that notebook, will run JavaScript code that generates and
#!  shows a plot in the output cell, which could be any of a wide variety of
#!  data visualizations, including bar charts, pie charts, scatterplots, etc.
#!  (To draw a vertex-and-edge graph, see <Ref Func="PlotGraph"/> instead.)
#!  <P/>
#!  If evaluated outside of a Jupyter Notebook, the result of this function
#!  is the name of a temporary file stored on disk in which HTML code for
#!  such a visualization has been written, and on which &GAP; has already
#!  invoked the user's default web browser.  The user should see the
#!  visualization appear in the browser immediately before the return value
#!  is shown.
#!  <P/>
#!  This function can take data in a wide variety of input formats.  Here is
#!  the current list of acceptable formats:
#!  <List>
#!    <Item>If <Code>X</Code> is a list of <Math>x</Math> values and
#!      <Code>Y</Code> is a list of <Math>y</Math> values then
#!      <Code>Plot(X,Y)</Code> plots them as ordered pairs.</Item>
#!    <Item>If <Code>X</Code> is a list of <Math>x</Math> values and
#!      <Code>f</Code> is a &GAP; function that can be applied to each
#!      <Math>x</Math> to yield a corresponding <Math>y</Math>, then
#!      <Code>Plot(X,f)</Code> computes those corresponding <Math>y</Math>
#!      values and plots everything as ordered pairs.</Item>
#!    <Item>If <Code>P</Code> is a list of <Math>(x,y)</Math> pairs then
#!      <Code>Plot(P)</Code> plots those ordered pairs.</Item>
#!    <Item>If <Code>Y</Code> is a list of <Math>y</Math> values then
#!      <Code>Plot(Y)</Code> assumes the corresponding <Math>x</Math>
#!      values are 1, 2, 3, and so on up to the length of <Code>Y</Code>.
#!      It then plots the corresponding set of ordered pairs.</Item>
#!    <Item>If <Code>f</Code> is a &GAP; function then <Code>Plot(f)</Code>
#!      assumes that <Code>f</Code> requiers integer inputs and evaluates it
#!      on a small domain (1 through 5) of <Math>x</Math> values and plots
#!      the resulting <Math>(x,y)</Math> pairs.</Item>
#!    <Item>In any of the cases above, a new, last argument may be added
#!      that is a &GAP; record (call it <Code>R</Code>) containing options
#!      for how to draw the plot, including the plot type, title, axes
#!      options, and more.  Thus the forms <Code>Plot(X,Y,R)</Code>,
#!      <Code>Plot(X,f,R)</Code>, <Code>Plot(P,R)</Code>,
#!      <Code>Plot(Y,R)</Code>, and <Code>Plot(f,R)</Code> are all acceptable.
#!      (For details, see <Ref Var="ConvertDataSeriesForTool"/>.)</Item>
#!    <Item>If <Code>A1</Code> is a list of arguments fitting any of the
#!      cases documented above (such as <Code>[X,f]</Code>) and
#!      <Code>A2</Code> is as well, and so on through <Code>An</Code>, then
#!      <Code>Plot(A1,A2,...,An)</Code> creates a combination plot with all
#!      of the data from each of the arguments treated as a separate data
#!      series.  If the arguments contain conflicting plot options (e.g.,
#!      the first requests a line plot and the second a bar chart) then the
#!      earliest option specified takes precedence.</Item>
#!  </List>
#!  <P/>
#! @BeginLog
#! # Plot the number of small groups of order n, from n=1 to n=50:
#! Plot( [1..50], NrSmallGroups );
#! @EndLog
#! <Alt Only="LaTeX">
#!     \begin{center}
#!         \includegraphics[width=4in]{groups-plot.png}
#!     \end{center}
#! </Alt>
#! <Alt Only="HTML"><![CDATA[<img width="500" src="groups-plot.png"/>]]></Alt>
#! <Alt Not="LaTeX HTML">Resulting image not shown here.</Alt>
#! @BeginLog
#! # Plot how much Andrea has been jogging lately:
#! Plot( ["Jan","Feb","Mar"], [46,59,61],
#!       rec( title := "Andrea's Jogging", yaxis := "miles per month" ) );
#! @EndLog
#! <Alt Only="LaTeX">
#!     \begin{center}
#!         \includegraphics[width=4in]{andrea-plot.png}
#!     \end{center}
#! </Alt>
#! <Alt Only="HTML"><![CDATA[<img width="500" src="andrea-plot.png"/>]]></Alt>
#! <Alt Not="LaTeX HTML">Resulting image not shown here.</Alt>
DeclareGlobalFunction( "Plot" );

#! @Description
#!  The <Package>JupyterViz</Package> Package has a high-level API and a
#!  low-level API.  The high-level API involves functions like
#!  <Code>Plot</Code>, which take data in a variety of convenient formats,
#!  and produce visualizations from them.  The low-level API can be used to
#!  pass JSON data structures to JavaScript visualization tools in their own
#!  native formats for rendering.  The high-level API is built on the
#!  low-level API, using key functions to do the conversion.
#!  <P/>
#!  The conversion functions for plots are stored in a global dictionary
#!  in this variable.  It is a &GAP; record mapping visualization tool
#!  names (such as plotly, etc., a complete list of which appears in Section
#!  <Ref Sect="Section_purpose"/>) to conversion functions.  Only those
#!  tools that support plotting data in the form of <Math>(x,y)</Math> pairs
#!  should be included.  (For example, tools that specialize in drawing
#!  vertex-and-edge graphs are not relevant here.)
#!  <P/>
#!  Each conversion function must behave as follows.  It expects its input
#!  object to be a single data series, which will be a &GAP; record with
#!  three fields:
#!  <List>
#!    <Item><Code>x</Code> - a list of <Math>x</Math> values for the
#!      plot</Item>
#!    <Item><Code>y</Code> - the corresponding list of <Math>y</Math> values
#!      for the same plot</Item>
#!    <Item><Code>options</Code> - another (inner) &GAP; record containing
#!      any of the options documented in Section
#!      <Ref Sect="Section_plotopts"/>.</Item>
#!  </List>
#!  <P/>
#!  The output of the conversion function should be a &GAP; record amenable
#!  to conversion (using <Code>GapToJsonString</Code> from the
#!  <Package>json</Package> package) into JSON.  The format of the JSON is
#!  governed entirely by the tool that will be used to visualize it, each of
#!  which has a different data format it expects.
#!  <P/>
#!  Those who wish to install new visualization tools for plots (as
#!  discussed in Chapter <Ref Chap="Chapter_extend"/>) will want
#!  to install a new function in this object corresponding to the new tool.
#!  If you plan to do so, consider the source code for the existing
#!  conversion functions, which makes use of two useful convenince methods,
#!  <Ref Func="JUPVIZFetchWithDefault"/> and
#!  <Ref Func="JUPVIZFetchIfPresent"/>.  Following those examples will
#!  help keep your code consistent with existing code and as concise as
#!  possible.
#DeclareGlobalVariable( "ConvertDataSeriesForTool" );

#! @Arguments various
#! @Returns one of two things, documented below
#! @Description
#!  If evaluated in a Jupyter Notebook, the result of this function, when
#!  rendered by that notebook, will run JavaScript code that generates and
#!  shows a graph in the output cell, not in the sense of coordinate axes,
#!  but in the sense of vertices and edges.  (To graph a function or data
#!  set on coordinate axes, use <Ref Func="Plot"/> instead.)
#!  <P/>
#!  If evaluated outside of a Jupyter Notebook, the result of this function
#!  is the name of a temporary file stored on disk in which HTML code for
#!  such a visualization has been written, and on which &GAP; has already
#!  invoked the user's default web browser.  The user should see the
#!  visualization appear in the browser immediately before the return value
#!  is shown.
#!  <P/>
#!  This function can take data in a wide variety of input formats.  Here is
#!  the current list of acceptable formats:
#!  <List>
#!    <Item>If <Code>V</Code> is a list and <Code>E</Code> is a list of
#!      pairs of items from <Code>V</Code> then <Code>PlotGraph(V,E)</Code>
#!      treats them as vertex and edge sets, respectively.</Item>
#!    <Item>If <Code>V</Code> is a list and <Code>R</Code> is a &GAP;
#!      function then <Code>PlotGraph(V,R)</Code> treats <Code>V</Code> as
#!      the vertex set and calls <Code>R(v1,v2)</Code> for every pair of
#!      vertices (in both orders) to test whether there is an edge
#!      between them.  It exepcts <Code>R</Code> to return
#!      boolean values.</Item>
#!    <Item>If <Code>E</Code> is a list of pairs then
#!      <Code>PlotGraph(E)</Code> treats <Code>E</Code> as a list of edges,
#!      inferring the vertex set to be any vertex mentioned in any of the
#!      edges.</Item>
#!    <Item>If <Code>M</Code> is a square matrix then
#!      <Code>PlotGraph(M)</Code> treats <Code>M</Code> as an adjacency
#!      matrix whose vertices are the integers 1 through <Math>n</Math>
#!      (the height of the matrix) and where two vertices are connected by
#!      an edge if and only if that matrix entry is positive.</Item>
#!    <Item>In any of the cases above, a new, last argument may be added
#!      that is a &GAP; record containing options for how to draw the graph,
#!      such as the tool to use.  For details on the supported options,
#!      see <Ref Var="ConvertGraphForTool"/>.</Item>
#!  </List>
#!  <P/>
#! @BeginLog
#! # Plot the subgroup lattice for a small group:
#! G := Group((1,2),(2,3));
#! PlotGraph( AllSubgroups(G), IsSubgroup );
#! @EndLog
#! <Alt Only="LaTeX">
#!     \begin{center}
#!         \includegraphics[width=4in]{subgroup-lattice.png}
#!     \end{center}
#! </Alt>
#! <Alt Only="HTML"><![CDATA[<img width="500" src="subgroup-lattice.png"/>]]></Alt>
#! <Alt Not="LaTeX HTML">Resulting image not shown here.</Alt>
#! @BeginLog
#! # Plot a random graph on 5 vertices:
#! # (The results change from one run to the next, of course.)
#! PlotGraph( RandomMat(5,5) );
#! @EndLog
#! <Alt Only="LaTeX">
#!     \begin{center}
#!         \includegraphics[width=2in]{random-graph.png}
#!     \end{center}
#! </Alt>
#! <Alt Only="HTML"><![CDATA[<img width="250" src="random-graph.png"/>]]></Alt>
#! <Alt Not="LaTeX HTML">Resulting image not shown here.</Alt>
DeclareGlobalFunction( "PlotGraph" );

#! @Description
#!  The <Package>JupyterViz</Package> Package has a high-level API and a
#!  low-level API.  The high-level API involves functions like
#!  <Code>PlotGraph</Code>, which take data in a variety of convenient
#!  formats, and produce visualizations from them.  The low-level API can
#!  be used to pass JSON data structures to JavaScript visualization tools
#!  in their own native formats for rendering.  The high-level API is built
#!  on the low-level API, using key functions to do the conversion.
#!  <P/>
#!  The conversion functions for graphs are stored in a global dictionary
#!  in this variable.  It is a &GAP; record mapping visualization tool
#!  names (such as cytoscape, a complete list of which appears in Section
#!  <Ref Sect="Section_purpose"/>) to conversion functions.  Only those
#!  tools that support graphing vertex and edge sets should be included.
#!  (For example, tools that specialize in drawing plots of data stored as
#!  <Math>(x,y)</Math> pairs are not relevant here.)
#!  <P/>
#!  Each conversion function must behave as follows.  It expects its input
#!  object to be a single graph, which will be a &GAP; record with three
#!  fields:
#!  <List>
#!    <Item><Code>vertices</Code> - a list of vertex names for the
#!      graph.  These can be any &GAP; data structure and they will be
#!      converted to strings with <Code>PrintString</Code>.  The one
#!      exception is that you can give each vertex a position by making it
#!      a record with three entries: <Code>name</Code>, <Code>x</Code>, and
#!      <Code>y</Code>.  In this way, you can manually lay out a
#!      graph.</Item>
#!    <Item><Code>edges</Code> - a list of pairs from the
#!      <Code>vertices</Code> list, each of which represents an edge</Item>
#!    <Item><Code>options</Code> - a &GAP; record containing any of the
#!      options documented in Section
#!      <Ref Sect="Section_graphopts"/>.</Item>
#!  </List>
#!  <P/>
#!  The output of the conversion function should be a &GAP; record amenable
#!  to conversion (using <Code>GapToJsonString</Code> from the
#!  <Package>json</Package> package) into JSON.  The format of the JSON is
#!  governed entirely by the tool that will be used to visualize it, each of
#!  which has a different data format it expects.
#!  <P/>
#!  Those who wish to install new visualization tools for graphs (as
#!  discussed in Chapter <Ref Chap="Chapter_extend"/>) will want
#!  to install a new function in this object corresponding to the new tool.
#!  If you plan to do so, consider the source code for the existing
#!  conversion functions, which makes use of two useful convenince methods,
#!  <Ref Func="JUPVIZFetchWithDefault"/> and
#!  <Ref Func="JUPVIZFetchIfPresent"/>.  Following those examples will
#!  help keep your code consistent with existing code and as concise as
#!  possible.
#DeclareGlobalVariable( "ConvertGraphForTool" );

#! @Description
#!  The <Package>JupyterViz</Package> Package can display visualizations in
#!  three different ways, and this global variable is used to switch among
#!  those ways.
#! @BeginLog
#! PlotDisplayMethod := PlotDisplayMethod_HTML;
#! @EndLog
#!  <P/>
#!  Users of this package almost never need to alter the value of this
#!  variable because a sensible default is chosen at package loading time.
#!  If the <Package>JupyterViz</Package> Package is loaded after the
#!  <Package>JupyterKernel</Package> Package, it notices the presence of
#!  that package and leverage its tools to set up support for plotting in a
#!  Jupyter environment.  Furthermore, it will initialize
#!  <Ref Var="PlotDisplayMethod"/> to
#!  <Ref Var="PlotDisplayMethod_Jupyter"/>, which is probably what the user
#!  wants.  Note that if one calls <Code>LoadPackage("JupyterViz");</Code>
#!  from a cell in a Jupyter notebook, this is the case that applies,
#!  because clearly in such a case, the <Package>JupyterKernel</Package>
#!  Package was already loaded.
#!  <P/>
#!  If the <Package>JupyterViz</Package> Package is loaded without the
#!  <Package>JupyterKernel</Package> Package already loaded, then it will
#!  initialize <Ref Var="PlotDisplayMethod"/> to
#!  <Ref Var="PlotDisplayMethod_HTML"/>, which is what the user probably
#!  wants if using &GAP; from a terminal, for example.  You may later
#!  assign <Ref Var="PlotDisplayMethod"/> to another value, but doing so
#!  has little purpose from the REPL.  You would need to first load the
#!  <Package>JupyterKernel</Package> Package, and even then, all that
#!  would be produced by this package would be data structures that would,
#!  if evaluated in a Jupyter notebook, produce visualizations.
#DeclareGlobalVariable( "PlotDisplayMethod" );

#! @Description
#!  This global constant can be assigned to the global variable
#!  <Ref Var="PlotDisplayMethod"/> as documented above.
#!  Doing so produces the following results.
#!  <List>
#!    <Item>Functions such as <Ref Func="Plot"/>, <Ref Func="PlotGraph"/>,
#!      and <Ref Func="CreateVisualization"/> will return objects of type
#!      <Code>JupyterRenderable</Code>, which is defined in the
#!      <Package>JupyterKernel</Package> Package.</Item>
#!    <Item>Such objects, when rendered in a Jupyter cell, will run a block
#!      of JavaScript contained within them, which will create the desired
#!      visualization.</Item>
#!    <Item>Such scripts tend to request additional information from &GAP;
#!      as they are running, by using calls to the JavaScript function
#!      <Code>Jupyter.kernel.execute</Code> defined in the notebook.
#!      Such calls are typically to fetch JavaScript libraries needed to
#!      create the requested visualization.</Item>
#!    <Item>Visualizations produced this way will not be visible if one
#!      later closes and then reopens the Jupyter notebook in which they
#!      are stored.  To see the visualizations again, one must re-evaluate
#!      the cells that created them, so that the required libraries are
#!      re-fetched from the &GAP; Jupyter kernel.</Item>
#!  </List>
#DeclareGlobalVariable( "PlotDisplayMethod_Jupyter" );

#! @Description
#!  This global constant can be assigned to the global variable
#!  <Ref Var="PlotDisplayMethod"/> as documented above.
#!  Doing so produces the following results.
#!  <List>
#!    <Item>Functions such as <Ref Func="Plot"/>, <Ref Func="PlotGraph"/>,
#!      and <Ref Func="CreateVisualization"/> will return objects of type
#!      <Code>JupyterRenderable</Code>, which is defined in the
#!      <Package>JupyterKernel</Package> Package.</Item>
#!    <Item>Such objects, when rendered in a Jupyter cell, will run a block
#!      of JavaScript contained within them, which will create the desired
#!      visualization.</Item>
#!    <Item>Such scripts will be entirely self-contained, and thus will not
#!      make any additional requests from the &GAP; Jupyter kernel.  This
#!      makes such objects larger because they must contain all the
#!      required JavaScript visualization libraries, rather than being able
#!      to request them as needed later.</Item>
#!    <Item>Visualizations produced this way will be visible even if one
#!      later closes and then reopens the Jupyter notebook in which they
#!      are stored, because all the code needed to create them is included
#!      in the output cell itself, and is re-run upon re-opening the
#!      notebook.</Item>
#!  </List>
#DeclareGlobalVariable( "PlotDisplayMethod_JupyterSimple" );

#! @Description
#!  This global constant can be assigned to the global variable
#!  <Ref Var="PlotDisplayMethod"/> as documented above.
#!  Doing so produces the following results.
#!  <List>
#!    <Item>Functions such as <Ref Func="Plot"/>, <Ref Func="PlotGraph"/>,
#!      and <Ref Func="CreateVisualization"/> will return no value, but
#!      will instead store HTML (and JavaScript) code for the
#!      visualization in a temporary file on the filesystem, then launch
#!      the operating system's default web browser to view that
#!      file.</Item>
#!    <Item>Such files are entirely self-contained, and require no &GAP;
#!      session to be running to continue viewing them.  They can be saved
#!      anywhere the user likes for later viewing, printing, or sharing
#!      without &GAP;.</Item>
#!    <Item>Visualizations produced this way will not be visible if one
#!      later closes and then reopens the Jupyter notebook in which they
#!      are stored.  To see the visualizations again, one must re-evaluate
#!      the cells that created them, so that the required libraries are
#!      re-fetched from the &GAP; Jupyter kernel.</Item>
#!  </List>
#DeclareGlobalVariable( "PlotDisplayMethod_HTML" );

#! @Section Low-Level Public API

#! @Arguments script[,returnHTML]
#! @Returns one of two things, documented below
#! @Description
#!  If run in a Jupyter Notebook, this function returns an object that, when
#!  rendered by that notebook, will run the JavaScript code given in
#!  <Arg>script</Arg>.
#!  <P/>
#!  If run outside of a Jupyter Notebook, this function creates an HTML
#!  page containing the given <Arg>script</Arg>, an HTML element on which
#!  that script can act, and the RequireJS library for importing other
#!  script tools.  It then opens the page in the system default web browser
#!  (thus running the script) and returns the path to the temporary file in
#!  which the script is stored.
#!  <P/>
#!  In this second case only, the optional second parameter (which defaults
#!  to false) can be set to true if the caller does not wish the function to
#!  open a web browser, but just wants the HTML content that would have been
#!  displayed in such a browser returned as a string instead.
#!  <P/>
#!  When the given code is run, the varible <Code>element</Code> will be
#!  defined in its environment, and will contain either the output element
#!  in the Jupyter notebook corresponding to the code that was just
#!  evaluated or, in the case outside of Jupyter, the HTML element mentioned
#!  above.  The script is free to write to that element in both cases.
DeclareGlobalFunction( "RunJavaScript" );

#! @Arguments filename
#! @Returns the string contents of the file whose name is given
#! @Description
#!  Interprets the given <Arg>filename</Arg> relative to the
#!  <File>lib/js/</File> path in the <Package>JupyterViz</Package>
#!  package's installation folder, because that is where this package
#!  stores its JavaScript libraries.  A <File>.js</File> extension will be
#!  added to <Arg>filename</Arg> iff needed.  A <File>.min.js</File>
#!  extension will be added iff such a file exists, to prioritize minified
#!  versions of files.
#!  <P/>
#!  If the file has been loaded before in this &GAP; session, it will not be
#!  reloaded, but will be returned from a cache in memory, for efficiency.
#!  <P/>
#!  If no such file exists, returns <Keyword>fail</Keyword> and caches
#!  nothing.
DeclareGlobalFunction( "LoadJavaScriptFile" );

#! @Arguments toolName,script
#! @Returns boolean indicating success (true) or failure (false)
#! @Description
#!  This function permits extending, at runtime, the set of JavaScript
#!  visualization tools beyond those that are built into the
#!  <Package>JupyterViz</Package> package.
#!  <P/>
#!  The first argument must be the name of the visualization tool (a string,
#!  which you will later use in the <Code>tool</Code> field when calling
#!  <Ref Func="CreateVisualization"/>).  The second must be a string of
#!  JavaScript code that installs into
#!  <Code>window.VisualizationTools.TOOL_NAME_HERE</Code> the function for
#!  creating visualizations using that tool.  It can also define other
#!  helper functions or make calls to <Code>window.requirejs.config</Code>.
#!  For examples of how to write such JavaScript code, see the chapter on
#!  extending this package in its manual.
#!  <P/>
#!  This function returns false and does nothing if a tool of that name has
#!  already been installed.  Otherwise, it installs the tool and returns
#!  true.
#!  <P/>
#!  There is also a convenience method that calls this one on your behalf;
#!  see <Ref Func="InstallVisualizationToolFromTemplate"/>.
DeclareGlobalFunction( "InstallVisualizationTool" );

#! @Arguments toolName,functionBody[,CDNURL]
#! @Returns boolean indicating success (true) or failure (false)
#! @Description
#!  This function is a convenience function that makes it easier to use
#!  <Ref Func="InstallVisualizationTool"/>; see the documentation for that
#!  function, then read on below for how this function makes it easier.
#!  <P/>
#!  Most visualization tools do two things:  First, they install a CDN URL
#!  into <Code>window.requirejs.config</Code> for some external JavaScript
#!  library that must be loaded in the client to support the given type of
#!  visualization.  Second, they install a function as
#!  <Code>window.VisualizationTools.TOOL_NAME_HERE</Code> accepting
#!  parameters <Code>element</Code>, <Code>json</Code>, and
#!  <Code>callback</Code>, and building the desired visualization inside
#!  the given DOM element.  Such code often begins with a call to
#!  <Code>require(['...'],function(library}{/*...*/}))</Code>, but not
#!  always.
#!  <P/>
#!  This function will write for you the boiler plate code for calling
#!  <Code>window.requirejs.config</Code> and the declaration and
#!  installation of a function into
#!  <Code>window.VisualizationTools.TOOL_NAME_HERE</Code>.  You provide the
#!  function body and optionally the CDN URL.  (If you provide no CDN URL,
#!  then no external CDN will be installed into <Code>requirejs</Code>.)
DeclareGlobalFunction( "InstallVisualizationToolFromTemplate" );

#! @Arguments data[,code]
#! @Returns one of two things, documented below
#! @Description
#!  If run in a Jupyter Notebook, this function returns an object that, when
#!  rendered by that notebook, will produce the visualization specified by
#!  <Arg>data</Arg> in the corresponding output cell, and will also run any
#!  given <Arg>code</Arg> on that visualization.
#!  <P/>
#!  If run outside of a Jupyter Notebook, this function creates an HTML
#!  page containing the visualization specified by <Arg>data</Arg> and then
#!  opens the page in the system default web browser.  It will also run any
#!  given <Arg>code</Arg> as soon as the page opens.
#! @Description
#!  The <Arg>data</Arg> must be a record that will be converted to JSON
#!  using &GAP;'s <Package>json</Package> package.
#!  <P/>
#!  The second argument is optional, a string containing JavaScript
#!  <Arg>code</Arg> to run once the visualization has been created.  When
#!  that code is run, the variables <Code>element</Code> and
#!  <Code>visualization</Code> will be in its environment, the former
#!  holding the output element in the notebook containing the
#!  visualization, and the latter holding the visualization element itself.
#!  <P/>
#!  The <Arg>data</Arg> should have the following attributes.
#!   * <Code>tool</Code> (required) - the name of the visualization tool to
#!     use.  Currently supported tools are listed in Section
#!     <Ref Sect="Section_term"/> and links to their documentation are given
#!     in Section <Ref Sect="Section_tooldocs"/>.
#!   * <Code>data</Code> (required) - subobject containing all options
#!     specific to the content of the visualization, often passed intact to
#!     the external JavaScript visualization library.  You should prepare
#!     this data in the format required by the library specified in the
#!     <Code>tool</Code> field, following the documentation for that
#!     library, linked to in Section <Ref Sect="Section_tooldocs"/>.
#!   * <Code>width</Code> (optional) - width to set on the output element
#!     being created
#!   * <Code>height</Code> (optional) - similar, but height
#! @BeginLog
#! CreateVisualization( rec(
#!     tool := "html",
#!     data := rec( html := "I am <i>SO</i> excited about this." )
#! ), "console.log( 'Visualization created.' );" );
#! @EndLog
DeclareGlobalFunction( "CreateVisualization" );

#! @Section Internal methods

#! Using the convention common to &GAP; packages, we prefix all methods not
#! intended for public use with a sequence of characters that indicate our
#! particular package.  In this case, we use the <Code>JUPVIZ</Code> prefix.
#! This is a sort of "poor man's namespacing."
#! <P/>
#! **None of these methods should need to be called by a client of this
#! package.  We provide this documentation here for completeness, not out of
#! necessity.**

#! @Arguments filename
#! @Returns a JavaScript filename to an absolute path in the package dir
#! @Description
#!  Given a relative <Arg>filename</Arg>, convert it into an absolute
#!  filename by prepending the path to the <File>lib/js/</File> folder
#!  within the <Package>JupyterViz</Package> package's installation
#!  folder.  This is used by functions that need to find JavaScript files
#!  stored there.
#!  <P/>
#!  A <File>.js</File> extension is appended if none is included in the
#!  given <Arg>filename</Arg>.
DeclareGlobalFunction( "JUPVIZAbsoluteJavaScriptFilename" );

#! @Description
#!  A cache of the contents of any JavaScript files that have been loaded
#!  from this package's folder.  The existence of this cache means needing
#!  to go to the filesystem for these files only once per &GAP; session.
#!  This cache is used by <Ref Func="LoadJavaScriptFile"/>.
#DeclareGlobalVariable( "JUPVIZLoadedJavaScriptCache" );

#! @Arguments filename, dictionary
#! @Returns a string containing the contents of the given template file, filled in using the given dictionary
#! @Description
#!  A template file is one containing identifiers that begin with a dollar
#!  sign (<Code>\$</Code>).  For example, <Code>\$one</Code> and
#!  <Code>\$two</Code> are both identifiers.  One "fills in" the template by
#!  replacing such identifiers with whatever text the caller associates with
#!  them.
#!  <P/>
#!  This function loads the file specified by <Arg>filename</Arg> by passing
#!  that argument directly to <Ref Func="LoadJavaScriptFile"/>.  If no such
#!  file exists, returns <Keyword>fail</Keyword>.  Otherwise, it proceed as
#!  follows.
#!  <P/>
#!  For each key-value pair in the given <Arg>dictionary</Arg>, prefix a
#!  <Code>\$</Code> onto the key, suffix a newline character onto the value,
#!  and then replace all occurrences of the new key with the new value.
#!  The resulting string is the result.
#!  <P/>
#!  The newline character is included so that if any of the values in the
#!  <Arg>dictionary</Arg> contains single-line JavaScript comment characters
#!  (<Code>//</Code>) then they will not inadvertently affect later code in
#!  the template.
DeclareGlobalFunction( "JUPVIZFillInJavaScriptTemplate" );

#! @Arguments filename, dictionary[, returnHTML]
#! @Returns the composition of <Ref Func="RunJavaScript"/> with <Ref Func="JUPVIZFillInJavaScriptTemplate"/>
#! @Description
#!  This function is quite simple, and is just a convenience function.
#!  The optional third argument is passed on to RunJavaScript internally.
DeclareGlobalFunction( "JUPVIZRunJavaScriptFromTemplate" );

#! @Arguments jsCode[, returnHTML]
#! @Returns an object that, if rendered in a Jupyter notebook, will run <Arg>jsCode</Arg> as JavaScript after <Code>runGAP</Code> has been defined
#! @Description
#!  There is a JavaScript function called <Code>runGAP</Code>, defined in
#!  the <File>using-runGAP.js</File> file distributed with this package.
#!  That function makes it easy to make callbacks from JavaScript in a
#!  Jupyter notebook to the &GAP; kernel underneath that notebook.  This
#!  &GAP; function runs the given <Arg>jsCode</Arg> in the notebook, but
#!  only after ensuring that <Code>runGAP</Code> is defined globally in that
#!  notebook, so that <Arg>jsCode</Arg> can call <Code>runGAP</Code> as
#!  needed.
#!  <P/>
#!  The optional third argument is passed on to RunJavaScript internally.
#!  <P/>
#!  An example use, from JavaScript, of the <Code>runGAP</Code> function
#!  appears at the end of Section <Ref Sect="Section_plainhtml"/>.
DeclareGlobalFunction( "JUPVIZRunJavaScriptUsingRunGAP" );

#! @Arguments libraries, jsCode[, returnHTML]
#! @Returns one of two things, documented below
#! @Description
#!  If run in a Jupyter Notebook, this function returns an object that, when
#!  rendered by that notebook, will run <Arg>jsCode</Arg> as JavaScript
#!  after all <Arg>libraries</Arg> have been loaded (which typically happens
#!  asynchronously).
#!  <P/>
#!  If run outside of a Jupyter Notebook, this function loads all the code
#!  for the given <Arg>libraries</Arg> from disk and concatenates them (with
#!  checks to be sure no library is loaded twice) followed by
#!  <Arg>jsCode</Arg>.  It then calls <Ref Func="RunJavaScript"/> on the
#!  result, to form a web page and display it to the user.
#!  <P/>
#!  There are a set of JavaScript libraries stored in the
#!  <File>lib/js/</File> subfolder of this package's installation folder.
#!  Neither the Jupyter notebook nor the temporary HTML files created from
#!  the command line know, by default, about any of those libraries.  Thus
#!  this function is necessary so that <Arg>jsCode</Arg> can assume the
#!  existence of the tools it needs to do its job.
#!  <P/>
#!  If the first parameter is given as a string instead of a list of
#!  strings, it is treated as a list of just one string.
#!  <P/>
#!  The optional third argument is passed on to RunJavaScript internally.
#! @BeginLog
#! JUPVIZRunJavaScriptUsingLibraries( [ "mylib.js" ],
#!     "alert( 'My Lib defines foo to be: ' + window.foo );" );
#! # Equivalently:
#! JUPVIZRunJavaScriptUsingLibraries( "mylib.js",
#!     "alert( 'My Lib defines foo to be: ' + window.foo );" );
#! @EndLog
DeclareGlobalFunction( "JUPVIZRunJavaScriptUsingLibraries" );

#! @Arguments series
#! @Returns a record with the appropriate fields (<Code>x</Code>, <Code>y</Code>, <Code>options</Code>) that can be passed to one of the functions in <Ref Var="ConvertDataSeriesForTool"/>
#! @Description
#!  This function is called by <Ref Func="Plot"/> to convert any of the wide
#!  variety of inputs that <Ref Func="Plot"/> might receive into a single
#!  internal format.  Then that internal format can be converted to the JSON
#!  format needed by any of the visualization tools supported by this
#!  package.
#!  <P/>
#!  See the documentation for <Ref Var="ConvertDataSeriesForTool"/> for
#!  more information on how that latter conversion takes place, and the
#!  format it expects.
DeclareGlobalFunction( "JUPVIZMakePlotDataSeries" );

#! @Arguments various
#! @Returns a record with the appropriate fields (<Code>vertices</Code>, <Code>edges</Code>, <Code>options</Code>) that can be passed to one of the functions in <Ref Var="ConvertGraphForTool"/>
#! @Description
#!  This function is called by <Ref Func="PlotGraph"/> to convert any of
#!  the wide variety of inputs that <Ref Func="PlotGraph"/> might receive
#!  into a single internal format.  Then that internal format can be
#!  converted to the JSON format needed by any of the visualization tools
#!  supported by this package.
#!  <P/>
#!  See the documentation for <Ref Var="ConvertGraphForTool"/> for
#!  more information on how that latter conversion takes place, and the
#!  format it expects.
DeclareGlobalFunction( "JUPVIZMakePlotGraphRecord" );

#! @Arguments series1, series2, series3...
#! @Returns a <Code>JupyterRenderable</Code> object ready to be displayed in the Jupyter Notebook
#! @Description
#!  Because the <Ref Func="Plot"/> function can take a single data series or
#!  many data series as input, it detects which it received, then passes the
#!  resulting data series (as an array containing one or more series) to
#!  this function for collecting into a single plot.
#!  <P/>
#!  It is not expected that clients of this package will need to call this
#!  internal function.
DeclareGlobalFunction( "JUPVIZPlotDataSeriesList" );

#! @Arguments record, keychain, default
#! @Returns the result of looking up the chain of keys in the given record
#! @Description
#!  In nested records, such as <Code>myRec:=rec(a:=rec(b:=5))</Code>, it
#!  is common to write code such as <Code>myRec.a.b</Code> to access the
#!  internal values.  However when records are passed as parameters, and may
#!  not contain every key (as in the case when some default values should be
#!  filled in automatically), code like <Code>myRec.a.b</Code> could cause
#!  an error.  Thus we wish to first check before indexing a record that the
#!  key we're looking up exists.  If not, we wish to return the value given
#!  as the <Code>default</Code> instead.
#!  <P/>
#!  This function accepts a <Code>record</Code> (which may have other
#!  records inside it as values), an array of strings that describe a
#!  chain of keys to follow inward (<Code>["a","b"]</Code> in the example
#!  just given), and a <Code>default</Code> value to return if any of the
#!  keys do not exist.
#!  <P/>
#!  It is not expected that clients of this package will need to call this
#!  internal function.  It is used primarily to implement the
#!  <Ref Func="JUPVIZFetchWithDefault"/> function, which is useful to those
#!  who wish to extend the <Ref Var="ConvertDataSeriesForTool"/> and
#!  <Ref Var="ConvertGraphForTool"/> objects.
#!  <P/>
#! @BeginLog
#! myRec := rec( height := 50, width := 50, title := rec(
#!   text := "GAP", fontSize := 20
#! ) );
#! JUPVIZRecordKeychainLookup( myRec, [ "height" ], 10 );                # = 50
#! JUPVIZRecordKeychainLookup( myRec, [ "width" ], 10 );                 # = 50
#! JUPVIZRecordKeychainLookup( myRec, [ "depth" ], 10 );                 # = 10
#! JUPVIZRecordKeychainLookup( myRec, [ "title", "text" ], "Title" );    # = "GAP"
#! JUPVIZRecordKeychainLookup( myRec, [ "title", "color" ], "black" );   # = "black"
#! JUPVIZRecordKeychainLookup( myRec, [ "one", "two", "three" ], fail ); # = fail
#! @EndLog
DeclareGlobalFunction( "JUPVIZRecordKeychainLookup" );

#! @Arguments records, keychain, default
#! @Returns the result of looking up the chain of keys in each of the given records until a lookup succeeds
#! @Description
#!  This function is extremely similar to
#!  <Ref Func="JUPVIZRecordKeychainLookup"/> with the following difference:
#!  The first parameter is a list of records, and
#!  <Ref Func="JUPVIZRecordKeychainLookup"/> is called on each in succession
#!  with the same <Code>keychain</Code>.  If any of the lookups succeeds,
#!  then its value is returned and no further searching through the list is
#!  done.  If all of the lookups fail, the <Code>default</Code> is returned.
#!  <P/>
#!  It is not expected that clients of this package will need to call this
#!  internal function.  It is used primarily to implement the
#!  <Ref Func="JUPVIZFetchWithDefault"/> function, which is useful to those
#!  who wish to extend the <Ref Var="ConvertDataSeriesForTool"/> and
#!  <Ref Var="ConvertGraphForTool"/> objects.
#!  <P/>
#! @BeginLog
#! myRecs := [
#!   rec( height := 50, width := 50, title := rec(
#!     text := "GAP", fontSize := 20
#!   ) ),
#!   rec( width := 10, depth := 10, color := "blue" )
#! ];
#! JUPVIZRecordsKeychainLookup( myRecs, [ "height" ], 0 );              # = 50
#! JUPVIZRecordsKeychainLookup( myRecs, [ "width" ], 0 );               # = 50
#! JUPVIZRecordsKeychainLookup( myRecs, [ "depth" ], 0 );               # = 10
#! JUPVIZRecordsKeychainLookup( myRecs, [ "title", "text" ], "Title" ); # = "GAP"
#! JUPVIZRecordsKeychainLookup( myRecs, [ "color" ], "" );              # = "blue"
#! JUPVIZRecordsKeychainLookup( myRecs, [ "flavor" ], fail );           # = fail
#! @EndLog
DeclareGlobalFunction( "JUPVIZRecordsKeychainLookup" );

#! @Arguments record, others, chain, default, action
#! @Returns nothing
#! @Description
#!  This function is designed to make it easier to write new entries in the
#!  <Ref Var="ConvertDataSeriesForTool"/> and
#!  <Ref Var="ConvertGraphForTool"/> functions.
#!  Those functions are often processing a list of records (here called
#!  <Code>others</Code>) sometimes with one record the most important one
#!  (here called <Code>record</Code>) and looking up a <Code>chain</Code> of
#!  keys (using <Code>default</Code> just as in
#!  <Ref Func="JUPVIZRecordKeychainLookup"/>) and then taking some
#!  <Code>action</Code> based on the result.
#!  This function just allows all of that to be done with a single call.
#!  <P/>
#!  Specifically, it considers the array of records formed by
#!  <Code>Concatenation([record],others)</Code> and calls
#!  <Ref Func="JUPVIZRecordsKeychainLookup"/> on it with the given
#!  <Code>chain</Code> and <Code>default</Code>.  (If the <Code>chain</Code>
#!  is a string, it is automatically converted to a length-one list with
#!  the string inside.)  Whatever the result, the function
#!  <Code>action</Code> is called on it, even if it is the default.
#!  <P/>
#! @BeginLog
#! # Trivial examples:
#! myRec := rec( a := 5 );
#! myRecs := [ rec( b := 3 ), rec( a := 6 ) ];
#! f := function ( x ) Print( x, "\n" ); end;
#! JUPVIZFetchWithDefault( myRec, myRecs, "a", 0, f );       # prints 5
#! JUPVIZFetchWithDefault( myRec, myRecs, "b", 0, f );       # prints 3
#! JUPVIZFetchWithDefault( myRec, myRecs, "c", 0, f );       # prints 0
#! JUPVIZFetchWithDefault( myRec, myRecs, ["a","b"], 0, f ); # prints 0
#! # Useful example:
#! JUPVIZFetchWithDefault( primaryRecord, secondaryRecordsList,
#!   [ "options", "height" ], 400,
#!   function ( h ) myGraphJSON.height := h; end
#! );
#! @EndLog
#!  <P/>
#!  See also <Ref Func="JUPVIZFetchIfPresent"/>.
DeclareGlobalFunction( "JUPVIZFetchWithDefault" );

#! @Arguments record, others, chain, action
#! @Returns nothing
#! @Description
#!  This function is extremely similar to
#!  <Ref Func="JUPVIZFetchWithDefault"/> with the following exception:
#!  No default value is provided, and thus if the lookup fails for all the
#!  records (including <Code>record</Code> and everything in
#!  <Code>others</Code>) then the <Code>action</Code> is not called.
#!  <P/>
#!  Examples:
#! @BeginLog
#! myRec := rec( a := 5 );
#! myRecs := [ rec( b := 3 ), rec( a := 6 ) ];
#! f := function ( x ) Print( x, "\n" ); end;
#! JUPVIZFetchIfPresent( myRec, myRecs, "a", 0, f );       # prints 5
#! JUPVIZFetchIfPresent( myRec, myRecs, "b", 0, f );       # prints 3
#! JUPVIZFetchIfPresent( myRec, myRecs, "c", 0, f );       # does nothing
#! JUPVIZFetchIfPresent( myRec, myRecs, ["a","b"], 0, f ); # does nothing
#! @EndLog
DeclareGlobalFunction( "JUPVIZFetchIfPresent" );

#! @Section Representation wrapper

#! This code is documented for completeness's sake only.  It is not needed
#! for clients of this package.  Package maintainers may be interested in it
#! in the future.
#! <P/>
#! The <Package>JupyterKernel</Package> package defines a method
#! <Code>JupyterRender</Code> that determines how &GAP; data will be shown
#! to the user in the Jupyter notebook interface.  When there is no method
#! implemented for a specific data type, the fallback method uses the
#! built-in &GAP; method <Code>ViewString</Code>.
#! <P/>
#! This presents a problem, because we are often transmitting string data
#! (the contents of JavaScript files) from the &GAP; kernel to the notebook,
#! and <Code>ViewString</Code> is not careful about how it escapes
#! characters such as quotation marks, which can seriously mangle code.
#! Thus we must define our own type and <Code>JupyterRender</Code> method
#! for that type, to prevent the use of <Code>ViewString</Code>.
#! <P/>
#! The declarations documented below do just that.  In the event that
#! <Code>ViewString</Code> were upgraded to more useful behavior, this
#! workaround could probably be removed.  Note that it is used explicitly
#! in the <File>using-library.js</File> file in this package.
#! <P/>
#! If this package is loaded without the <Package>JupyterKernel</Package>
#! package having already been loaded, then the following functions and
#! tools are not defined, because their definitions rely on global data
#! made available by the <Package>JupyterKernel</Package> package.

#! @Description
#!  The type we create is called <Code>FileContents</Code>, because that is
#!  our purpose for it (to preserve, unaltered, the contents of a text
#!  file).
DeclareCategory( "JUPVIZIsFileContents", IsObject );

#! @Description
#!  The representation for the <Code>FileContents</Code> type
DeclareRepresentation( "JUPVIZIsFileContentsRep",
    IsComponentObjectRep and JUPVIZIsFileContents, [ "content" ] );

#! @Description
#!  A constructor for <Code>FileContents</Code> objects
DeclareOperation( "JUPVIZFileContents", [ IsString ] );

#! Elsewhere, the <Package>JupyterViz</Package> package also installs a
#! <Code>JupyterRender</Code> method for <Code>FileContents</Code> objects
#! that just returns their text content untouched.

#E  main.gd  . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here

[ Dauer der Verarbeitung: 0.29 Sekunden  (vorverarbeitet)  ]