Jupyter Notebook
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:
- Documentar os scripts, escrevendo o significado e objetivo de cada conjunto de comandos;
- Atualizar os meus repositórios na plataforma GitHub;
- 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…
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.
- É possível acessar esse post em formato html, que possibilita ter uma visualização rápida do código;
- Diretamente por meio do repositório, onde está disponível este arquivo .ipynb, que permite fazer edições no código;
- 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.
Aww yeah, you successfully read this important alert message. This example text is going to run a bit longer so that you can see how spacing within an alert works with this kind of content.
Whenever you need to, be sure to use margin utilities to keep things nice and tidy.
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