Julia. Geradores de relatórios e documentos


Um dos problemas prementes o tempo todo é o problema de preparar relatórios. Como Julia é uma linguagem cujos usuários estão diretamente conectados às tarefas de análise de dados, preparando artigos e belas apresentações com os resultados de cálculos e relatórios, esse tópico simplesmente não pode ser ignorado.


Inicialmente, este artigo planejava um conjunto de receitas para gerar relatórios, mas ao lado dos relatórios está o tópico da documentação, com o qual os geradores de relatórios têm muitas interseções. Portanto, isso inclui ferramentas para o critério da possibilidade de incorporar o código executável Julia em um modelo com alguma marcação. Por fim, observamos que a revisão incluiu geradores de relatórios, implementados na própria Julia, e ferramentas escritas em outras linguagens de programação. Bem, é claro, alguns pontos-chave da própria linguagem Julia não foram ignorados, sem os quais pode não estar claro em quais casos e quais meios devem ser usados.


Caderno Jupyter


Essa ferramenta, talvez, deve ser atribuída aos mais populares entre os envolvidos na análise de dados. Devido à capacidade de conectar vários núcleos de computação, é popular entre pesquisadores e matemáticos acostumados a suas linguagens de programação específicas, uma das quais é Julia. Os módulos correspondentes para a linguagem Julia são totalmente implementados no Notebook Jupyter. E é por isso que o Notebook é mencionado aqui.
O processo de instalação do Jupyter Notebook não é complicado. Para o pedido, consulte https://github.com/JuliaLang/IJulia.jl Se o Jupyter Notebook já estiver instalado, será necessário instalar o pacote Ijulia e registrar o núcleo de computação correspondente.


Como o produto Notebook Jupyter é conhecido o suficiente para não ser escrito em detalhes, mencionaremos apenas alguns pontos. O bloco de notas (usaremos a terminologia do bloco de notas) em um bloco de anotações Jupyter consiste em blocos, cada um dos quais pode conter código ou marcação em suas várias formas (por exemplo, Markdown). O resultado do processamento é a visualização da marcação (texto, fórmulas etc.) ou o resultado da última operação. Se um ponto e vírgula for colocado no final da linha com o código, o resultado não será exibido.


Exemplos. O bloco de notas antes da execução é mostrado na figura a seguir:



O resultado de sua implementação é mostrado na figura a seguir.



O bloco de notas contém gráficos e algum texto. Observe que, para DataFrame a matriz, é possível usar o tipo DataFrame , para o qual o resultado é exibido na forma de uma tabela html com bordas explícitas e um scroller, se necessário.


O notebook Jupyter pode exportar o notebook atual para o arquivo html. Se houver ferramentas de conversão instaladas, elas poderão ser convertidas para pdf.


Para criar relatórios de acordo com alguns regulamentos, você pode usar o módulo nbconvert e o seguinte comando, chamado em segundo plano, de acordo com o cronograma:
jupyter nbconvert --to html --execute julia_filename.ipynb


Ao executar cálculos demorados, é recomendável adicionar uma opção indicando o tempo limite - --ExecutePreprocessor.timeout=180


Um relatório html gerado a partir deste arquivo aparecerá no diretório atual. A opção --execute aqui significa forçar a recontagem a iniciar.


Para obter um conjunto completo de nbconvert módulo nbconvert consulte
https://nbconvert.readthedocs.io/en/latest/usage.html


O resultado da conversão para html é quase completamente consistente com a figura anterior, exceto pelo fato de não possuir uma barra de menus ou botões.


Jupytext


Um utilitário bastante interessante que permite converter notas de ipynb criadas anteriormente em texto Markdown ou código Julia.


Podemos transformar o exemplo considerado anteriormente usando o comando
jupytext --to julia julia_filename.ipynb


Como resultado, obtemos o arquivo julia_filename.jl com o código Julia e a marcação especial na forma de comentários.


 # --- # jupyter: # jupytext: # text_representation: # extension: .jl # format_name: light # format_version: '1.3' # jupytext_version: 0.8.6 # kernelspec: # display_name: Julia 1.0.3 # language: julia # name: julia-1.0 # --- # # Report example using Plots, DataFrames # ### Drawing # Good time to show some plot plot(rand(5,5), linewidth=2, title="My Plot", size = (500, 200)) # ## Some computational results rand(2, 3) DataFrame(rand(2, 3)) 

Os separadores de bloco de notas são apenas alimentações de linha dupla.


Podemos fazer a transformação inversa usando o comando:
jupytext --to notebook julia_filename.jl


Como resultado, será gerado um arquivo ipynb que, por sua vez, pode ser processado e convertido em pdf ou html.


Veja detalhes https://github.com/mwouts/jupytext


A desvantagem geral do jupytext e do notebook jupyter é que a "beleza" do relatório é limitada pelos recursos dessas ferramentas.


HTML auto-gerado


Se, por algum motivo, acreditarmos que o Jupyter Notebook é um produto muito pesado, exigindo a instalação de vários pacotes de terceiros que não são necessários para que Julia funcione, ou que não sejam flexíveis o suficiente para criar o formulário de relatório necessário, uma maneira alternativa é gerar uma página html manualmente. No entanto, aqui você precisa se aprofundar um pouco nas características da imagem.


Para Julia, uma maneira típica de produzir algo para o fluxo de saída é usar a função Base.write e, para decorar, Base.show(io, mime, x) . Além disso, para os vários métodos de saída MIME solicitados, pode haver várias opções de exibição. Por exemplo, um DataFrame quando exibido como texto é exibido por uma tabela pseudo-gráfica.


 julia> show(stdout, MIME"text/plain"(), DataFrame(rand(3, 2))) 3×2 DataFrame │ Row │ x1 │ x2 │ │ │ Float64 │ Float64 │ ├─────┼──────────┼───────────┤ │ 1 │ 0.321698 │ 0.939474 │ │ 2 │ 0.933878 │ 0.0745969 │ │ 3 │ 0.497315 │ 0.0167594 │ 

Se mime for especificado como text/html , o resultado será a marcação HTML.


 julia> show(stdout, MIME"text/html"(), DataFrame(rand(3, 2))) <table class="data-frame"> <thead> <tr><th></th><th>x1</th><th>x2</th></tr> <tr><th></th><th>Float64</th><th>Float64</th></tr> </thead> <tbody><p>3 rows × 2 columns</p> <tr><th>1</th><td>0.640151</td><td>0.219299</td></tr> <tr><th>2</th><td>0.463402</td><td>0.764952</td></tr> <tr><th>3</th><td>0.806543</td><td>0.300902</td></tr> </tbody> </table> 

Ou seja, usando os métodos da função show definidos para o tipo de dados correspondente (terceiro argumento) e o formato de saída correspondente, é possível garantir a formação de um arquivo em qualquer formato de dados desejado.


A situação com imagens é mais complicada. Se precisarmos criar um único arquivo html, a imagem deverá ser incorporada no código da página.


Considere o exemplo no qual isso é implementado. A saída para o arquivo será realizada pela função Base.write , para a qual definimos os métodos apropriados. Então o código:


 #!/usr/bin/env julia using Plots using Base64 using DataFrames #        p = plot(rand(5,5), linewidth=2, title="My Plot", size = (500, 200)) #  ,  ,    @show typeof(p) # => typeof(p) = Plots.Plot{Plots.GRBackend} #    ,   3  #     abstract type Png end abstract type Svg end abstract type Svg2 end #  Base.write      #         #   —   ,  #   Base64-. #  HTML  img src="data:image/png;base64,..." function Base.write(file::IO, ::Type{Png}, p::Plots.Plot) local io = IOBuffer() local iob64_encode = Base64EncodePipe(io); show(iob64_encode, MIME"image/png"(), p) close(iob64_encode); write(file, string("<img src=\"data:image/png;base64, ", String(take!(io)), "\" alt=\"fig.png\"/>\n")) end #     Svg function Base.write(file::IO, ::Type{Svg}, p::Plots.Plot) local io = IOBuffer() show(io, MIME"image/svg+xml"(), p) write(file, replace(String(take!(io)), r"<\?xml.*\?>" => "" )) end #    XML-  ,  SVG Base.write(file::IO, ::Type{Svg2}, p::Plots.Plot) = show(file, MIME"image/svg+xml"(), p) #     DataFrame Base.write(file::IO, df::DataFrame) = show(file, MIME"text/html"(), df) #   out.html   HTML open("out.html", "w") do file write(file, """ <!DOCTYPE html> <html> <head><title>Test report</title></head> <body> <h1>Test html</h1> """) write(file, Png, p) write(file, "<br/>") write(file, Svg, p) write(file, "<br/>") write(file, Svg2, p) write(file, DataFrame(rand(2, 3))) write(file, """ </body> </html> """) end 

Para criar imagens, o mecanismo Plots.GRBackend é usado por padrão, que pode executar saída de imagem raster ou vetorial. Dependendo do tipo especificado no argumento mime da função show , o resultado correspondente é gerado. MIME"image/png"() forma uma imagem no formato png . MIME"image/svg+xml"() gera uma imagem svg. No entanto, no segundo caso, você deve prestar atenção ao fato de um documento xml completamente independente ser formado, que pode ser gravado como um arquivo separado. Ao mesmo tempo, nosso objetivo é incorporar uma imagem em uma página HTML, o que pode ser feito no HTML5 simplesmente inserindo a marcação SVG. É por isso que o método Base.write(file::IO, ::Type{Svg}, p::Plots.Plot) corta o cabeçalho xml, que, caso contrário, violará a estrutura do documento HTML. Embora a maioria dos navegadores possa exibir corretamente a imagem, mesmo nesse caso.


Em relação ao método para Base.write(file::IO, ::Type{Png}, p::Plots.Plot) , o recurso de implementação aqui é que só podemos inserir dados binários no HTML no formato Base64. Fazemos isso usando a construção <img src="data:image/png;base64,"/> . E para transcodificação, usamos Base64EncodePipe .


O método Base.write(file::IO, df::DataFrame) fornece saída no formato de tabela html do objeto DataFrame .


A página resultante é a seguinte:



Na imagem, todas as três imagens têm a mesma aparência; no entanto, lembre-se de que uma delas foi inserida incorretamente do ponto de vista do HTML (cabeçalho xml extra). Uma é a varredura, o que significa que não pode ser aumentada sem perda de detalhes. E apenas um deles é inserido como o fragmento svg correto dentro da marcação HTML. E pode ser facilmente dimensionado sem perda de detalhes.


Naturalmente, a página acabou sendo muito simples. Mas qualquer aprimoramento visual é possível com CSS.


Esse método de geração de relatórios é útil, por exemplo, quando o número de tabelas exibidas é determinado por dados reais e não por um modelo. Por exemplo, você precisa agrupar dados por algum campo. E para cada grupo formar blocos separados. Como na formação de uma página, o resultado é determinado pelo número de chamadas para Base.write , é óbvio que não há problema em Base.write o bloco desejado em um loop, tornando a saída dependente dos dados etc.


Exemplo de código:


 using DataFrames #       ptable = DataFrame( Symbol = ["H", "He", "C", "O", "Fe" ], Room = [:Gas, :Gas, :Solid, :Gas, :Solid] ) res = groupby(ptable, [:Room]) #      open("out2.html", "w") do f for df in (groupby(ptable, [:Room])) write(f, "<h2>$(df[1, :Room])</h2>\n") show(f, MIME"text/html"(), DataFrame(df)) write(f, "\n") end end 

O resultado desse script é um fragmento da página HTML.



Observe que tudo o que não requer conversão de decoração / formato é exibido diretamente através da função Base.write . Ao mesmo tempo, tudo o que requer conversão é produzido através do Base.show .


Weave.jl


O Weave é um gerador de relatórios científicos implementado por Julia. Usa as idéias dos geradores Pweave, Knitr, rmarkdown, Sweave. Sua principal tarefa é exportar a marcação de origem em qualquer um dos idiomas propostos (Noweb, Markdown, formato de script) para os formatos LaTex, Pandoc, Github, MultiMarkdown, Asciidoc, reStructuredText. E, mesmo nos cadernos IJulia e vice-versa. Na última parte, é semelhante ao Jupytext.


Ou seja, o Weave é uma ferramenta que permite escrever modelos contendo o código Julia em várias linguagens de marcação e, na saída, ter marcação em outra linguagem (mas com os resultados da execução do código Julia). E esta é uma ferramenta muito útil especificamente para pesquisadores. Por exemplo, você pode preparar um artigo sobre Látex, que terá inserções na Julia com cálculo automático do resultado e sua substituição. O Weave irá gerar um arquivo para o artigo final.


Há suporte para o editor Atom usando o plug-in correspondente https://atom.io/packages/language-weave . Isso permite que você desenvolva e depure scripts Julia incorporados na marcação e gere o arquivo de destino.


O princípio básico do Weave, como já mencionado, é analisar um modelo contendo marcação com texto (fórmulas etc.) e colar o código na Julia. O resultado da execução do código pode ser exibido no relatório final. A saída de texto, código, a saída dos resultados, a saída dos gráficos - tudo isso pode ser configurado individualmente.


Para processar os modelos, você precisa executar um script externo que colete tudo em um único documento e o converta no formato de saída desejado. Ou seja, modelos separadamente, manipuladores separadamente.


Um exemplo de um script de processamento:


 #     : # Markdown weave("w_example.jmd", doctype="pandoc" out_path=:pwd) # HTML weave("w_example.jmd", out_path=:pwd, doctype = "md2html") # pdf weave("w_example.jmd", out_path=:pwd, doctype = "md2pdf") 

jmd nos nomes dos arquivos é Julia Markdown.


Veja o mesmo exemplo que usamos nas ferramentas anteriores. No entanto, inseriremos um cabeçalho com informações sobre o autor que o Weave entende.


 --- title : Intro to Weave.jl with Plots author : Anonymous date : 06th Feb 2019 --- # Intro ## Plot ` ``{julia;} using Plots, DataFrames plot(rand(5,5), linewidth=2, title="My Plot", size = (500, 200)) ` `` ## Some computational results ` ``julia rand(2, 3) ` `` ` ``julia DataFrame(rand(2, 3)) ` `` 

Este fragmento, sendo convertido para pdf, se parece com isso:



Fontes e layout são bem reconhecidos pelos usuários de látex.


Para cada parte do código incorporado, você pode determinar como esse código será processado e o que será exibido no final.


Por exemplo:


  • echo = true - o código será exibido
  • eval = true - o resultado da execução do código será exibido
  • label - adicione um rótulo. Se Latex for usado, ele será usado como fig: label
  • fig_width, fig_height - tamanhos da imagem
  • e assim por diante

Para os formatos noweb e script, além de mais sobre essa ferramenta, consulte http://weavejl.mpastell.com/stable/


Literate.jl


Os autores deste pacote, quando perguntados sobre o porquê do Literate, se referem ao paradigma de programação alfabética de Donald Knutt. A tarefa desta ferramenta é gerar documentos com base no código Julia contendo comentários no formato de remarcação. Ao contrário da ferramenta Weave anterior examinada, ele não pode fazer documentos com os resultados da execução. No entanto, a ferramenta é leve e focada principalmente na documentação de códigos. Por exemplo, ajude a escrever belos exemplos que podem ser colocados em qualquer plataforma de descontos. Geralmente usado em uma cadeia de outras ferramentas de documentação, por exemplo, junto com o Documenter.jl .


Existem três opções possíveis para o formato de saída - markdown, notebook e script (código Julia puro). Nenhum deles executará o código implementado.


Exemplo de arquivo de origem com comentários do Markdown (após o primeiro caractere #):


 #!/usr/bin/env julia using Literate Literate.markdown(@__FILE__, pwd()) # documenter=true # # Intro # ## Plot using Plots, DataFrames plot(rand(5,5), linewidth=2, title="My Plot", size = (500, 200)) # ## Some computational results rand(2, 3) DataFrame(rand(2, 3)) 

O resultado de seu trabalho será um documento do Markdown e diretrizes para o Documenter , se a geração deles não tiver sido explicitamente desativada.


 ` ``@meta EditURL = "https://github.com/TRAVIS_REPO_SLUG/blob/master/" ` `` ` ``@example literate_example #!/usr/bin/env julia using Literate Literate.markdown(@__FILE__, pwd(), documenter=true) ` `` # Intro ## Plot ` ``@example literate_example using Plots, DataFrames plot(rand(5,5), linewidth=2, title="My Plot", size = (500, 200)) ` `` ## Some computational results ` ``@example literate_example rand(2, 3) DataFrame(rand(2, 3)) ` `` *This page was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).* 

As inserções de código dentro da marcação são deliberadamente colocadas com um espaço entre o primeiro e o subseqüente apóstrofo, para não ficar confuso quando o artigo é publicado.


Veja mais detalhes https://fredrikekre.imtqy.com/Literate.jl/stable/


Documenter.jl


Gerador de documentação. Seu principal objetivo é formar documentação legível para pacotes escritos em Julia. O Documenter converte exemplos html ou pdf com marcação Markdown e código Julia incorporado, bem como arquivos de origem do módulo, extraindo Julia-docstrings (comentários de Julia).


Um exemplo de documentação típica:



Neste artigo, não abordaremos os princípios da documentação, pois, de uma maneira boa, isso deve ser feito como parte de um artigo separado sobre o desenvolvimento de módulos. No entanto, veremos alguns aspectos do Documenter aqui.


Antes de tudo, vale a pena prestar atenção ao fato de que a tela é dividida em duas partes - o lado esquerdo contém um índice interativo. O lado direito é, de fato, o texto da documentação.


Uma estrutura de diretório típica com exemplos e documentação é a seguinte:


  docs/ src/ make.jl src/ Example.jl ... 

O diretório docs/src é a documentação de remarcação. E exemplos são encontrados em algum lugar no diretório de origem compartilhada src .


O arquivo de chave do Docuementer é docs/make.jl O conteúdo deste arquivo para o próprio Documentador:


 using Documenter, DocumenterTools makedocs( modules = [Documenter, DocumenterTools], format = Documenter.HTML( # Use clean URLs, unless built as a "local" build prettyurls = !("local" in ARGS), canonical = "https://juliadocs.imtqy.com/Documenter.jl/stable/", ), clean = false, assets = ["assets/favicon.ico"], sitename = "Documenter.jl", authors = "Michael Hatherly, Morten Piibeleht, and contributors.", analytics = "UA-89508993-1", linkcheck = !("skiplinks" in ARGS), pages = [ "Home" => "index.md", "Manual" => Any[ "Guide" => "man/guide.md", "man/examples.md", "man/syntax.md", "man/doctests.md", "man/latex.md", hide("man/hosting.md", [ "man/hosting/walkthrough.md" ]), "man/other-formats.md", ], "Library" => Any[ "Public" => "lib/public.md", hide("Internals" => "lib/internals.md", Any[ "lib/internals/anchors.md", "lib/internals/builder.md", "lib/internals/cross-references.md", "lib/internals/docchecks.md", "lib/internals/docsystem.md", "lib/internals/doctests.md", "lib/internals/documenter.md", "lib/internals/documentertools.md", "lib/internals/documents.md", "lib/internals/dom.md", "lib/internals/expanders.md", "lib/internals/mdflatten.md", "lib/internals/selectors.md", "lib/internals/textdiff.md", "lib/internals/utilities.md", "lib/internals/writers.md", ]) ], "contributing.md", ], ) deploydocs( repo = "github.com/JuliaDocs/Documenter.jl.git", target = "build", ) 

Como você pode ver, os principais métodos aqui são makedocs e deploydocs , que determinam a estrutura da documentação futura e o local para sua colocação. makedocs fornece a formação de marcação de remarcação de todos os arquivos especificados, o que inclui a execução do código incorporado e a extração de comentários de documentos.


O Documenter suporta várias diretivas para inserir código. Seu formato é `` @something


  • @docs , @autodocs - links para documentação de documentação extraída dos arquivos Julia.
  • @meta , @meta , @index , @contents - links, indicações de páginas de índice, etc.
  • @example , @repl , @eval - modos de execução do código Julia incorporado.
  • ...

A presença das diretivas @example, @repl, @eval , de fato, determinou se o Documenter deveria ser incluído nessa visão geral ou não. Além disso, o Literate.jl mencionado anteriormente pode gerar automaticamente essa marcação, como foi demonstrado anteriormente. Ou seja, não há restrições fundamentais ao uso do gerador de documentação como gerador de relatório.


Para obter mais informações sobre o Documenter.jl, consulte https://juliadocs.imtqy.com/Documenter.jl/stable/


Conclusão


Apesar da juventude da linguagem Julia, os pacotes e ferramentas já desenvolvidos para ela nos permitem falar sobre o uso total em serviços altamente carregados, e não apenas sobre a implementação de projetos de avaliação. Como você pode ver, a capacidade de gerar vários documentos e relatórios, incluindo os resultados da execução do código, tanto em texto quanto em forma gráfica, já é fornecida. Além disso, dependendo da complexidade do relatório, podemos escolher entre a facilidade de criar um modelo e a flexibilidade de gerar relatórios.


O artigo não considera o gerador de linho do pacote Genie.jl. O Genie.jl é uma tentativa de implementar Julia no Rails, e o Flax é um tipo de análogo do eRubis com inserções de código para Julia. No entanto, o Flax não é fornecido como um pacote separado e o Genie não está incluído no repositório principal de pacotes, portanto, não foi incluído nesta revisão.


Separadamente, gostaria de mencionar os pacotes Makie.jl e Luxor.jl , que fornecem a formação de visualizações vetoriais complexas. O resultado do trabalho também pode ser usado como parte dos relatórios, mas um artigo separado também deve ser escrito sobre isso.


Referências


Source: https://habr.com/ru/post/pt439442/


All Articles