-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from daskol/style/neurips2023
Add NeurIPS 2023 template
- Loading branch information
Showing
10 changed files
with
1,149 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Ignore LaTeX output files. | ||
*.aux | ||
*.bbl | ||
*.bst | ||
*.log | ||
*.out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
#!/usr/bin/env python | ||
"""Simple script based on MuPDF bindings for colorizing annotation in documents | ||
produced by Typst v0.10.0 (or may be newer). | ||
""" | ||
|
||
from argparse import ArgumentParser, Namespace | ||
from dataclasses import astuple, dataclass | ||
from os import unlink | ||
from pathlib import Path | ||
from shutil import move | ||
from tempfile import NamedTemporaryFile | ||
from typing import Any, Self | ||
|
||
import fitz | ||
from fitz import Document, Page | ||
|
||
DEFAULT_STROKE_CYAN = (0.0, 1.0, 1.0) | ||
|
||
DEFAULT_STROKE_RED = (1.0, 0.0, 0.0) | ||
|
||
parser = ArgumentParser(description=__doc__) | ||
parser.add_argument('source', type=Path, help='path to original document') | ||
parser.add_argument('target', type=Path, help='path to output document') | ||
|
||
|
||
@dataclass | ||
class Point: | ||
|
||
x: float | ||
|
||
y: float | ||
|
||
def __add__(self, other: Self) -> Self: | ||
return self.__class__(self.x + other.x, self.y + other.y) | ||
|
||
def __iadd__(self, other: Self) -> Self: | ||
self.x += other.x | ||
self.y += other.y | ||
return self | ||
|
||
|
||
@dataclass | ||
class Rect: | ||
|
||
top_left: Point | ||
|
||
bot_right: Point | ||
|
||
@classmethod | ||
def from_points(cls, x0: float, y0: float, x1: float, y1: float) -> Self: | ||
return cls(Point(x0, y0), Point(x1, y1)) | ||
|
||
@classmethod | ||
def from_postscript(cls, value: str) -> Self: | ||
points = [float(x) for x in value[1:-1].split()] | ||
return cls.from_points(*points) | ||
|
||
def __add__(self, other) -> Self: | ||
return self.__class__(self.top_left + other.top_left, | ||
self.bot_right + other.bot_right) | ||
|
||
def __iadd__(self, other) -> Self: | ||
self.top_left += other.top_left | ||
self.bot_right += other.bot_right | ||
return self | ||
|
||
def to_points(self) -> tuple[float, float, float, float]: | ||
return astuple(self.top_left) + astuple(self.bot_right) | ||
|
||
def to_postscript(self) -> str: | ||
points = self.to_points() | ||
coords = ' '.join(f'{point:g}' for point in points) | ||
return f'[{coords}]' | ||
|
||
|
||
DEFAULT_SPACING = Rect.from_points(-0.5, -2.5, 0.5, 1.5) | ||
|
||
|
||
@dataclass | ||
class Style: | ||
|
||
stroke: tuple[float, float, float] | ||
|
||
spacing: Rect | ||
|
||
|
||
DEFAULT_STYLES = { | ||
'external': Style(stroke=DEFAULT_STROKE_CYAN, spacing=DEFAULT_SPACING), | ||
'internal': Style(stroke=DEFAULT_STROKE_RED, spacing=DEFAULT_SPACING), | ||
} | ||
|
||
|
||
def enumerate_links(doc: Document): | ||
page: Page | ||
for ix, page in enumerate(doc): | ||
for link in page.get_links(): | ||
yield ix, page, link | ||
|
||
|
||
def colorize_link(doc: Document, link: dict[str, Any], styles=None): | ||
# If there is no valid xref then it is embedded annotation. Skip it. | ||
if (xref := link['xref']) is None or xref <= 0: | ||
return | ||
|
||
styles = styles or DEFAULT_STYLES | ||
if 'uri' in link: | ||
style = styles['external'] | ||
else: | ||
style = styles['internal'] | ||
|
||
stroke_str = ' '.join(f'{x:g}' for x in style.stroke) | ||
doc.xref_set_key(xref, 'H', '/I') | ||
doc.xref_set_key(xref, 'C', f'[{stroke_str}]') | ||
doc.xref_set_key(xref, 'BS', '<< /W 1 /S /S >>') | ||
|
||
# Adjust bounding box of annotation. | ||
type_, value = doc.xref_get_key(xref, 'Rect') | ||
if type_ != 'array': | ||
print(f'Attribute `Rect` of xref={xref} is not array.') | ||
return | ||
rect = Rect.from_postscript(value) | ||
rect += style.spacing | ||
doc.xref_set_key(xref, 'Rect', rect.to_postscript()) | ||
|
||
|
||
def colorize(source: Path, target: Path, styles=None): | ||
doc: Document = fitz.open(source) | ||
|
||
# Enumerate all available links and create new link with the same | ||
# attributes. The issue is that Typst writes embeddable annotations which | ||
# does not have xref. This makes impossible to modify annotation attributes | ||
# inplace. | ||
for _, page, link in enumerate_links(doc): | ||
new_link = {**link} | ||
new_link.pop('xref', None) | ||
new_link.pop('zoom', None) | ||
new_link.pop('id', None) | ||
page.insert_link(new_link) | ||
|
||
# As we duplicated annotations, we can update their appearence. | ||
total_pages = len(doc) | ||
for ix, page in enumerate(doc, 1): | ||
print(f'{ix}/{total_pages}: {page}') | ||
for link in page.links(): | ||
colorize_link(doc, link, styles) | ||
|
||
# If source and target pathes are equal then write to temporary and then | ||
# replace the original one. | ||
if target != source: | ||
target.parent.mkdir(exist_ok=True, parents=True) | ||
doc.save(target, garbage=3, deflate=True) | ||
doc.close() | ||
else: | ||
prefix = '.' + target.name.removesuffix('.pdf') + '-' | ||
with NamedTemporaryFile(mode='w', dir=target.parent, prefix=prefix, | ||
suffix='.pdf', delete=False) as tempfile: | ||
unlink(tempfile.name) | ||
doc.save(tempfile.name, garbage=3, deflate=True) | ||
doc.close() | ||
move(tempfile.name, source) # Copy back. | ||
|
||
|
||
def main(): | ||
ns: Namespace = parser.parse_args() | ||
colorize(ns.source, ns.target) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Neural Information Processing Systems (NeurIPS) 2023 | ||
|
||
## Example Papers | ||
|
||
Here are an example paper in [LaTeX][1] and in [Typst][2]. | ||
|
||
## Issues | ||
|
||
- The biggest and the most important issues is related to line ruler. We are | ||
not aware of universal method for numbering lines in the main body of a | ||
paper. | ||
|
||
- There is an issue in Typst with spacing between figures and between figure | ||
with floating placement. The issue is that there is no way to specify gap | ||
between subsequent figures. In order to have behaviour similar to original | ||
LaTeX template, one should consider direct spacing adjacemnt with `v(-1em)` | ||
as follows. | ||
|
||
```typst | ||
#figure( | ||
rect(width: 4.25cm, height: 4.25cm, stroke: 0.4pt), | ||
caption: [Sample figure caption.#v(-1em)], | ||
placement: top, | ||
) | ||
#figure( | ||
rect(width: 4.25cm, height: 4.25cm, stroke: 0.4pt), | ||
caption: [Sample figure caption.], | ||
placement: top, | ||
) | ||
``` | ||
|
||
- Another issue is related to Typst's inablity to produce colored annotation. | ||
In order to mitigte the issue, we add a script which modifies annotations and | ||
make them colored. | ||
|
||
```shell | ||
../colorize-annotations.py \ | ||
example-paper.typst.pdf example-paper-colored.typst.pdf | ||
``` | ||
|
||
See [README.md][3] for details. | ||
|
||
- NeurIPS 2023 instructions discuss bibliography in vague terms. Namely, there | ||
is not specific requirements. Thus we stick to `ieee` bibliography style | ||
since we found it in several accepted papers and it is similar to that in the | ||
example paper. | ||
|
||
- It is unclear how to render notice in the bottom of the title page in case of | ||
final (`accepted: true`) or preprint (`accepted: none`) submission. | ||
|
||
[1]: example-paper.latex.pdf | ||
[2]: example-paper.typst.pdf | ||
[3]: ../#colored-annotations |
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#let kern(length) = h(length, weak: true) | ||
#let TeX = style(styles => { | ||
let e = measure(text("E"), styles) | ||
let T = "T" | ||
let E = text(baseline: e.height / 2, "E") | ||
let X = "X" | ||
box(T + kern(-0.1667em) + E + kern(-0.125em) + X) | ||
}) | ||
#let LaTeX = style(styles => { | ||
let l = measure(text(10pt, "L"), styles) | ||
let a = measure(text(7pt, "A"), styles) | ||
let L = "L" | ||
let A = text(7pt, baseline: a.height - l.height, "A") | ||
box(L + kern(-0.36em) + A + kern(-0.15em) + TeX) | ||
}) | ||
#let LaTeXe = style(styles => { | ||
box(LaTeX + sym.space.sixth + [2#text(baseline: 0.3em, $epsilon$)]) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
@article{alexander1994template, | ||
title={Template-based algorithms for connectionist rule extraction}, | ||
author={Alexander, Jay and Mozer, Michael C}, | ||
journal={Advances in neural information processing systems}, | ||
volume={7}, | ||
year={1994} | ||
} | ||
|
||
@book{bower2012book, | ||
title={The book of GENESIS: exploring realistic neural models with the GEneral NEural SImulation System}, | ||
author={Bower, James M and Beeman, David}, | ||
year={2012}, | ||
publisher={Springer Science \& Business Media} | ||
} | ||
|
||
@article{hasselmo1995dynamics, | ||
title={Dynamics of learning and recall at excitatory recurrent synapses and cholinergic modulation in rat hippocampal region CA3}, | ||
author={Hasselmo, Michael E and Schnell, Eric and Barkai, Edi}, | ||
journal={Journal of Neuroscience}, | ||
volume={15}, | ||
number={7}, | ||
pages={5249--5262}, | ||
year={1995}, | ||
publisher={Soc Neuroscience} | ||
} |
Oops, something went wrong.