Jupyter Notebook

9 minuto(s) de leitura

O Jupyter Notebook é a maneira que optei para escrever os códigos na linguagem python, visto que além de rodar os códigos, é possível:

  1. Documentar os scripts, escrevendo o significado e objetivo de cada conjunto de comandos;
  2. Atualizar os meus repositórios na plataforma GitHub;
  3. Trabalhar com uma diversidade de opções de exportação do arquivo em formatos diversos, adaptados até mesmo para as simples leitura, como PDFs e Markdowns.

Com tais caraterísticas, notei que é possível publicar posts diretamente do Jupyter Notebook. Aqui pretendo apresentar um pouco das funções que tenho explorado para aperfeiçoar e facilitar minhas publicações no meu site pessoal: https://michelmetran.github.io. E, pesquisando pela internet, descobri que não sou o único a Exploring Jupyer Notebook to write a Blog, tem muito material a ser explorado…

OBSERVAÇÃO
Esse post tem a finalidade de mostrar os comandos básicos e me deixar com uma "cola" rápida para meu uso cotidiano.
Todas os códigos são exemplificativos e podem/devem ser alterados, indicando o nome dos arquivos e diretórios corretamente.
INFORMAÇÃO
  1. É possível acessar esse post em formato html, que possibilita ter uma visualização rápida do código;
  2. Diretamente por meio do repositório, onde está disponível este arquivo .ipynb, que permite fazer edições no código;
  3. Ou ainda, de maneira interativa, usando o MyBinder, que possibilita rodar e editar o código sem a necessidade de instalar nada.
import os
import json
import time
import folium
import pandas as pd
from datetime import date
[os.makedirs(i, exist_ok=True) for i in ['docs']]

Get Jupyter Notebook filename

Para as funções que serão apresentadas ao longo desse script, a obtenção do nome do arquivo .ipynb em uma variável seria de grande ajuda. Não há modo fácil de obter, visto que para todas as opções, é necessário o java, que não funciona quando é solicitado que todas as células rodem de uma só vez (Kernel > Run All).

Diretamente na célula

Testei diversos comandos para obter o nome do Jupyter Notebook em uma variável. A melhor opção que encontrei estava nesse post que tem diversas outras opções.

%%
javascript

var kernel = IPython.notebook.kernel;
var body = document.body, attribs = body.attributes;
var command = 'ipynb_filename = ' + '"' + attribs['data-notebook-name'].value + '"';
kernel.execute(command);
# ipynb_filename
%%
javascript

var kernel = IPython.notebook.kernel;
var nb = IPython.notebook;
var command = 'ipynb_pathname = ' + '"' + nb.base_url + nb.notebook_path + '"';
kernel.execute(command);
# ipynb_pathname

Com função

Usei uma função que peguei na, provavelmente aqui, para pegar o nome do arquivo .ipynb. Atualmente preferi, nas funões que necessitam do nome do arquivo, em escreve-lo como uma constante… evitando o uso do java dentro do Juptyter Notebook.

# %load '../codes/files/get_jupyternotebook_name.py'
def get_jupyternotebook_name():
    """
    Returns the name of the current notebook as a string
    From https://mail.scipy.org/pipermail/ipython-dev/2014-June/014096.html
    :return: Returns the name of the current notebook as a string
    """
    # Import Packages
    from IPython.core.display import Javascript
    from IPython.display import display

    display(Javascript('IPython.notebook.kernel.execute("theNotebook = " + \
    "\'"+IPython.notebook.notebook_name+"\'");'))

    # Result
    return theNotebook

name = get_jupyternotebook_name()
name

Markdown Cell

Inserindo HTML

Sabendo que tanto o framework Jerkll, quando o Jupyter Notebook utilizam o BootStrap 4.0, torna-se possível utilizar alguns parâmetros para renderizar, nas células markdown um conteúdo mais interessante, bastando inserir as <div> abaixo.

<div class="alert alert-success" role="alert">
  This is a success alert—check it out!
</div>

Ainda é possível criar box mais elaborados, escrevendo com os códigos em HTML.

Além de diversas outros elementos do Bootstrap que podem ser inseridas, por exemplo:

Variáveis em Markdowns

# 
a = 10

Para inserir uma variável em uma célula markdow para eu inserir a variável entre colchetes duplos, por exemplo . Logo, se eu alterar o valor de a para qualquer um terei que a=.

O mesmo pode ser feito com tabelas. Em tentativa de inserir tabelas diretamente do Pandas não obtive sucesso… Depois temos dataframe modificado pelo .to_html() , função que fornece várias opções a serem exploradas.

df = pd.DataFrame({"A": [1.0, 2.2, 3.6666], "B": [4.12134, 5.674, 6.13215]})
df_html = df.to_html(index=False, decimal='.', notebook=True, justify='center')
df_html = df_html.replace('\n', '')

Linhas de Tabelas

Descobri que nesse _ post_ que é possível trabalhar para inserir também mais de uma tabela alinhada, mas isso se dá em uma célula de output (e não _ markdown_).

import pandas as pd
import numpy as np
from IPython.display import display, HTML

CSS = """
.output {
    flex-direction: row;
}
"""

HTML('<style>{}</style>'.format(CSS))
display(df)


Comandos do Sistema

Praticamente qualquer comando do sistema pode ser acessado usando previamente !, o qual passa qualquer comando subsequente diretamente para o sistema operacional. Você pode até usar variáveis python em comandos enviados para o sistema operacional!

!ls

É possível trabalhar com variáveis entre o python e esses comandos do sistema.

file_type = 'ipynb'

!ls. / *$file_type


Exportando o Juptyter Notebook

Os arquivos Jupyter Notebook podem ser exportados em diversos formatos, seja através do menu de opções, ou através dos comandos. Ao exportar, é possível definir diversas opções que limitam o que será exportado, podendo escolher determinados tipos de células ou, até mesmo, células invidivuais.

No _ post_ Jupyter Notebook nbconvert without Magic Commands/ w/o Markdown é apresentado algumas opções de exportação. A página oficial do NbConvert tem todos os parâmetros, tanto para linhas de comando quanto para python.


Linha de Comando

a maneira mais simples de exportar um arquivo é por meio do comando abaixo. O uso do ponto de explamação no início do comando é pelo fato desse comando ser “nativo” da linha de comando, e não do python.

!jupyter - nbconvert
jupyter.ipynb - -to
html - -output
docs / jupyter.html

Uma vez compreendida a função e sabendo que é possível inserir variáveis criadas no python em comandos de “linha de comando”, criei a seguinte rotina.

# Input
inp = 'jupyter.ipynb'

# Output
out = os.path.join('docs', inp.split('.')[0])

# Extension to export ('html', 'html_embed', 'markdown', 'latex', 'pdf', 'python')
ext = 'html_embed'

# Remove cells with tag
tag = ("['" + '"remove_cell"' + ", " + '"yaml"' + "']")
!echo $tag
!jupyter - nbconvert $inp
- -to $ext
- -TagRemovePreprocessor.enabled = True
- -TagRemovePreprocessor.remove_cell_tags =$tag
- -ClearOutputPreprocessor.enabled = True
- -TemplateExporter.exclude_markdown = False
- -TemplateExporter.exclude_code_cell = False
- -TemplateExporter.exclude_output = True
- -TemplateExporter.exclude_raw = False
- -TemplateExporter.exclude_input_prompt = True
- -TemplateExporter.exclude_output_prompt = True
- -output $out


Função

Abaixo mostro uma função que escrevi para facilitar o processo de exportação do arquivo em diferentes locais do PC para, posteriormente, atualizar os repositórios contidos no GitHub. Incorporei diversas opções para exportação no script ../codes/files/export_jupyter.py, quando notei que seria mais fácil usar os códigos diretamente, sem funções.

# %load '../codes/files/export_jupyter.py'
def export_jupyter(filename, path, extensions=['html', 'markdown', 'latex', 'pdf', 'python'], today=True):
    """
    Export .ipynb file to others formats
    :return: File in other formats
    """
    # Import Packages
    import os
    import datetime

    # Data
    timestamp = datetime.datetime.now()
    srt_today = (str(timestamp.year) + '-' +
                 str(f"{timestamp.month:02d}") + '-' +
                 str(f"{timestamp.day:02d}"))

    import os
    filter = "['remove_cell']"
    options = ('--TagRemovePreprocessor.enabled=True '
               '--ClearOutputPreprocessor.enabled=True '
               '--TemplateExporter.exclude_markdown=False '
               '--TemplateExporter.exclude_code_cell=True '
               '--TemplateExporter.exclude_output=True '
               '--TemplateExporter.exclude_raw=False '
               '--TemplateExporter.exclude_input_prompt=True '
               '--TagRemovePreprocessor.remove_cell_tags="' + filter + '" ')

    # Extensions
    for extension in extensions:
        if today == True:
            command = ('jupyter nbconvert {} --to {} {} --output {}'.
                       format(filename,
                              extension,
                              options,
                              os.path.join(path, srt_today + '-' + filename.split('.')[0])))
            # print(command)
            os.system(command)
            print('Arquivo {} exportado corretamente para o formato {} usando prefixo da data.'.
                  format(filename, extension))

        else:
            command = ('jupyter nbconvert {} --to {} {} --output {}'.
                       format(filename,
                              extension,
                              options,
                              os.path.join(path, filename.split('.')[0])))
            # print(command)
            os.system(command)
            print('Arquivo {} exportado corretamente para o formato {} sem usar prefixo da data.'.
                  format(filename, extension))

# export_jupyter(ipynb_filename, 'docs', ['html', 'markdown', 'pdf', 'python'], False)

Exportar para Word (.doc)

Usando Pandoc descobri que é possível exportar para .doc. Em tentativos, notei alguns problemas de incompatibilidade, mas pode auxiliar em algum momento.

ipynb_filename = 'jupyter.ipynb'

file_wo_ext = ipynb_filename.split('.')[0]
file_md = file_wo_ext + '.md'
file_doc = file_wo_ext + '.docx'

file_doc = os.path.join('docs', file_doc)
file_md = os.path.join('docs', file_md)
!pandoc - o $file_doc - f
markdown - t
docx $file_md - -reference - links


GitHub

Diversos projetos que tenho feito, com scripts do Jupyter Notebook, estão listados no GitHub. Alguns destes _ scripts_ são, também, publicações no meu site pessoal, o qual também está hospedado no GitHub.

Dessa maneira, busquei fazer com que os comandos para atualização dos repositórios já constassem dentro dos scripts, de modo que modificações e ajustes fossem facilmente compartilhados. Ainda, como alguns scripts dão origem a posts em meu site, estes também são atualizados.


NbStripout

Inicialmente compreendi que é considerada como best pratices no git de projetos escritos em Jupyter Notebook a aplicação de um determinado código usando o package nbstripout, para “limpar o cache” do arquivo. No post How to Git Jupyter Notebooks the Right Way e no vídeo nbstripout: strip output from Jupyter and IPython notebooks é explicado detalhadamente o funcionamento.

!nbstripout - -install - -attributes.gitattributes

Git de linha de comando

Basta atualizar o repositório com os comandos do git usualmente aplicados na linha de comando. Quando se deseja rodar comandos da linha decomando dentro de um Jupyter Notebook, basta adicionar o ponto de exclamação no início do comando.

Atualmente é a minha solução preferida, mas testei algumas outras anteriormente, conforme será demonstrado abaixo. Fiz essa opção pois acho mais prático utilizar os comandos “originais” do git, para manusear os repositórios, e me dá a flexibilidade de me familharizar com os comandos para usar em outros projetos que não envolvam python (e integrações).

!git
status
!git
add.
!git
commit - m

# Atualização do repositório
!git
push

Integrações do Git com Python

Existem diversos módulos para promover a integração do git e python. Dentre elas destaca-se o pacote GitPython, porém existem outros. Muito foi discutido no post Python Git Module experiences?. Testei algumas delas mas preferi dedicar tempo a aprender outras coisas.

Funções e Subprocess

Criei uma função, utilizando o subprocess, para exportar o Jupyter Notebook em diversos formatos. Aproveitei para incorporar o comando do nbstripout na função que faz o commit, visando simplificar as coisas. Com o tempo abandonei o uso, por não gostava dos logs do outputs.

# %load '../codes/git/update_github.py'
import subprocess


def git_add(repo, files):
    cmd = 'git add ' + files
    pipe = subprocess.Popen(cmd, shell=True, cwd=repo, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (out, error) = pipe.communicate()
    print(out, error)
    pipe.wait()
    return


def git_commit(repo, msg):
    cmd = 'git commit -am "%s"' % msg
    pipe = subprocess.Popen(cmd, shell=True, cwd=repo, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (out, error) = pipe.communicate()
    print(out, error)
    pipe.wait()
    return


def git_push(repo):
    cmd = 'git push '
    pipe = subprocess.Popen(cmd, shell=True, cwd=repo, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (out, error) = pipe.communicate()
    print(out, error)
    pipe.wait()
    return


def git_full(repo, files, msg):
    # Strip Out
    import os
    os.system('nbstripout --install --attributes .gitattributes')

    # Function to comit
    git_add(repo, files)
    git_commit(repo, msg)
    git_push(repo)
    print('Done!!')
    return

Erros

Em uma tentativa de exportar o Jupyter Notebook para PDF tive problemas. O arquivo não era exportado e apresentava a seguinte mensagem de erro:

  • nbconvert failed: xelatex not found on PATH, if you have not installed xelatex you may need to do so. Find further instructions at https://nbconvert.readthedocs.io/en/latest/install.html#installing-tex.

Para solucionar, descobri que é necessário instalar, no Linux, akguns pacotes de aplicativos com os seguintes comandos, sendo o primeiro uma instalação mais compacta e o segundo uma instalação completa.

sudo apt-get install texlive-xetex texlive-fonts-recommended texlive-generic-recommended

sudo apt-get install texlive-full

Referêcias

Há muita informação na internet sobre funcionalidades do Jupyter Notebook. Apenas para exemplificar, usei particialmente algumas das funções e truques apresentados em Jupyter Notebook Extensions e 28 Jupyter Notebook Tips, Tricks, and Shortcuts.

Deixe um comentário