From f2278c4ebe48c174e43845ccfd838fffc3376514 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Thu, 10 Aug 2023 03:01:21 +0000 Subject: CTAN sync 202308100301 --- .../metapost/contrib/macros/wordcloud/README.md | 57 +++ .../metapost/contrib/macros/wordcloud/doc/ctan.bib | 99 +++++ .../contrib/macros/wordcloud/doc/doc-wc.pdf | Bin 0 -> 6760 bytes .../metapost/contrib/macros/wordcloud/doc/fond.pdf | Bin 0 -> 1309 bytes .../macros/wordcloud/doc/wordcloud-doc-en.pdf | Bin 0 -> 118155 bytes .../macros/wordcloud/doc/wordcloud-doc-en.tex | 429 +++++++++++++++++++ .../macros/wordcloud/doc/wordcloud-preamble.tex | 214 ++++++++++ .../contrib/macros/wordcloud/metapost/wordcloud.mp | 467 +++++++++++++++++++++ .../contrib/macros/wordcloud/scripts/wordcloud.lua | 224 ++++++++++ .../contrib/macros/wordcloud/tex/wordcloud.sty | 149 +++++++ 10 files changed, 1639 insertions(+) create mode 100644 graphics/metapost/contrib/macros/wordcloud/README.md create mode 100644 graphics/metapost/contrib/macros/wordcloud/doc/ctan.bib create mode 100644 graphics/metapost/contrib/macros/wordcloud/doc/doc-wc.pdf create mode 100644 graphics/metapost/contrib/macros/wordcloud/doc/fond.pdf create mode 100644 graphics/metapost/contrib/macros/wordcloud/doc/wordcloud-doc-en.pdf create mode 100644 graphics/metapost/contrib/macros/wordcloud/doc/wordcloud-doc-en.tex create mode 100644 graphics/metapost/contrib/macros/wordcloud/doc/wordcloud-preamble.tex create mode 100644 graphics/metapost/contrib/macros/wordcloud/metapost/wordcloud.mp create mode 100644 graphics/metapost/contrib/macros/wordcloud/scripts/wordcloud.lua create mode 100644 graphics/metapost/contrib/macros/wordcloud/tex/wordcloud.sty (limited to 'graphics') diff --git a/graphics/metapost/contrib/macros/wordcloud/README.md b/graphics/metapost/contrib/macros/wordcloud/README.md new file mode 100644 index 0000000000..a4db68ebf4 --- /dev/null +++ b/graphics/metapost/contrib/macros/wordcloud/README.md @@ -0,0 +1,57 @@ +# wordcloud + +This package (MetaPost, Lua, and LaTeX) allows you to draw wordclouds. + +_This package is in beta version, do not hesitate to report bugs, as well as +requests for improvement. There is lots to do!_ + +## Github + +To allow for easier feedback and bug reporting, this repository has a mirror +repository on github: +[https://github.com/chupinmaxime/wordcloud](https://github.com/chupinmaxime/wordcloud) + +## Installation + +MPchess is on the [ctan](ctan.org) and can be installed via the package manager of your +distribution [https://www.ctan.org/pkg/wordcloud](https://www.ctan.org/pkg/wordcloud). + +### With TeX live under Linux or MacOS + +To install `wordcloud` with TeX live, you will have to create the directory `texmf` +directory in your home. +```bash +user $> mkdir ~/texmf +``` + +Then, you will have to place the .mp files in the +`~/texmf/tex/metapost/wordcloud/`. + +`wordcloud` consists of 3 files: +* `wordcloud.mp` (MetaPost) that should be in `~/texmf/metapost/wordcloud/`; +* `wordcloud.tex` (LaTeX) that should be in `~/texmf/tex/latex/wordcloud/`; +* `wordcloud.lua` (Lua) that should be in `~/texmf/scripts/wordcloud/`. + +### With MikTEX and Windows + +These two systems are unknown to the author of MPchess, so we refer to their +documentation to add local packages: +[http://docs.miktex.org/manual/localadditions.html](http://docs.miktex.org/manual/localadditions.html) + +## Dependencies + +* metapost-colorbrewer +* latexmp +* luamplib +* xcolor +## Documentation + +* [English documentation](doc/wordcloud-doc-en.pdf) + +## Contact + +Maxime Chupin, `notezik(at)gmail.com` + +## Licenses + +This projet is under LATEX Project Public License 1.3c. \ No newline at end of file diff --git a/graphics/metapost/contrib/macros/wordcloud/doc/ctan.bib b/graphics/metapost/contrib/macros/wordcloud/doc/ctan.bib new file mode 100644 index 0000000000..fb435f0a3d --- /dev/null +++ b/graphics/metapost/contrib/macros/wordcloud/doc/ctan.bib @@ -0,0 +1,99 @@ + +@manual{ctan-metapost, + title = {The \texttt{metapost} package}, + subtitle = {A development of Metafont for creating graphics}, + author = {{The MetaPost Team} and John Hobby}, + date = {2021-08-26}, + license = {lgpl}, + url = {https://ctan.org/pkg/metapost}, + annotation = {MetaPost uses a language based on that of + to produce precise + technical illustrations. Its output is scalable PostScript or + SVG, rather than the bitmaps Metafont creates.}, +} + + + +@manual{ctan-metapost-colorbrewer, + title = {The \texttt{metapost-colorbrewer} package}, + subtitle = {An implementation of the colorbrewer2.org colours for MetaPost}, + author = {Toby Thurston}, + date = {2018-09-25}, + version = {}, + license = {gpl3+}, + mirror = {https://mirror.ctan.org/graphics/metapost/contrib/macros/metapost-colorbrewer}, + url = {https://ctan.org/pkg/metapost-colorbrewer}, +} + +@manual{ctan-latexmp, + title = {The \texttt{latexMP} package}, + subtitle = {Interface for \LaTeX{}-based typesetting in MetaPost}, + author = {Jens-Uwe Morawski}, + date = {2020-06-21}, + version = {1.2.1}, + license = {pd}, + mirror = {https://mirror.ctan.org/graphics/metapost/contrib/macros/latexmp}, + url = {https://ctan.org/pkg/latexmp}, + annotation = {The MetaPost package latexMP implements a user-friendly + interface to access \LaTeX{}-based typesetting capabilities in + MetaPost. The text to be typeset is given as string. This + allows even dynamic text elements, for example counters, to be + used in labels. Compared to other implementations it is much + more flexible, since it can be used as direct replacement for + , and much faster, compared for example to the + solution provided by .}, +} + +@manual{ctan-lualatex-doc, + title = {The \texttt{lualatex-doc} package}, + subtitle = {A guide to use of \LaTeX{} with LuaTeX}, + author = {Manuel Pégourié-Gonnard}, + date = {2016-06-24}, + version = {}, + license = {fdl}, + mirror = {https://mirror.ctan.org/info/luatex/lualatex-doc}, + url = {https://ctan.org/pkg/lualatex-doc}, +} + + +@manual{ctan-luamplib, + title = {The \texttt{luamplib} package}, + subtitle = {Use LuaTeX’s built-in MetaPost interpreter}, + author = {Hans Hagen and Taco Hoekwater and Élie Roux and Manuel Pégourié-Gonnard and Philipp Gesang and Dohyun Kim}, + date = {2022-01-12}, + version = {2.23.0}, + license = {gpl2}, + mirror = {https://mirror.ctan.org/macros/luatex/generic/luamplib}, + url = {https://ctan.org/pkg/luamplib}, +} + +@manual{ctan-xcolor, + title = {The \texttt{xcolor} package}, + subtitle = {Driver-independent color extensions for \LaTeX{} and pdfLaTeX}, + author = {Uwe Kern and {The \LaTeX{} Project Team}}, + date = {2022-06-12}, + version = {2.14}, + license = {lppl1.3c}, + mirror = {https://mirror.ctan.org/macros/latex/contrib/xcolor}, + url = {https://ctan.org/pkg/xcolor}, + annotation = {The package starts from the basic facilities of the + package, and + provides easy driver-independent access to several kinds of + color tints, shades, tones, and mixes of arbitrary colors. It + allows a user to select a document-wide target color model and + offers complete tools for conversion between eight color models. + Additionally, there is a command for alternating row colors plus + repeated non-aligned material (like horizontal lines) in tables. + Colors can be mixed like \textbackslash{}color{red!30!green!40!blue}.}, +} + +@manual{ctan-graphicx, + title = {The \texttt{graphicx} package}, + subtitle = {Enhanced support for graphics}, + author = {David Carlisle and {The \LaTeX{} Project Team}}, + date = {2021-11-12}, + version = {1.2d}, + license = {lppl1.3c}, + mirror = {https://mirror.ctan.org/macros/latex/required/graphics}, + url = {https://ctan.org/pkg/graphicx}, +} \ No newline at end of file diff --git a/graphics/metapost/contrib/macros/wordcloud/doc/doc-wc.pdf b/graphics/metapost/contrib/macros/wordcloud/doc/doc-wc.pdf new file mode 100644 index 0000000000..682af3842a Binary files /dev/null and b/graphics/metapost/contrib/macros/wordcloud/doc/doc-wc.pdf differ diff --git a/graphics/metapost/contrib/macros/wordcloud/doc/fond.pdf b/graphics/metapost/contrib/macros/wordcloud/doc/fond.pdf new file mode 100644 index 0000000000..22218152cc Binary files /dev/null and b/graphics/metapost/contrib/macros/wordcloud/doc/fond.pdf differ diff --git a/graphics/metapost/contrib/macros/wordcloud/doc/wordcloud-doc-en.pdf b/graphics/metapost/contrib/macros/wordcloud/doc/wordcloud-doc-en.pdf new file mode 100644 index 0000000000..38656d0d9b Binary files /dev/null and b/graphics/metapost/contrib/macros/wordcloud/doc/wordcloud-doc-en.pdf differ diff --git a/graphics/metapost/contrib/macros/wordcloud/doc/wordcloud-doc-en.tex b/graphics/metapost/contrib/macros/wordcloud/doc/wordcloud-doc-en.tex new file mode 100644 index 0000000000..e3ef5b24ae --- /dev/null +++ b/graphics/metapost/contrib/macros/wordcloud/doc/wordcloud-doc-en.tex @@ -0,0 +1,429 @@ + +% LTeX: language=en + +% wordcloud : draw word cloud with MetaPost and Lua +% +% Originally written by Maxime Chupin , +% 2023. +% +% Distributed under the terms of the GNU free documentation licence: +% http://www.gnu.org/licenses/fdl.html +% without any invariant section or cover text. + +\documentclass[english]{ltxdoc} + +\input{wordcloud-preamble} +\usepackage{wordcloud} +\usepackage[english]{babel} + +\makeindex[title=Command Index, columns=2] + + + +%\lstset{moredelim=*[s][\color{red}\rmfamily\itshape]{<}{>}} +%\lstset{moredelim=*[s][\color{blue}\rmfamily\itshape]{<<}{>>}} + +\begin{document} + +\title{{Wordcloud} : drawing wordclouds with \hologo{METAPOST} and Lua} +\author{Maxime Chupin, \url{notezik@gmail.com}} +\date{\today} + +%% === Page de garde =================================================== +\thispagestyle{empty} +\begin{tikzpicture}[remember picture, overlay] + \node[below right, shift={(-4pt,4pt)}] at (current page.north west) {% + \includegraphics{fond.pdf}% + }; +\end{tikzpicture}% + +\noindent +{\Huge \texttt{wordcloud}}\par\bigskip +\noindent +{\Large drawing wordclouds \\[0.2cm]with \hologo{METAPOST} and Lua}\\[3cm] +\parbox{0.6\textwidth}{ + \wordcloud[scale=2,rotate=0,margin=0.5pt,usecolor]{(Wordcloud,10);(\\hologo{METAPOST},6);(\\LaTeX,7);(Lua,4);(algorithm,3);(code,2);(mathematics,2);(CTAN,2);(mplib,4);(\\hologo{LuaTeX},4);(latexmp,3);(graphism,2)} +}\hfill +\parbox{0.5\textwidth}{\Large\raggedleft + \textbf{Contributor}\\ + Maxime \textsc{Chupin}\\ + \url{notezik@gmail.com} +} +\vfill +\begin{center} + Version 0.1, 2023, August, 9th \\ + \url{https://plmlab.math.cnrs.fr/mchupin/wordcloud} +\end{center} +%% == Page de garde ==================================================== +\newpage + +%\maketitle + +\begin{abstract} + These \hologo{METAPOST} and \hologo{LuaLaTeX} packages allows drawing + wordclouds from a list of words and weights. The algorithm is implemented with + \hologo{METAPOST} whereas Lua is used to parse \LaTeX{} commands, to build + the list of words and weights from a text file, and to generate + \hologo{METAPOST} code interpreted by \package{luamplib}. +\end{abstract} + + +\begin{center} + \url{https://plmlab.math.cnrs.fr/mchupin/wordcloud} + \url{https://github.com/chupinmaxime/wordcloud} +\end{center} + +\tableofcontents + +\bigskip + +\begin{tcolorbox}[ arc=0pt,outer arc=0pt, + colback=darkred!3, + colframe=darkred, + breakable, + boxsep=0pt,left=5pt,right=5pt,top=5pt,bottom=5pt, bottomtitle = + 3pt, toptitle=3pt, + boxrule=0pt,bottomrule=0.5pt,toprule=0.5pt, toprule at break = + 0pt, bottomrule at break = 0pt,] + \itshape + This package is in beta version---do not hesitate to report bugs, as well as + requests for improvement, or better: to help me to improve it. +\end{tcolorbox} + +\section{Installation} + +\wordcloudpkg is on \ctan{} and can also be installed via the package manager of your +distribution. + +\begin{center} + \url{https://www.ctan.org/pkg/wordcloud} +\end{center} + + +\subsection{With \TeX live under Linux or macOS} + +To install \wordcloudpkg with \TeX Live, you will have to create the directory +\lstinline+texmf+ in your \lstinline+home+. + +\begin{commandshell} +mkdir ~/texmf +\end{commandshell} + +Then, you will have to place the \lstinline+wordcloud.mp+ file in +\begin{center} + \verb+~/texmf/metapost/wordcloud/+ +\end{center} + + +You will also have to place the \lstinline+wordcloud.lua+ file in +\begin{center} + \verb+~/texmf/scripts/wordcloud/+ +\end{center} + +And finally, you will have to place the \lstinline+wordcloud.sty+ file in +\begin{center} + \verb+~/texmf/tex/latex/wordcloud/+ +\end{center} + + + +Once this is done, \wordcloudpkg will be loaded with the classic \MP{} +input code +\begin{mpcode} +input wordcloud +\end{mpcode} + +And for the \hologo{LuaLaTeX} side, \wordcloudpkg will be loaded with +\begin{latexcode} +\usepackage{wordcloud} +\end{latexcode} + +\subsection{With Mik\TeX{} and Windows} + +These two systems are unknown to the author of \wordcloudpkg, so we +refer you to the Mik\TeX documentation concerning the addition of local packages: +\begin{center} + \url{http://docs.miktex.org/manual/localadditions.html} +\end{center} + + + +\subsection{Dependencies} + + +\wordcloudpkg depends, for the \MP side, of course on \MP~\cite{ctan-metapost}, +but also on \package{metapost-colorbrewer}~\cite{ctan-metapost-colorbrewer} and the +\package{latexmp} package~\cite{ctan-latexmp}. For the \hologo{LuaLaTeX} side~\cite{ctan-lualatex-doc}, +\wordcloudpkg depends on the \package{luamplib} package~\cite{ctan-luamplib} +and the \package{xcolor}~\cite{ctan-xcolor}. + + +\section{\hologo{METAPOST} side} + +\subsection{Description of the algorithm} + +Given a set of words and weights, we first use a +\emph{scale function} of the weights to scale the words. In this beta version of +\package{wordcloud}, we only provide a log-based function\footnote{Other scale +options could be provided in the next versions.}. + +Then, we compute a spiral line starting at the center\footnote{There is variants +of the algorithm that use different line: squared spiral, etc.}. + +Then the algorithm is quite simple: +\begin{algorithmic}[1] +\Require set of words $(W_i)_{i\in\{1,\dots,N}$ and corresponding weight +$(w_i)_{i\in\{1,\dots,N}$, and a spiral line $\mathcal{S}$ +\ForAll{$i\in\{1, \dots,N\}$} +\State Place $W_i$ at the start of $\mathcal{S}$ +\Repeat + \State Set $b_\text{draw}:=\text{true}$ + \ForAll{$j\in{1,\dots,i}$} + \If{$W_i\cap W_j\neq\emptyset$} + \State Set $b_\text{draw}:=\text{false}$ + \EndIf + \EndFor + \If{$b_\text{draw}==\text{true}$} + \State Draw $W_i$ + \Else + \State Move $W_i$ along $\mathcal{S}$ + \EndIf +\Until{$W_i$ is drawn} +\EndFor +\end{algorithmic} + +The hard part is making it perform efficiently! According to Jonathan Feinberg, +Wordle\footnote{One of the first web application to build wordcloud.} uses a +combination of hierarchical bounding boxes and quadtrees to achieve reasonable +speeds. Here, with \hologo{METAPOST}, we compute intersections with the bounding +box of the word. + +\begin{remark} + \begin{itemize} + \item + The words with \hologo{METAPOST} are built with the \lstinline+textext()+ + function of \package{latexmp} or \package{luamplib}. We are trying to use the + bounding boxes of the letters when we get an intersection between ``global'' + bounding boxes to allow placing words nearer of each other. Unfortunately, + this does not work for the moment. Any help is welcomed. \medskip + + \item We first tried to compute intersections between words by decomposing the + letter using their contours and compute intersection of contours (with + \lstinline+intersectiontimes+). Unfortunately, this is much too slow. +\end{itemize} + +\end{remark} + +Some explanations can be found here: +\begin{center} + \url{https://www.jasondavies.com/wordcloud/about/} +\end{center} + +\subsection{Main command} + +The main command is + +\commande|draw_wordcloud(«words», «weights»,«rotation»,«size»)|\smallskip\index{draw_wordcloud@\lstinline+draw_wordcloud+} + +\begin{description} +\item[\meta{words}:] array of strings ; +\item[\meta{weights}:] array of numerics ; +\item[\meta{rotation}:] angle for wordcloud drawing; +\item[\meta{size}:] number of elements in arrays. +\end{description} + +\begin{ExempleMP} +input wordcloud +beginfig(0); +string words[]; +numeric weights[]; +words[1]:="\LaTeX"; +words[2]:="\hologo{METAPOST}"; +words[3]:="Document"; +words[4]:="Lua"; +words[5]:="\TeX"; +weights[1]:=5; +weights[2]:=4; +weights[3]:=3.5; +weights[4]:=3; +weights[5]:=3; +draw_wordcloud(words,weights,0,5); +endfig; +\end{ExempleMP} + +\begin{remark} +The ``unity'' of weights is not important because internally, +\package{wordcloud} compute new weights to work +with the internal scaling function. +\end{remark} + +\subsection{Parameters} + +There are few parameters. + +\subsubsection{Colors}\label{sec:colors} + +You can use set of colors to draw the wordcloud. For that, you have to use the +following command: +\commande|wordcloud_use_color(«bool»)|\smallskip\index{wordcloud_use_color@\lstinline+wordcloud_use_color+} + +\begin{description} + \item[\meta{bool}:] boolean \lstinline+true+ or \lstinline+false+ (default \lstinline+false+). +\end{description} + +\package{wordcloud} provides a set of five colors using the \hologo{METAPOST} +package \package{metapost-colorbrewer}~\cite{ctan-metapost-colorbrewer}. +\package{wordcloud} defines an array of \lstinline+color+s and a +\lstinline+numeric+ to set the colors to use.\index{wordcloud_colors@\lstinline+wordcloud_colors+}\index{wordcloud_colors_number@\lstinline+wordcloud_colors_number+} +\begin{mpcode} +% default colors +wordcloud_colors[1]:=Reds[3][3]; +wordcloud_colors[2]:=Greens[3][3]; +wordcloud_colors[3]:=Blues[3][3]; +wordcloud_colors[4]:=Oranges[3][3]; +wordcloud_colors[5]:=black; +wordcloud_colors_number:=5; +\end{mpcode} +Feel free to modify that variables to customize the colors. + +\subsubsection{Scaling} + +You can globally scale the picture using the following command: +\commande|set_wordcloud_scale(«scale»)|\smallskip\index{set_wordcloud_scale@\lstinline+set_wordcloud_scale+} + +\begin{description} + \item[\meta{scale}:] \lstinline+numeric+. +\end{description} + +\subsubsection{Margins} + +You can adjust the margins of the global bounding boxes of words using the +following command: +\commande|set_box_margin(«dim»)|\smallskip\index{set_box_margin@\lstinline+set_box_margin+} + +\begin{description} + \item[\meta{dim}:] a dimension with units (default 0.3pt). +\end{description} + + + +\section{\hologo{LuaLaTeX} side} + +\package{wordcloud} provides a \hologo{LuaLaTeX} package. It uses the package +\package{luamplib} to interpret the \hologo{METAPOST} code produced by Lua. + + +\subsection{Main commands} + +The first \LaTeX{} command provided by \wordcloudpkg is: + +\commande|\wordcloud[«options»]{«list of words and weights»}|\smallskip\index{\wordcloud@\lstinline+\wordcloud+} + +where +\begin{description} + \item[\meta{list of words and weights}:] is a list of couples of the form + \lstinline+(word1,weight1);(word2,weight2);(word3,weight3);...+ +\end{description} + +The second \LaTeX{} command allows to read a text file, to build the list of +words and weights and draw the wordcloud up to a certain number of words. + +\commande|\wordcloudFile[«options»]{«text file»}{«number of words»}|\smallskip\index{\wordcloudFile@\lstinline+\wordcloudFile+} + +where: +\begin{description} + \item[\meta{text file}:] is a text file to analyze and from which the + wordcloud is build ; + \item[\meta{number of words}:] is the number of words composing the wordcloud. +\end{description} + +\subsubsection{Options} + +Both of these functions (\lstinline+\wordcloud+ and \lstinline+\wordcloudFile+) +have the same options: + +\begin{description} + \item[\texttt{scale=}\meta{value}:] to scale the picture\footnote{Beware + that scaling increases the computation time and the values manipulated by + \hologo{METAPOST}.} ; + \item[\texttt{margin=}\meta{value with units}:] to adjust the margins + (default \lstinline+0.3pt+) ; + \item[\texttt{rotation=}\meta{angle}:] to rotate (degrees) the words with + $\pm$\meta{angle} alternatively (default 0) ; + \item[\texttt{usecolor}:] to use color for word drawing (boolean, default + \lstinline+false+) as described in section~\ref{sec:colors} ; + \item[\texttt{colors=}\meta{list of colors}:] to define a new + set of colors as described in section~\ref{sec:colors}\footnote{This needs + \package{xcolor} because the colors are converted to rgb coding and then + transferred to \hologo{METAPOST}.}. +\end{description} + + +Here an example: +\begin{ExempleLaTeX} +\wordcloud[scale=1,rotate=45,margin=0.5pt,usecolor,colors={red!40,blue!40,green!20!black}]{(Wordcloud,10);(\\hologo{METAPOST},6);(\\LaTeX,7);(Lua,4);(algorithm,3);(code,2);(mathematics,2);(CTAN,2);(mplib,4);(\\hologo{LuaTeX},4);(latexmp,3);(graphism,2)} +\end{ExempleLaTeX} + +\begin{remark} +Because the list of words and weights is given to Lua, we have to escape the +\lstinline+\+ to use \LaTeX{} commands. +\end{remark} + +\subsection{Add ignored words} + +The Lua function that builds words and weights from a text file ignores some +words (and characters). For the moment, \package{wordcloud} only includes word +lists to ignore for English and French. + +However, you can add a list of words to ignore with the following command: + +\commande|\wordcloudIgnoreWords{«word list»}|\smallskip\index{\wordcloudIgnoreWords@\lstinline+\wordcloudIgnoreWords+} + +\begin{description} + \item[\meta{word list}:] the list of words, separated with commas, to ignore + \lstinline+word1,word2,word3, etc.+ +\end{description} + + +\section{With \texttt{pdftotext}} + +Thanks to \package{wordcloud} and the program \texttt{pdftotext}\footnote{It +should be possible to parse a \pdf{} with \hologo{LuaTeX}, though. See \url{https://tex.stackexchange.com/questions/692930/recovering-the-textual-content-of-a-pdf-file-with-luatex}.} one can +easily produce the wordcloud of the current \pdf. + +For that, you can produce the text file of the \pdf{}: +\begin{commandshell} +pdftotext wordcloud-doc-en.pdf +\end{commandshell} +and then, you can use the following code: +\begin{latexcode} +\wordcloudFile[usecolor]{wordcloud-doc-en.txt}{50} +\end{latexcode} + +This produce the following wordcloud\footnote{Note that, because the wordcloud +production is slow, we used a separate file to only produce the \pdf{} of the +wordcloud, without any scaling, and we inserted the result scaling it with \package{graphicx}\cite{ctan-graphicx}.} +\begin{center} + \includegraphics[width=\linewidth]{doc-wc.pdf} +\end{center} + +\section{To do} + +Some things to do: +\begin{itemize} + \item Improve intersection of words by using the letters bounding boxes. + \item Work on speed of the algorithm. + \item Add supported languages (ignored words). + \item Improve text file analysis with Lua to build the set of words and + weights. + \item Build wordcloud inside a shape. + \item Add options for rotation of words. +\end{itemize} + +\printbibliography +\printindex +\newpage + + + +\end{document} diff --git a/graphics/metapost/contrib/macros/wordcloud/doc/wordcloud-preamble.tex b/graphics/metapost/contrib/macros/wordcloud/doc/wordcloud-preamble.tex new file mode 100644 index 0000000000..2e950254c4 --- /dev/null +++ b/graphics/metapost/contrib/macros/wordcloud/doc/wordcloud-preamble.tex @@ -0,0 +1,214 @@ +\usepackage{tcolorbox} +\tcbuselibrary{listings,breakable} +%\tcbuselibrary{documentation} +\usepackage{enumitem} +\usepackage[tikz]{bclogo} +\usepackage{mflogo} +\usepackage{hologo} +\usepackage{luamplib} +\mplibtextextlabel{enable} +\usepackage{biblatex} +\addbibresource{ctan.bib} +\usepackage{wrapfig} +\usepackage{accsupp} +\usepackage{siunitx} +\usepackage{imakeidx} +%\usepackage{csquotes} +\usepackage{fancyvrb,xparse,xargs} +\usepackage[sfdefault]{FiraSans} +\usepackage[mathrm=sym]{firamath-otf} +\setmonofont{Fira Mono} +%\setmonofont{FiraCode-Regular.ttf}[BoldFont= FiraCode-Bold.ttf,ItalicFont= FiraCode-RegularItalic.otf,BoldItalicFont= FiraCode-BoldItalic.otf,Ligatures={NoCommon, NoDiscretionary, NoHistoric, NoRequired, NoContextual}] +\usepackage[noEnd=false,]{algpseudocodex} +\usepackage{xspace} +\usepackage{animate} +\newcommand{\ctan}{\textsc{ctan}} +\NewDocumentCommand{\package}{ m }{% + \href{https://ctan.org/pkg/#1}{#1}\xspace +} + +\definecolor{darkred}{rgb}{0.6,0.1,0.1} +\definecolor{vert}{rgb}{0.1,0.4,0.1} +\definecolor{bleu}{rgb}{0.2,0.2,0.6} +\definecolor{orange}{rgb}{0.6,0.4,0.} +\colorlet{code}{blue!80!black} + +\usepackage[colorlinks=true,urlcolor=orange,linkcolor=orange,menucolor=black,citecolor=orange]{hyperref} + +\newcommand \file {\nolinkurl} +\renewcommand \cmd {\texttt} +\renewcommand \code [1] {\texorpdfstring {\texttt{\color{code}#1}} {#1}} +\renewcommand*\cs [1] {\code{\textbackslash #1}} + + + +\newcommand*\commande{\par\bigskip\noindent\hspace{-30pt}% + \SaveVerb[aftersave={% + \UseVerb{Vitem}% + }% + ]{Vitem}% + } + \newcommand\vitem[1][]{\SaveVerb[% + aftersave={\item[\textnormal{\UseVerb[#1]{vsave}}]}]{vsave}} +\newcommand*\textme[1]{\textcolor{black}{\rmfamily\textit{#1}}} +%\renewcommand*\meta[1]{% % meta +% \textme{\ensuremath{\langle}#1\ensuremath{\rangle}}} +\newcommand*\optstar{% % optional star + \meta{\ensuremath{*}}\xspace} +\DefineShortVerb{\|} +\newcommand\R{\mathbf{R}} +\setlength{\fboxsep}{2pt} +\fvset{% + codes={\catcode`\«\active \catcode`\×\active }, + defineactive={\makefancyog\makefancytimes}, + formatcom=\color{darkred}, + frame=single +} +% rendre «...» équivalent à \meta{...} +{\catcode`\«\active + \newcommandx\makefancyog[0][addprefix=\global]{% + \def«##1»{\meta{##1}}}} +% rendre × équivalent à \optstar +{\catcode`\×\active + \newcommandx\makefancytimes[0][addprefix=\global]{% + \def×{\optstar{}}}} + + +\newcommand\wordcloudpkg{\package{wordcloud}} + +\def\MO/{{\fontspec{fetamont}META\-OBJ}} + +%\addbibresource{biblio.bib} + + +\lstset{ + numberstyle=\footnotesize\color{vert}, + keywordstyle=\ttfamily\bfseries\color{bleu}, + basicstyle=\ttfamily, + commentstyle=\itshape\color{vert}, + stringstyle=\ttfamily\color{orange}, + showstringspaces=false, + language=MetaPost, + breaklines=true, + breakindent=30pt, + defaultdialect=MetaPost, + classoffset=1,% frame=tb + morekeywords={draw_wordcloud,set_box_margin,set_wordcloud_scale,wordcloud_colors,wordcloud_colors_number,wordcloud_use_color,\wordcloud,\wordcloudFile,\wordcloudIgnoreWords}, + keywordstyle=\color{darkred}, + classoffset=2,% frame=tb + morekeywords={Reds,Greens,Blues,Oranges}, + keywordstyle=\color{vert}, + classoffset=0,% frame=tb + morekeywords={draw}, + keywordstyle=\color{bleu} +} + + +\extractcolorspecs{darkred!3}\modelcmd\colorcmd +\makeatletter +\tcbset{% + listing metapost/.code={% + \def\tcbuselistingtext@input{\begin{mplibcode} verbatimtex \leavevmode etex; + background:=(\colorcmd); input \jobname.listing; \end{mplibcode}}% + } +} +\makeatother +\newtcblisting[auto counter,]{ExempleMP}[1][]{% + arc=0pt,outer arc=0pt, + colback=darkred!3, + colframe=darkred, + breakable,fontupper=\small, + boxsep=0pt,left=5pt,right=5pt,top=5pt,bottom=5pt, bottomtitle = + 3pt, toptitle=3pt, + boxrule=0pt,bottomrule=0.5pt,toprule=0.5pt, toprule at break = + 0pt, bottomrule at break = 0pt, + %listing side text, + listing metapost, + title=Exemple \hologo{METAPOST}~\thetcbcounter, + listing options={breaklines},#1 +} + +\newtcblisting[auto counter,]{ExempleLaTeX}{% + arc=0pt,outer arc=0pt, + colback=darkred!3, + colframe=darkred, + breakable,fontupper=\small, + boxsep=0pt,left=5pt,right=5pt,top=5pt,bottom=5pt, bottomtitle = + 3pt, toptitle=3pt, + boxrule=0pt,bottomrule=0.5pt,toprule=0.5pt, toprule at break = + 0pt, bottomrule at break = 0pt, + %listing side text, + title=Exemple \LaTeX~\thetcbcounter, + listing options={breaklines,language={[LaTeX]TeX}, + classoffset=1,% frame=tb + morekeywords={\wordcloud,\wordcloudFile}, + keywordstyle=\color{darkred}, + classoffset=2,% frame=tb + morekeywords={scale,rotate,margin,usecolor,colors}, + keywordstyle=\color{vert}, + classoffset=0,% frame=tb + morekeywords={draw}, + keywordstyle=\color{bleu} + } +} + +\newtcblisting{commandshell}{colback=black,colupper=white,colframe=black, + arc=0pt, + listing only,boxsep=0pt,listing + options={style=tcblatex,language=sh}, + every listing line={\BeginAccSupp{ActualText={}}\textcolor{red}{\small\ttfamily\bfseries user \$> }}\EndAccSupp{}} + + + \newtcblisting{mpcode}[1][]{ + arc=0pt,outer arc=0pt, + colback=darkred!3, + colframe=darkred, + breakable, + boxsep=0pt,left=5pt,right=5pt,top=5pt,bottom=5pt, bottomtitle = + 3pt, toptitle=3pt, + boxrule=0pt,bottomrule=0.5pt,toprule=0.5pt, toprule at break = + 0pt, bottomrule at break = 0pt, + listing only,boxsep=0pt,listing + options={breaklines},#1 +} + +\newtcblisting{latexcode}{ + arc=0pt,outer arc=0pt, + colback=darkred!3, + colframe=darkred, + breakable, + boxsep=0pt,left=5pt,right=5pt,top=5pt,bottom=5pt, bottomtitle = + 3pt, toptitle=3pt, + boxrule=0pt,bottomrule=0.5pt,toprule=0.5pt, toprule at break = + 0pt, bottomrule at break = 0pt, + listing only,boxsep=0pt,listing + options={breaklines,language={[LaTeX]TeX}, + classoffset=1,% frame=tb + morekeywords={\wordcloud,\wordcloudFile}, + keywordstyle=\color{darkred}, + classoffset=2,% frame=tb + morekeywords={scale,rotate,margin,usecolor,colors}, + keywordstyle=\color{vert}, + classoffset=0,% frame=tb + morekeywords={draw}, + keywordstyle=\color{bleu}} +} + + +\newcommand\pdf{\textsc{pdf}} + +\usepackage{array,booktabs} +\usepackage{collcell} + +\newcolumntype{H}{>{\collectcell\lstinline}l<{\endcollectcell}} + +\NewDocumentEnvironment{remark}{o}{ + \tcbset{% + arc=0pt,outer arc=0pt,colback=black!10,colframe=black, + boxsep=0pt,left=10pt,right=10pt,top=8pt,bottom=10pt, bottomtitle = 3pt, toptitle=3pt, + boxrule=0pt + } + \smallskip + \begin{tcolorbox}[fonttitle=\bfseries,title={Remark \IfNoValueF{#1}{(#1)}}]}% + {\end{tcolorbox}\medskip +} \ No newline at end of file diff --git a/graphics/metapost/contrib/macros/wordcloud/metapost/wordcloud.mp b/graphics/metapost/contrib/macros/wordcloud/metapost/wordcloud.mp new file mode 100644 index 0000000000..6a69fb5191 --- /dev/null +++ b/graphics/metapost/contrib/macros/wordcloud/metapost/wordcloud.mp @@ -0,0 +1,467 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% wordcloud %% +%% drawing wordclouds %% +%% with METAPOST and Lua %% +%% chupin@ceremade.dauphine.fr %% +%% Version 0.1 (aout 2023) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% This work may be distributed and/or modified under the conditions of +% the LaTeX Project Public License, either version 1.3c of this license +% or (at your option) any later version. The latest version of this +% license is in http://www.latex-project.org/lppl.txt +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if not known mplib: input latexmp ; show"wordcloud Infos: latexmp loaded";fi; +input colorbrewer-rgb + + +% function to get all the path of letters (too slow) +vardef build_pathpicture(expr pict)= + save tex_pct,glp_pct,glp_idx,glp_num,pth_num,glp_pth,fnt_str, txt_str, sub_str,txt_wd; + % text material and glyphs contours + picture tex_pct, glp_pct; + numeric glp_num, pth_num[]; + path glp_pth[][]; + % tex_pct btex .. etex material + % glp_num number of glyphs within tex_pct + % pth_num[i] number of paths defining the rank i (0 .. glp_num-1) glyph + % glp_pth[i][j] rank j (0 .. pth_num[i]-1) path of the rank i glyph + % glp_pct glyphs picture + + tex_pct:=pict; + + glp_pct:=nullpicture; + string fnt_str, txt_str, sub_str; + numeric txt_wd; + glp_num:=0; + for tkn within pict: + %show tkn; + if textual tkn: + %show "textual"; + fnt_str:=fontpart tkn; + txt_str:=textpart tkn; + txt_wd:=0; + for glp_idx=0 upto (length txt_str-1): + sub_str:=substring (glp_idx, glp_idx+1) of txt_str; + for sub_tkn within glyph ASCII sub_str of fnt_str + scaled (fontsize fnt_str/1000) + xscaled xxpart tkn + yscaled yypart tkn + shifted (txt_wd+xpart tkn, ypart tkn): + addto glp_pct doublepath (pathpart sub_tkn); + endfor + txt_wd:=txt_wd+ + (xxpart tkn)*xpart urcorner (sub_str infont fnt_str); + endfor + fi + endfor + glp_pct +enddef; + + +% path intersection (trop gourmant en temps, too slow...) +vardef word_intersection(expr tic, tac)= + save _p, _w, _v,_output; + boolean _output; + _output:=false; + path _p,_w,_v; + for _p within tic: + _w := pathpart _p; + for _q within tac: + _v := pathpart _q; + if((_w intersectiontimes _v)<>(-1,-1)): % intersection + _output:=true; + fi + endfor + endfor + _output +enddef; + +% global variable +_wordcloud_box_margin:=0.3pt; + +% setting the box margin +def set_box_margin(expr s)= + _wordcloud_box_margin:=s; +enddef; + +% extrenal box intersection (horizontal or vertical) +vardef extbb_intersection(expr tic, tac)= + save xmax_, xmin_, ymax_, ymin_, xmax__, xmin__, ymax__, ymin__, _output; + boolean _output; + _output:=false; + %show _p; + xmin_:= (xpart llcorner tic) -_wordcloud_box_margin; + ymin_ := (ypart llcorner tic)-_wordcloud_box_margin; + xmax_:= (xpart urcorner tic)+_wordcloud_box_margin; + ymax_ := (ypart urcorner tic)+_wordcloud_box_margin; + xmin__:= (xpart llcorner tac)-_wordcloud_box_margin; + ymin__ := (ypart llcorner tac)-_wordcloud_box_margin; + xmax__:= (xpart urcorner tac)+_wordcloud_box_margin; + ymax__ := (ypart urcorner tac)+_wordcloud_box_margin; + if ((xmin_<= xmax__) and (xmax_ >= xmin__) and (ymin_<= ymax__) and (ymax_ >= ymin__)): + _output:=true; + fi + _output +enddef; + +% subbb_entersection of words (from textext) +%%%!!!!!! not working !!!!!!!!! +vardef bb_intersection(expr tic, tac)= + save xmax_, xmin_, ymax_, ymin_, xmax__, xmin__, ymax__, ymin__, + _output; + save _p, _w, _v,_output,_q; + boolean _output; + _output:=false; + path _p,_w,_v; + i:=0; + for _v within tic: + for _p within _v: + i:=i+1; + %show "i"&decimal(i); + xmin_:= (xpart llcorner _p)-_wordcloud_box_margin; + ymin_ := (ypart llcorner _p)-_wordcloud_box_margin; + xmax_:= (xpart urcorner _p)+_wordcloud_box_margin; + ymax_ := (ypart urcorner _p)+_wordcloud_box_margin; + j:=0; + for _w within tac: + for _q within _w: + j:=j+1; + %show "j"&decimal(j); + xmin__:= (xpart llcorner _q)-_wordcloud_box_margin; + ymin__ := (ypart llcorner _q)-_wordcloud_box_margin; + xmax__:= (xpart urcorner _q)+_wordcloud_box_margin; + ymax__ := (ypart urcorner _q)+_wordcloud_box_margin; + if ((xmin_<= xmax__) and (xmax_ >= xmin__) and (ymin_<= ymax__) and (ymax_ >= ymin__)): + _output:=true; + fi + exitif(_output); + endfor + endfor + exitif(_output); + endfor + endfor + _output +enddef; + + +% build the spiral to put words +path _wordcloud_spiral; + +_wordcloud_spiral:=(0,0); + +_wordcloud_N:= 10*360; +_tours:=20; +_scale:=0.3; +for j:=1 upto _tours: + _rapj:=j/_tours; + for i:=1 step 10 until 360: + _rapi:=((i)+(j)*360)/360; + %show (_rapj*_rapi); + %show (6*_rapj*_rapi)*(cosd(i)*1cm,sind(i)*1cm); + _wordcloud_spiral:=_wordcloud_spiral--((_scale*_rapi)*(cosd(i)*1cm,sind(i)*1cm)); + endfor; +endfor + +picture _wordcloud_words[], _wordcloud_pathwords[]; +path _wordcloud_words_oriented_bb[]; +numeric _wordcloud_weights[]; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%% FONCTIONS USUELLES %%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% from repere.mp Olivier Péault + +pi:=3.141592654; +e:=2.718281828; + +vardef sin(expr x) = sind(180*x/pi) enddef; + +vardef cos(expr x) = cosd(180*x/pi) enddef; + +vardef tan(expr x) = sin(x)/cos(x) enddef; + +vardef exp(expr x) = mexp(x*256) enddef; + +vardef ln(expr x) = mlog(x)/256 enddef; + +vardef ch(expr x)=(exp(x)+exp(-x))/2 enddef; + +vardef sh(expr x)=(exp(x)-exp(-x))/2 enddef; + +vardef Arctan(expr x)= pi*angle(1,x)/180 enddef; +vardef Arctand(expr x)= angle(1,x) enddef; + +vardef Arcsin(expr x)= Arctan(x/sqrt(1-x**2)) enddef; +vardef Arcsind(expr x)= Arctand(x/sqrt(1-x**2)) enddef; + +vardef Arccos(expr x)= pi/2-Arcsin(x) enddef; +vardef Arccosd(expr x)= Arctand((sqrt(1-x**2))/x)enddef; + +% general scaling +_wordcloud_gen_scale:=1; + +def set_wordcloud_scale(expr s)= + _wordcloud_gen_scale:=s; +enddef; + +% fonction d'agrandissement en fonction du poids du mot +vardef _wordcloud_scale_fct(expr e,_max,_min)= + save _t,_N,_a,_b; + _a*_min+_b=0.7; + _a*_max+_b=2.5; + _t:=_a*e+_b; + _t:=ln(_t)-ln(0.7)+0.295; + _wordcloud_gen_scale*(1.1*_t) +enddef; + +% fabrication des mots avec la taille requise +vardef _build_tabs(suffix _words, _weights)(expr _N)= + save _tmp_pict,_width,_height; + picture _tmp_pict; + for i=1 upto _N: + _tmp_pict:=textext(_words[i]) scaled (_wordcloud_scale_fct(_weights[i],_weights[1],_weights[_N])); + _width:=abs(ulcorner _tmp_pict - urcorner _tmp_pict); + _height:=abs(ulcorner _tmp_pict - llcorner _tmp_pict); + _wordcloud_words[i]:= _tmp_pict shifted (-0.5_width,-0.5_height); + _wordcloud_weights[i]:=_weights[i]; + _bbox_old:=bboxmargin; + bboxmargin:=_wordcloud_box_margin; + _wordcloud_words_oriented_bb[i]:= bbox _wordcloud_words[i]; + bboxmargin:=_bbox_old; + _wordcloud_pathwords[i]:=build_pathpicture(_wordcloud_words[i]) ; + endfor; +enddef; +% function to compute angle +def _wordcloud_rotation(expr a,b)= +% a: angle +% b: 0 or 1 + if b=0: + a + else: + if(a=0): + 90 + else: + -a + fi + fi +enddef; + +%%% colors +boolean _wordcloud_use_color; +_wordcloud_use_color:=false; + +numeric wordcloud_colors_number; +color wordcloud_colors[]; + +% default colors +wordcloud_colors[1]:=Reds[3][3]; +wordcloud_colors[2]:=Greens[3][3]; +wordcloud_colors[3]:=Blues[3][3]; +wordcloud_colors[4]:=Oranges[3][3]; +wordcloud_colors[5]:=black; +wordcloud_colors_number:=5; + +def wordcloud_use_color(expr b)= + _wordcloud_use_color:= b; +enddef; + +% main function to draw the picture +vardef draw_wordcloud(suffix _words, _weights, rotation)(expr _N)= + save _rotation_bool,_position,_ok_draw,_tmp_word,_random_pt,_position_pt,_pt; + pair _random_pt,_position_pt,_pt; + path _tmp_word; + boolean _ok_draw; + _position:=0; + _build_tabs(_words,_weights,_N); + for i=1 upto _N: + %show i; + _position:=0; + if(i mod 2) = 0: + _rotation_bool:=1; + else: + _rotation_bool:=0; + fi + if(i=1): + draw _wordcloud_words[i] rotated (_wordcloud_rotation(rotation,_rotation_bool)) shifted (point _position + of _wordcloud_spiral) if(_wordcloud_use_color): withcolor wordcloud_colors[i] fi ; + _position_pt:=(0,0); + _random_pt:=(0,0); + else: + _count:=0; + + forever: + _position_pt:=point _position of _wordcloud_spiral; + _random_pt:=(uniformdeviate(1)*0.01cm,uniformdeviate(1)*0.01cm); + _pt:=_position_pt+_random_pt; + _count:=_count+1; + _ok_draw:= true; + _tmp_word:=_wordcloud_words_oriented_bb[i] rotated (_wordcloud_rotation(rotation,_rotation_bool)) shifted (_position_pt + _random_pt); + %_tmp_word:=_wordcloud_words[i] rotated (_rotation*90) shifted (point %_position + % of _wordcloud_spiral); + for j=1 upto i-1: + if(rectangles_intersection(_tmp_word,_wordcloud_words_oriented_bb[j])): + %if(bb_intersection(_tmp_word,_wordcloud_words[j])): + _ok_draw:= false; + %fi + fi + endfor; + if(_ok_draw): % if there is no intersections + draw _wordcloud_words[i] rotated + (_wordcloud_rotation(rotation,_rotation_bool)) shifted (_position_pt + + _random_pt) if(_wordcloud_use_color): withcolor wordcloud_colors[((i-1) + mod wordcloud_colors_number)+1] fi; + else: % else, we move along the spiral + _position:=_position+1; + fi + exitif(_ok_draw); + %exitif(_count>30); + endfor; + fi + _wordcloud_words[i]:=_wordcloud_words[i] rotated (_wordcloud_rotation(rotation,_rotation_bool)) shifted + (_position_pt + _random_pt); + _wordcloud_words_oriented_bb[i]:=_wordcloud_words_oriented_bb[i] rotated (_wordcloud_rotation(rotation,_rotation_bool)) shifted + (_position_pt + _random_pt); + _wordcloud_pathwords[i]:=_wordcloud_pathwords[i] rotated (_wordcloud_rotation(rotation,_rotation_bool)) shifted + (_position_pt + _random_pt); + endfor; +enddef; + + +vardef dotproduct(expr a,b)= + save _output; + _output := (xpart a)*(xpart b)+(ypart a)*(ypart b); + _output +enddef; + +vardef normvec(expr p)= + p/(sqrt((xpart p)**2+(ypart p)**2)) +enddef; + +vardef bb_projection(expr p,a)= + % p : edge of a rectangle (pair) + % a : axis of proj + dotproduct(p,a) +enddef; + +% intersection of oriented rectangel +vardef rectangles_intersection(expr tic,tac)= + % tic, tac, two rectangular path (closed) + save x,y,a,b,normedge,edge,_min,_max,_dotprod,_output,_minEdge,_maxEdge; + pair normedge,edge; + boolean _output; + _output:=false; + numeric x[],y[],a[],b[]; + (x1,y1) = point 1 of tic; + (x2,y2) = point 2 of tic; + (x3,y3) = point 3 of tic; + (x4,y4) = point 4 of tic; + (a1,b1) = point 1 of tac; + (a2,b2) = point 2 of tac; + (a3,b3) = point 3 of tac; + (a4,b4) = point 4 of tac; + for i=1 upto 4: + %show (x[i],y[i]); + endfor; + for i=1 upto 4: + %show (a[i],b[i]); + endfor; + %draw (a1,b1)--(a2,b2)--(a3,b3)--(a4,b4); + for i=1 upto 2: % on prend deux côtés perpendiculaire du rectangle 1 + %show "premier"; + %show i; + edge:=(x[i+1],y[i+1])-(x[i],y[i]); + %show edge; + normedge:=normvec(edge); + for j=1 upto 4: %pour chaque point de deuxième triangle on projette sur + % l’axe du côté du rectangle 1 qu’on considère + _dotprod:=dotproduct((x[j],y[j]),normedge); + if(j=1): + _minEdge:=_dotprod; + _maxEdge:=_dotprod; + fi + if(_dotprod<_minEdge): + _minEdge:=_dotprod; + else: + if(_dotprod>_maxEdge): + _maxEdge:=_dotprod; + fi + fi + %show _minEdge; + %show _maxEdge; + endfor; + %show _minEdge; + %show _maxEdge; + + for j=1 upto 4: %pour chaque point de deuxième triangle on projette sur + % l’axe du côté du rectangle 1 qu’on considère + _dotprod:=dotproduct((a[j],b[j]),normedge); + if(j=1): + _min:=_dotprod; + _max:=_dotprod; + fi + if(_dotprod<_min): + _min:=_dotprod; + else: + if(_dotprod>_max): + _max:=_dotprod; + fi + fi + endfor; + %show _min; + %show _max; + if (_min>_maxEdge) or (_max<_minEdge): + %show "OK"; + _output:=true; + fi + endfor; %the other way + for i=1 upto 2: % on prend deux côtés perpendiculaire du rectangle 1 + %show "deuxième"; + %show i; + edge:=(a[i+1],b[i+1])-(a[i],b[i]); + %show edge; + normedge:=normvec(edge); + for j=1 upto 4: %pour chaque point de deuxième triangle on projette sur + % l’axe du côté du rectangle 1 qu’on considère + _dotprod:=dotproduct((a[j],b[j]),normedge); + if(j=1): + _minEdge:=_dotprod; + _maxEdge:=_dotprod; + fi + if(_dotprod<_minEdge): + _minEdge:=_dotprod; + else: + if(_dotprod>_maxEdge): + _maxEdge:=_dotprod; + fi + fi + %show _minEdge; + %show _maxEdge; + endfor; + %show _minEdge; + %show _maxEdge; + + for j=1 upto 4: %pour chaque point de deuxième triangle on projette sur + % l’axe du côté du rectangle 1 qu’on considère + _dotprod:=dotproduct((x[j],y[j]),normedge); + if(j=1): + _min:=_dotprod; + _max:=_dotprod; + fi + if(_dotprod<_min): + _min:=_dotprod; + else: + if(_dotprod>_max): + _max:=_dotprod; + fi + fi + endfor; + if (_min>_maxEdge) or (_max<_minEdge): + %show "OK"; + _output:=true; + fi + endfor; + not _output +enddef; + diff --git a/graphics/metapost/contrib/macros/wordcloud/scripts/wordcloud.lua b/graphics/metapost/contrib/macros/wordcloud/scripts/wordcloud.lua new file mode 100644 index 0000000000..209ab0ca71 --- /dev/null +++ b/graphics/metapost/contrib/macros/wordcloud/scripts/wordcloud.lua @@ -0,0 +1,224 @@ +--[[ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% wordcloud %% +%% drawing wordclouds %% +%% with METAPOST and Lua %% +%% chupin@ceremade.dauphine.fr %% +%% Version 0.1 (aout 2023) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% This work may be distributed and/or modified under the conditions of +% the LaTeX Project Public License, either version 1.3c of this license +% or (at your option) any later version. The latest version of this +% license is in http://www.latex-project.org/lppl.txt +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +]] +function wc_file2string(file) + local f = assert(io.open(file, "rb")) + local content = f:read("*all") + f:close() + return content +end + +function wc_table_concat(t1,t2) + for i=1,#t2 do + t1[#t1+1] = t2[i] + end + return t1 +end + +function wc_ignor_fr() + local output; + output= {"et", "donc", "alors", "les", "ainsi", "des", "que", "qui", "sont", "par", "dans","est","pour","une","peut","avec","sans","Les","son","sur","ces","ses","tandis","quand"} + return output +end + +function wc_ignor_en() + local output; + output= {"and", "so", "the", "the", "hence", "some", "that", "are", "is", "have", "has","in","on","could","should","with","be","this","these","where","when","not","with","can",} + return output +end + +-- global variable for ignored words +wordcloud_ignor_words = {}; +wc_table_concat(wordcloud_ignor_words,wc_ignor_fr()) +wc_table_concat(wordcloud_ignor_words,wc_ignor_en()) + +-- function to add list of words to be ignored +function wc_add_ignored_words(tab) + wc_table_concat(wordcloud_ignor_words,tab) +end + +-- function to build a tab from a string of the form +-- word1,word2,word3,etc. +function wc_string_to_tab(strWord) + strWord=string.gsub(strWord, "%s+", "") -- space delete + local tab + tab = string.explode(strWord, ",") + return tab +end + +function wc_build_word_table(mystr) + local loc_str = mystr; + local ignor_chars = {";","’","'","\"","{","}","[","]","(",")","…",".","?","!","$","\\","#","<",">","«","»","+","*","-","/","=","%%", "€",":","~"} + loc_str = loc_str:gsub('[%p%c]+',' ') + for i=1,#ignor_chars do + loc_str = loc_str:gsub('['..ignor_chars[i]..']+',' ') + end + for i=1,#wordcloud_ignor_words do + loc_str = loc_str:gsub(' '..wordcloud_ignor_words[i]..' ',' ') + end + loc_str = loc_str:gsub(' LaTeX ',' \\LaTeX ') + loc_str = loc_str:gsub(' TeX ',' \\TeX ') + local t = {} + for i in loc_str:gmatch("%S+") do + t[#t + 1] = i + end + -- delete 2 size words + local id_two={} + for i=1,#t do + if(string.len(t[i])<=2) then + table.insert(id_two,i) + end + end + for i=#id_two,1,-1 do + table.remove(t,id_two[i]) + end + return t +end + +function wc_build_table_weight(t) + local weight = {} + for _, v in ipairs(t) do + weight[v] = (weight[v] or 0) + 1 + end + return weight +end + +function wc_table_to_tabular(table_weight) + local total_occ = 0 + local tabular_weight = {} + for k,v in pairs(table_weight) do + total_occ=total_occ+v + end + local i=0 + for k,v in pairs(table_weight) do + i=i+1 + tabular_weight[i] ={} + tabular_weight[i][1]=k + tabular_weight[i][2]=v/total_occ + end + table.sort(tabular_weight,function (k1, k2) return k1[2] > k2[2] end) + return tabular_weight +end + +function wc_build_mp_code(table_weight,maximum,rotation) + -- optional arguments + maximum = maximum or 50 + rotation = rotation or 0 + + local total_occ = 0 + local tabular_weight = wc_table_to_tabular(table_weight) + + + local str_mp=[[ + string words[]; + numeric weights[]; + ]] + local i=0 + for i=1, #tabular_weight do + + str_mp=str_mp.."words["..i.."]:=\""..tabular_weight[i][1].."\";" + str_mp=str_mp.."weights["..i.."]:="..tabular_weight[i][2]..";" + if (i>=maximum) then + break + end + end + str_mp=str_mp.."draw_wordcloud(words,weights,"..rotation..","..math.min(maximum,#tabular_weight)..");" + return str_mp +end + +function wc_list_to_table(list) + -- list of words and weights (word1,weight1);(word2,weight2); etc. + local table_weight = {} + local pair = string.explode(list, ";") + local lgth=#pair + for i=1,lgth do + word,weight=string.match(pair[i],"%((.+),(.+)%)") + table_weight[word]=weight + end + return table_weight +end + +function wc_size_of_table(table) + local lengthNum = 0 + + for k, v in pairs(table) do -- for every key in the table with a corresponding non-nil value + lengthNum = lengthNum + 1 + end + return lengthNum +end + + +function wc_build_color_list(colors) + -- list of LaTeX colors separated with colons + local out = "" + local pair = string.explode(colors:sub(1,-2), ";") -- sub(1,-2) to delete last ; + local lgth=#pair + for i=1,lgth do + out=out.."wordcloud_colors["..i.."]:="..pair[i]..";"; + end + out=out.."wordcloud_colors_number:="..lgth..";" + return out +end + +-- build mp code for the wordcloud of a list given in LaTeX command +function wc_build_wordcloud(str,rotation,scale,margin,usecolor,colors) + + maximum = maximum or 50 + local table = wc_list_to_table(str) + local lgth_table = wc_size_of_table(table) + local output + output= [[\begin{mplibcode}[wordcloud] + input wordcloud + beginfig(0); + ]] + if(usecolor=="true") then + output = output.."wordcloud_use_color(true);" + if(colors~="") then + output=output..wc_build_color_list(colors) + end + end + output = output.."set_wordcloud_scale("..scale..");" + output = output.."set_box_margin("..margin..");" + output = output..wc_build_mp_code(table,lgth_table,rotation) + output = output.."endfig;\\end{mplibcode}" + tex.sprint(output) +end + + +-- build mp code for the wordcloud of a file given in LaTeX command +function wc_build_wordcloud_file(file,number,rotation,scale,margin,usecolor,colors) + local str = wc_file2string(file) + + local words = wc_build_word_table(str) + + local table_weight = wc_build_table_weight(words) + local output + output= [[\begin{mplibcode}[wordcloud] + input wordcloud + beginfig(0); + ]] + if(usecolor=="true") then + output = output.."wordcloud_use_color(true);" + if(colors~="") then + output=output..wc_build_color_list(colors) + end + end + output = output.."set_wordcloud_scale("..scale..");" + output = output.."set_box_margin("..margin..");" + output = output..wc_build_mp_code(table_weight,number,rotation) + output = output.."endfig;\\end{mplibcode}" + tex.sprint(output) +end diff --git a/graphics/metapost/contrib/macros/wordcloud/tex/wordcloud.sty b/graphics/metapost/contrib/macros/wordcloud/tex/wordcloud.sty new file mode 100644 index 0000000000..6fce2b03d9 --- /dev/null +++ b/graphics/metapost/contrib/macros/wordcloud/tex/wordcloud.sty @@ -0,0 +1,149 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% wordcloud %% +%% drawing wordclouds %% +%% with METAPOST and Lua %% +%% chupin@ceremade.dauphine.fr %% +%% Version 0.1 (aout 2023) %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% This work may be distributed and/or modified under the conditions of +% the LaTeX Project Public License, either version 1.3c of this license +% or (at your option) any later version. The latest version of this +% license is in http://www.latex-project.org/lppl.txt +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\NeedsTeXFormat{LaTeX2e}% +\def\PackageName{wordcloud}% +\def\fileversion{v0.1}% +\def\filedate{2023/07/26}% +\ProvidesPackage{wordcloud}[\filedate\space\fileversion]% +% +% package to load +\RequirePackage{luamplib}% + +% +% load the lua code +\directlua{require("wordcloud.lua")}% + +\ExplSyntaxOn + +% variable globale +\tl_new:N \g__wc_wordcloud_scale_tl +\tl_new:N \g__wc_wordcloud_rotate_tl +\tl_new:N \g__wc_wordcloud_margin_tl + +% definitions des clés/valeurs pour la commande \wordcloud +\keys_define:nn{wc/wordcloud}{% + scale .tl_gset:N = \g__wc_wordcloud_scale_tl, + scale .value_required:n = true, + rotate .tl_gset:N = \g__wc_wordcloud_rotate_tl, + rotate .value_required:n = true, + margin .tl_gset:N = \g__wc_wordcloud_margin_tl, + margin .value_required:n = true, + usecolor .bool_set:N = \g__wc_wordcloud_usecolor_bool, + colors .clist_set:N = \g__wc_wordcloud_colors_clist, % list of LaTeX colors + colors .value_required:n = true, +% usecolor .default:n = true, +} + +% local variable to stock metapost colors list +\tl_new:N \l_colors_list_tl% + +% function to build a wordcloud from a list of the form : +% (word1,weight1);(word2,weight2);etc. +\NewDocumentCommand\wordcloud{ o m }{% + % mandatory argument : list (word1,weight1);(word2,weight2);etc. + % optional arguments : + % scale= (default 1) + % rotation= (default 0) + % margin= (default 0.3pt) + % usecolor=true/false (default false) + % colors={color1,color2,etc} + % pour les clés à valeur par défaut + \keys_set:nn { wc/wordcloud } { scale=1 } % + \keys_set:nn { wc/wordcloud } { rotate=0 } % + \keys_set:nn { wc/wordcloud } { margin=0.3pt } % + \keys_set:nn { wc/wordcloud } { colors={} } % + \keys_set:nn { wc/wordcloud } { usecolor=false } % + + \tl_clear:N \l_colors_list_tl% + \IfNoValueF {#1} + { + \keys_set:nn { wc/wordcloud } { #1 } + } + + % parse the list to build a list of rgb colors for metapost code + + \clist_map_variable:NNn \g__wc_wordcloud_colors_clist \l_onecolor_tl {% + \extractcolorspecs{\tl_use:N + \l_onecolor_tl}{\wc_onecolor_type}{\wc_onecolor_values} + % get the type and values of color (see xcolor doc) + \convertcolorspec{\wc_onecolor_type}{\wc_onecolor_values}{rgb}\wc_rgb_values + % convert to rgb (see xcolor loc) + \tl_gput_right:Nx \l_colors_list_tl {(\wc_rgb_values);} % add value with + %parenthesis + }% + + + %\show {coucous} + \directlua{% + %tex.sprint("test") + wc_build_wordcloud("#2",\tl_use:N \g__wc_wordcloud_rotate_tl,\tl_use:N \g__wc_wordcloud_scale_tl,"\tl_use:N \g__wc_wordcloud_margin_tl",\bool_if:NTF \g__wc_wordcloud_usecolor_bool{"true"}{"false"},"\tl_use:N \l_colors_list_tl") + }% +} + + +% function to build a wordcloud from a text file : +\NewDocumentCommand\wordcloudFile{ o m m}{% + % two mandatory arguments : name of the file and number of words for the + % wordcloud + % optional arguments : + % scale= (default 1) + % rotation= (default 0) + % margin= (default 0.3pt) + % usecolor=true/false (default false) + % colors={color1,color2,etc} + + % pour les clés à valeur par défaut + \keys_set:nn { wc/wordcloud } { scale=1 } % + \keys_set:nn { wc/wordcloud } { rotate=0 } % + \keys_set:nn { wc/wordcloud } { margin=0.3pt } % + \keys_set:nn { wc/wordcloud } { colors={} } % + \keys_set:nn { wc/wordcloud } { usecolor=false } % + \tl_clear:N \l_colors_list_tl% + + \IfNoValueF {#1} + { + \keys_set:nn { wc/wordcloud } { #1 } + } + + % parse the list to build a list of rgb colors for metapost code + + \clist_map_variable:NNn \g__wc_wordcloud_colors_clist \l_onecolor_tl {% + \extractcolorspecs{\tl_use:N + \l_onecolor_tl}{\wc_onecolor_type}{\wc_onecolor_values} + % get the type and values of color (see xcolor doc) + \convertcolorspec{\wc_onecolor_type}{\wc_onecolor_values}{rgb}\wc_rgb_values + % convert to rgb (see xcolor loc) + \tl_gput_right:Nx \l_colors_list_tl {(\wc_rgb_values);} % add value with + %parenthesis + }% + + %\show {coucous} + \directlua{% + wc_build_wordcloud_file("#2",#3,\tl_use:N \g__wc_wordcloud_rotate_tl,\tl_use:N \g__wc_wordcloud_scale_tl,"\tl_use:N \g__wc_wordcloud_margin_tl",\bool_if:NTF \g__wc_wordcloud_usecolor_bool{"true"}{"false"},"\tl_use:N \l_colors_list_tl") + }% +} + +% function to add words to ignor when a wordcloud is build from a text file +\NewDocumentCommand\wordcloudIgnoreWords{m}{% + % mandatory argument : list of words separated by commas + % word1, word2, word3, etc. + \directlua{% + tab=wc_string_to_tab("#1") + wc_add_ignored_words(tab) + }% +} + + +\ExplSyntaxOff \ No newline at end of file -- cgit v1.2.3