Трудный рабочий процесс написания латексной книги, полной кода Python - PullRequest
1 голос
/ 08 марта 2019

Я пишу книгу по кодированию на python с использованием Latex.Я планирую иметь много текста с разбросанным по всему Python-коду, а также его вывод.Что действительно доставляет мне неприятности, так это то, что когда мне нужно вернуться и отредактировать свой код Python, мне очень тяжело вернуть его обратно в мой последний документ.

Я провел много исследований и могуКажется, я не могу найти хорошего решения.

Этот файл включает в себя полные файлы как один, не решает мои проблемы https://tex.stackexchange.com/questions/289385/workflow-for-including-jupyter-aka-ipython-notebooks-as-pages-in-a-latex-docum

То же самое с этим.http://blog.juliusschulz.de/blog/ultimate-ipython-notebook

Найдено решение 1 (ужасно)

Я могу скопировать и вставить код Python в латекс, используя пакет латексных списков.

Плюсы:

  1. Легко обновить только небольшой фрагмент кода.

Минусы:

  1. Для вывода нужнозапустить на python, скопировать, вставить отдельно.
  2. Первоначальная запись МЕДЛЕННО, необходимо выполнить этот процесс сотни раз за главу.

Найдено решение 2 (плохо)

Используйте блокнот Jupyter с уценкой, экспортируйте в Latex, \ включайте файл в основной документ Latex.

Плюсы:

  1. Оптимизировано
  2. Имеетсявывод содержится в пределах.

Минусы:

  • Чтобы внести небольшие изменения, необходимо повторно импортировать весь документ, все изменения, внесенные в текст уценки в редакторе латекса, не сохраняются
  • Переименование одной переменной в python после того, как ноутбук jupyter может занять несколько часов.
  • Редактирование выглядит как гигантская рутина.

Идеальное решение

  • Запись текста в латексе
  • Запись Python в блокноте Jupyter, экспорт в латекс.
  • Каким-то образом включить фрагменты кода (небольшие разделы экспортируемого файла) в различные части основной книги по латексу. Это часть, которую я не могу понять
  • Когда нужны изменения на python, изменения в jupyter, а затем реэкспорт как файл латекса с тем же именем
  • Latex bookавтоматически обновляется из include.

Ключевым моментом здесь является то, что экспортированный блокнот Python разделяется и отправляется в разные части документа.Чтобы это работало, его нужно каким-то образом пометить или пометить в уценке или коде блокнота, поэтому, когда я реэкспортирую его, те же самые части отправляются в те же места в книге.

Плюсы:

  1. Python редактирует легко, легко распространяется обратно в книгу.
  2. Текст, написанный на латексе, может использовать силу латекса

Любая помощь в появлениис решением ближе к моему идеальному решению будет высоко ценится.Это убивает меня.

Возможно, это не имеет значения, но я пишу как латексные, так и jupyter ноутбуки в VS Code.Я открыт для смены инструментов, если это означает решение этих проблем.

Ответы [ 3 ]

2 голосов
/ 08 марта 2019

Вот небольшой сценарий, который я написал.Он разбивает один *.ipynb файл и преобразует его в несколько *.tex файлов.

Использование:

  1. Скопируйте следующий скрипт и сохраните его как main.py
  2. выполнить python main.py init.это создаст main.tex и style_ipython_custom.tplx
  3. в вашей записной книжке Jupyther, добавьте дополнительную строку #latex:tag_a, #latex:tag_b, .. в каждую ячейку, которую вы хотите извлечь.тот же тег будет извлечен в тот же файл *.tex.
  4. сохраните его как файл *.ipynb.К счастью, текущий плагин VSCode Python поддерживает экспорт в *.ipynb или использует jupytext для преобразования из *.py в *.ipynb.
  5. run python main.py path/to/your.ipynb, и он создаст tag_a.tex и tag_b.tex
  6. отредактируйте main.tex и добавьте \input{tag_a.tex} или \input{tag_b.tex} где угодно.
  7. запустите pdflatex main.tex, и он выдаст main.pdf

Идеяза этим сценарием:

Преобразование из блокнота jupyter в LaTex с использованием значения по умолчанию nbconvert.LatexExporter приводит к созданию полного файла LaTex, который включает определения макросов.Использование его для преобразования каждой ячейки может создать большой файл LaTex.Чтобы избежать этой проблемы, сценарий сначала создает main.tex, который имеет только определения макросов, а затем преобразует каждую ячейку в файл LaTex, который не имеет определения макросов.Это можно сделать с помощью пользовательского файла шаблона, который слегка изменен по сравнению с style_ipython.tplx

. Пометка или маркировка ячейки может быть выполнена с использованием метаданных ячейки, но я не смог найти способ ее установки в плагине VSCode Python ( Issue ), поэтому вместо этого он сканирует источник каждой ячейки с шаблоном регулярного выражения ^#latex:(.*) и удаляет его перед преобразованием в файл LaTex.

Источник:

import sys
import re
import os
from collections import defaultdict
import nbformat
from nbconvert import LatexExporter, exporters

OUTPUT_FILES_DIR = './images'
CUSTOM_TEMPLATE = 'style_ipython_custom.tplx'
MAIN_TEX = 'main.tex'


def create_main():
    # creates `main.tex` which only has macro definition
    latex_exporter = LatexExporter()
    book = nbformat.v4.new_notebook()
    book.cells.append(
        nbformat.v4.new_raw_cell(r'\input{__your_input__here.tex}'))
    (body, _) = latex_exporter.from_notebook_node(book)
    with open(MAIN_TEX, 'x') as fout:
        fout.write(body)
    print("created:", MAIN_TEX)


def init():
    create_main()
    latex_exporter = LatexExporter()
    # copy `style_ipython.tplx` in `nbconvert.exporters` module to current directory,
    # and modify it so that it does not contain macro definition
    tmpl_path = os.path.join(
        os.path.dirname(exporters.__file__),
        latex_exporter.default_template_path)
    src = os.path.join(tmpl_path, 'style_ipython.tplx')
    target = CUSTOM_TEMPLATE
    with open(src) as fsrc:
        with open(target, 'w') as ftarget:
            for line in fsrc:
                # replace the line so than it does not contain macro definition
                if line == "((*- extends 'base.tplx' -*))\n":
                    line = "((*- extends 'document_contents.tplx' -*))\n"
                ftarget.write(line)
    print("created:", CUSTOM_TEMPLATE)


def group_cells(note):
    # scan the cell source for tag with regexp `^#latex:(.*)`
    # if sames tags are found group it to same list
    pattern = re.compile(r'^#latex:(.*?)$(\n?)', re.M)
    group = defaultdict(list)
    for num, cell in enumerate(note.cells):
        m = pattern.search(cell.source)
        if m:
            tag = m.group(1).strip()
            # remove the line which contains tag
            cell.source = cell.source[:m.start(0)] + cell.source[m.end(0):]
            group[tag].append(cell)
        else:
            print("tag not found in cell number {}. ignore".format(num + 1))
    return group


def doit():
    with open(sys.argv[1]) as f:
        note = nbformat.read(f, as_version=4)
    group = group_cells(note)
    latex_exporter = LatexExporter()
    # use the template which does not contain LaTex macro definition
    latex_exporter.template_file = CUSTOM_TEMPLATE
    try:
        os.mkdir(OUTPUT_FILES_DIR)
    except FileExistsError:
        pass
    for (tag, g) in group.items():
        book = nbformat.v4.new_notebook()
        book.cells.extend(g)
        # unique_key will be prefix of image
        (body, resources) = latex_exporter.from_notebook_node(
            book,
            resources={
                'output_files_dir': OUTPUT_FILES_DIR,
                'unique_key': tag
            })
        ofile = tag + '.tex'
        with open(ofile, 'w') as fout:
            fout.write(body)
            print("created:", ofile)
        # the image data which is embedded as base64 in notebook
        # will be decoded and returned in `resources`, so write it to file
        for filename, data in resources.get('outputs', {}).items():
            with open(filename, 'wb') as fres:
                fres.write(data)
                print("created:", filename)


if len(sys.argv) <= 1:
    print("USAGE: this_script [init|yourfile.ipynb]")
elif sys.argv[1] == "init":
    init()
else:
    doit()
1 голос
/ 08 марта 2019

Я бы использовал bookdown , чтобы иметь и тестовый, и исходный код в одном документе (для удобства разбитый на несколько файлов).Этот пакет происходит из мира R, но также может использоваться вместе с другими языками.Вот очень простой пример:

---
output: bookdown::pdf_document2
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

# Setup data

First we define some varialbes with data.

```{python data}
bob = ['Bob Smith', 42, 30000, 'software']
sue = ['Sue Jones', 45, 40000, 'music']
```

# Output data

then we output some of the data.

```{python output}
bob[0], sue[2]
```

# Reference code block

Finally lets repeate the code block without evaluating it.

```{python, ref.label="output", eval = FALSE}
```

Вывод:

enter image description here

1 голос
/ 08 марта 2019

Jupyter не позволяет экспортировать определенные ячейки из записной книжки - он позволяет вам экспортировать только записную книжку целиком. Чтобы максимально приблизиться к вашему идеальному сценарию, вам нужна модульная установка Jupyter:

  1. Разделите ваш единственный ноутбук Jupyter на меньшие ноутбуки.
  2. Каждый блокнот затем можно экспортировать в LaTeX через Файл> Загрузить как> LaTeX (.tex)
  3. В LaTeX вы можете импортировать сгенерированный файл .tex через

    \ вход {filname.tex}

Если вы хотите импортировать меньшие блокноты в ячейки вашего основного блокнота, вы можете сделать это с помощью (см. Магическую команду run )

%run my_other_notebook.ipynb #or %run 'my notebook with spaces.ipynb'

Вы также можете вставлять файлы Python через (см. Волшебную команду load )

%load python_file.py

, который загружает файл Python и позволяет выполнять его в основной записной книжке.

Вы также можете иметь небольшие фрагменты .py, загрузить их в свой маленький блокнот Jupyter, а затем запустить этот маленький блокнот в свой больший.

Вы можете использовать VS Code, но Jupyter в браузере может быть быстрее для вас редактировать.

( ссылка для всех магических команд )

...