Skip to content

Commit

Permalink
Merge branch 'master' into revert-69-patch-3
Browse files Browse the repository at this point in the history
  • Loading branch information
mwouts authored Sep 13, 2018
2 parents 589f85d + 30690ca commit f619fc5
Show file tree
Hide file tree
Showing 13 changed files with 425 additions and 17 deletions.
13 changes: 13 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
Release History
---------------

0.6.5 (2018-09-13)
+++++++++++++++++++

**Improvements**

- Code lines that start with a quotation mark in Jupyter are commented in the
corresponding Python and Julia scripts (#73)
- Update pypy , add flake8 tests on Travis CI (#74)

**BugFixes**

- Import notebook.transutils before notebook.services.contents.filemanager (#75)

0.6.4 (2018-09-12)
+++++++++++++++++++

Expand Down
13 changes: 5 additions & 8 deletions jupytext/cell_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ def uncomment(lines):
for line in lines]


def paragraph_is_fully_commented(lines):
def paragraph_is_fully_commented(lines, main_language):
"""Is the paragraph fully commented?"""
for i, line in enumerate(lines):
if line.startswith('#'):
if line.startswith('# %') and is_magic(line):
if (line.startswith('# %') or line.startswith('# ?')) \
and is_magic(line, main_language):
return False
continue
return i > 0 and _BLANK_LINE.match(line)
Expand Down Expand Up @@ -137,11 +138,6 @@ def metadata_and_language_from_option_line(self, line):
self.language = self.metadata['language']
del self.metadata['language']

def has_explicit_end_marker(self):
"""Should we expect a specific pattern for end of cell?"""

return self.metadata is not None

def find_cell_end_rmd(self, lines):
"""Return position of end of cell marker, and position
of first line after cell"""
Expand Down Expand Up @@ -191,7 +187,8 @@ def find_cell_end_r(self, lines):
def find_cell_end_py(self, lines):
"""Return position of end of cell marker, and position
of first line after cell"""
if self.metadata is None and paragraph_is_fully_commented(lines):
if self.metadata is None and \
paragraph_is_fully_commented(lines, 'python'):
self.cell_type = 'markdown'
for i, line in enumerate(lines):
if _BLANK_LINE.match(line):
Expand Down
5 changes: 3 additions & 2 deletions jupytext/contentsmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
from traitlets import Unicode, Float
from traitlets.config import Configurable

from notebook.services.contents.filemanager import FileContentsManager

# import notebook.transutils before notebook.services.contents.filemanager #75
try:
import notebook.transutils # noqa
except ImportError:
pass

from notebook.services.contents.filemanager import FileContentsManager

import jupytext
from . import combine
from .file_format_version import check_file_version
Expand Down
18 changes: 13 additions & 5 deletions jupytext/magics.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,26 @@
_FORCE_NOT_ESC_RE = re.compile(r"^(# |#)*%(.*)noescape")
_MAGIC_RE = re.compile(r"^(# |#)*(%%|{})".format('|'.join(_LINE_MAGICS)))

# Commands starting with a question marks have to be escaped
_HELP_RE = re.compile(r"^(# |#)*\?")

def is_magic(line):

def is_magic(line, language):
"""Is the current line a (possibly escaped) Jupyter magic?"""
return (_FORCE_ESC_RE.match(line) or (not _FORCE_NOT_ESC_RE.match(line)
and _MAGIC_RE.match(line)))
if _FORCE_ESC_RE.match(line):
return True
if not _FORCE_NOT_ESC_RE.match(line) and _MAGIC_RE.match(line):
return True
if language == 'R':
return False
return _HELP_RE.match(line)


def escape_magic(source, language='python'):
"""Escape Jupyter magics with '# '"""
parser = StringParser(language)
for pos, line in enumerate(source):
if not parser.is_quoted() and is_magic(line):
if not parser.is_quoted() and is_magic(line, language):
source[pos] = '# ' + line
parser.read_line(line)
return source
Expand All @@ -64,7 +72,7 @@ def unescape_magic(source, language='python'):
"""Unescape Jupyter magics"""
parser = StringParser(language)
for pos, line in enumerate(source):
if not parser.is_quoted() and is_magic(line):
if not parser.is_quoted() and is_magic(line, language):
source[pos] = unesc(line)
parser.read_line(line)
return source
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

setup(
name='jupytext',
version='0.6.4',
version='0.6.5',
author='Marc Wouts',
author_email='marc.wouts@gmail.com',
description='Jupyter notebooks as Markdown documents, '
Expand Down
115 changes: 115 additions & 0 deletions tests/mirror/julia_benchmark_plotly_barchart.Rmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
jupyter:
kernelspec:
display_name: Python 3
language: python
name: python3
language_info:
codemirror_mode:
name: ipython
version: 3
file_extension: .py
mimetype: text/x-python
name: python
nbconvert_exporter: python
pygments_lexer: ipython3
version: 3.6.6
---

```{python}
# IJulia rocks! So does Plotly. Check it out
using Plotly
api_key = "" # visit https://plot.ly/api to generate an API username and password
username = ""
Plotly.signin(username, api_key)
```

```{python}
# Following data taken from http://julialang.org/ frontpage
benchmarks = ["fib", "parse_int", "quicksort3", "mandel", "pi_sum", "rand_mat_stat", "rand_mat_mul"]
platforms = ["Fortran", "Julia", "Python", "R", "Matlab", "Mathematica", "Javascript", "Go"]
data = {
platforms[1] => [0.26, 5.03, 1.11, 0.86, 0.80, 0.64, 0.96],
platforms[2] => [0.91, 1.60, 1.14, 0.85, 1.00, 1.66, 1.01],
platforms[3] => [30.37, 13.95, 31.98, 14.19, 16.33, 13.52, 3.41 ],
platforms[4] => [411.36, 59.40, 524.29, 106.97, 15.42, 10.84, 3.98 ],
platforms[5] => [1992.00, 1463.16, 101.84, 64.58, 1.29, 6.61, 1.10 ],
platforms[6] => [64.46, 29.54, 35.74, 6.07, 1.32, 4.52, 1.16 ],
platforms[7] => [2.18, 2.43, 3.51, 3.49, 0.84, 3.28, 14.60],
platforms[8] => [1.03, 4.79, 1.25, 2.36, 1.41, 8.12, 8.51]
}
pdata = [ {"x"=>benchmarks,"y"=>data[k],"bardir"=>"h","type"=>"bar","name"=>k} for k = platforms ]
layout = {
"title"=> "Julia benchmark comparison (smaller is better, C performance = 1.0)",
"barmode"=> "group",
"autosize"=> false,
"width"=> 900,
"height"=> 900,
"titlefont"=>
{
"family"=> "Open Sans",
"size"=> 18,
"color"=> "rgb(84, 39, 143)"
},
"margin"=> {"l"=>160, "pad"=>0},
"xaxis"=> {
"title"=> "Benchmark log-time",
"type"=> "log"
},
"yaxis"=> {"title"=> "Benchmark Name"}
}
response = Plotly.plot(pdata,["layout"=>layout])
# Embed in an iframe within IJulia
s = string("<iframe height='750' id='igraph' scrolling='no' seamless='seamless' src='",
response["url"],
"/700/700' width='750'></iframe>")
display("text/html", s)
```

```{python}
# checkout https://plot.ly/api/ for more Julia examples!
# But to show off some other Plotly features:
x = 1:1500
y1 = sin(2*pi*x/1500.) + rand(1500)-0.5
y2 = sin(2*pi*x/1500.)
fish = {"x"=>x,"y"=> y1,
"type"=>"scatter","mode"=>"markers",
"marker"=>{"color"=>"rgb(0, 0, 255)","opacity"=>0.5 } }
fit = {"x"=> x,"y"=> y2,
"type"=>"scatter", "mode"=>"markers", "opacity"=>0.8,
"marker"=>{"color"=>"rgb(255, 0, 0)"} }
layout = {"autosize"=> false,
"width"=> 650, "height"=> 550,
"title"=>"Fish School",
"xaxis"=>{ "ticks"=> "",
"gridcolor"=> "white",
"zerolinecolor"=> "white",
"linecolor"=> "white",
"autorange"=> false,
"range"=>[0,1500] },
"yaxis"=>{ "ticks"=> "",
"gridcolor"=> "white",
"zerolinecolor"=> "white",
"linecolor"=> "white",
"autorange"=> false,
"range"=>[-2.2,2.2] },
"plot_bgcolor"=> "rgb(245,245,247)",
"showlegend"=> false,
"hovermode"=> "closest"}
response = Plotly.plot([fish, fit],["layout"=>layout])
s = string("<iframe height='750' id='igraph' scrolling='no' seamless='seamless' src='",
response["url"],
"/700/700' width='750'></iframe>")
display("text/html", s)
```
123 changes: 123 additions & 0 deletions tests/mirror/julia_functional_geometry.Rmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
```{julia}
# This notebook is a semi top-down explanation. This cell needs to be
# executed first so that the operators and helper functions are defined
# All of this is explained in the later half of the notebook
using Compose, Interact
Compose.set_default_graphic_size(2inch, 2inch)
points_f = [
(.1, .1),
(.9, .1),
(.9, .2),
(.2, .2),
(.2, .4),
(.6, .4),
(.6, .5),
(.2, .5),
(.2, .9),
(.1, .9),
(.1, .1)
]
f = compose(context(), stroke("black"), line(points_f))
rot(pic) = compose(context(rotation=Rotation(-deg2rad(90))), pic)
flip(pic) = compose(context(mirror=Mirror(deg2rad(90), 0.5w, 0.5h)), pic)
above(m, n, p, q) =
compose(context(),
(context(0, 0, 1, m/(m+n)), p),
(context(0, m/(m+n), 1, n/(m+n)), q))
above(p, q) = above(1, 1, p, q)
beside(m, n, p, q) =
compose(context(),
(context(0, 0, m/(m+n), 1), p),
(context(m/(m+n), 0, n/(m+n), 1), q))
beside(p, q) = beside(1, 1, p, q)
over(p, q) = compose(context(),
(context(), p), (context(), q))
rot45(pic) =
compose(context(0, 0, 1/sqrt(2), 1/sqrt(2),
rotation=Rotation(-deg2rad(45), 0w, 0h)), pic)
# Utility function to zoom out and look at the context
zoomout(pic) = compose(context(),
(context(0.2, 0.2, 0.6, 0.6), pic),
(context(0.2, 0.2, 0.6, 0.6), fill(nothing), stroke("black"), strokedash([0.5mm, 0.5mm]),
polygon([(0, 0), (1, 0), (1, 1), (0, 1)])))
function read_path(p_str)
tokens = [try parsefloat(x) catch symbol(x) end for x in split(p_str, r"[\s,]+")]
path(tokens)
end
fish = compose(context(units=UnitBox(260, 260)), stroke("black"),
read_path(strip(readall("fish.path"))))
rotatable(pic) = @manipulate for θ=0:0.001:2π
compose(context(rotation=Rotation(θ)), pic)
end
blank = compose(context())
fliprot45(pic) = rot45(compose(context(mirror=Mirror(deg2rad(-45))),pic))
# Hide this cell.
display(MIME("text/html"), """<script>
var cell = \$(".container .cell").eq(0), ia = cell.find(".input_area")
if (cell.find(".toggle-button").length == 0) {
ia.after(
\$('<button class="toggle-button">Toggle hidden code</button>').click(
function (){ ia.toggle() }
)
)
ia.hide()
}
</script>""")
```

# Functional Geometry
*Functional Geometry* is a paper by Peter Henderson ([original (1982)](users.ecs.soton.ac.uk/peter/funcgeo.pdf), [revisited (2002)](https://cs.au.dk/~hosc/local/HOSC-15-4-pp349-365.pdf)) which deconstructs the MC Escher woodcut *Square Limit*

![Square Limit](http://i.imgur.com/LjRzmNM.png)


> A picture is an example of a complex object that can be described in terms of its parts.
Yet a picture needs to be rendered on a printer or a screen by a device that expects to
be given a sequence of commands. Programming that sequence of commands directly is
much harder than having an application generate the commands automatically from the
simpler, denotational description.


A `picture` is a *denotation* of something to draw.

e.g. The value of f here denotes the picture of the letter F


Original at http://nbviewer.jupyter.org/github/shashi/ijulia-notebooks/blob/master/funcgeo/Functional%20Geometry.ipynb


## In conclusion

We described Escher's *Square Limit* from the description of its smaller parts, which in turn were described in terms of their smaller parts.

This seemed simple because we chose to talk in terms of an *algebra* to describe pictures. The primitives `rot`, `flip`, `fliprot45`, `above`, `beside` and `over` fit the job perfectly.

We were able to describe these primitves in terms of `compose` `contexts`, which the Compose library knows how to render.

Denotation can be an easy way to describe a system as well as a practical implementation method.

[Abstraction barriers](https://mitpress.mit.edu/sicp/full-text/sicp/book/node29.html) are useful tools that can reduce the cognitive overhead on the programmer. It entails creating layers consisting of functions which only use functions in the same layer or layers below in their own implementation. The layers in our language were:

------------------[ squarelimit ]------------------
-------------[ quartet, cycle, nonet ]-------------
---[ rot, flip, fliprot45, above, beside, over ]---
-------[ compose, context, line, path,... ]--------

Drawing this diagram out is a useful way to begin building any library.

Loading

0 comments on commit f619fc5

Please sign in to comment.