diff --git a/Makefile b/Makefile index b5dfe2fa..9300ee0c 100644 --- a/Makefile +++ b/Makefile @@ -6,10 +6,10 @@ MAKEFILES=Makefile $(wildcard *.mk) JEKYLL=jekyll PARSER=bin/markdown_ast.rb DST=_site +JUPYTER=jupyter # Controls .PHONY : commands clean files -.NOTPARALLEL: all : commands ## commands : show all commands. @@ -17,11 +17,11 @@ commands : @grep -h -E '^##' ${MAKEFILES} | sed -e 's/## //g' ## serve : run a local server. -serve : lesson-md +serve : lesson-rmd lesson-jupyter ${JEKYLL} serve ## site : build files but do not run a server. -site : lesson-md +site : lesson-rmd lesson-jupyter ${JEKYLL} build # repo-check : check repository settings. @@ -54,12 +54,16 @@ workshop-check : ## ---------------------------------------- ## Commands specific to lesson websites. -.PHONY : lesson-check lesson-md lesson-files lesson-fixme +.PHONY : lesson-check lesson-rmd lesson-files lesson-fixme # RMarkdown files RMD_SRC = $(wildcard _episodes_rmd/??-*.Rmd) RMD_DST = $(patsubst _episodes_rmd/%.Rmd,_episodes/%.md,$(RMD_SRC)) +# JUPYTER files +JUPYTER_SRC = $(wildcard _episodes_ipynb/??-*.ipynb) +JUPYTER_DST = $(patsubst _episodes_ipynb/%.ipynb,_episodes/%.ipynb,$(JUPYTER_SRC)) + # Lesson source files in the order they appear in the navigation menu. MARKDOWN_SRC = \ index.md \ @@ -80,16 +84,17 @@ HTML_DST = \ $(patsubst _extras/%.md,${DST}/%/index.html,$(wildcard _extras/*.md)) \ ${DST}/license/index.html -## lesson-md : convert Rmarkdown files to markdown -lesson-md : ${RMD_DST} +## lesson-rmd : convert Rmarkdown files to markdown +lesson-rmd: $(RMD_SRC) + @bin/knit_lessons.sh $(RMD_SRC) -# Use of .NOTPARALLEL makes rule execute only once -${RMD_DST} : ${RMD_SRC} - @bin/knit_lessons.sh ${RMD_SRC} +## lesson-jupyter : convert Jupyter Notebook files to markdown +lesson-jupyter: $(JUPYTER_SRC) + ${JUPYTER} nbconvert -y --execute --allow-errors --to markdown --output-dir=_episodes --NbConvertApp.output_files_dir="" --template=_layouts/ipynb2md.tpl $(JUPYTER_SRC) ## lesson-check : validate lesson Markdown. lesson-check : - @bin/lesson_check.py -s . -p ${PARSER} -r _includes/links.md + @bin/lesson_check.py -s . -p ${PARSER} ## lesson-check-all : validate lesson Markdown, checking line lengths and trailing whitespace. lesson-check-all : diff --git a/_config.yml b/_config.yml index cc650eec..1fb2afaf 100644 --- a/_config.yml +++ b/_config.yml @@ -67,3 +67,6 @@ exclude: # Turn off built-in syntax highlighting. highlighter: false + +kramdown: + parse_block_html: true diff --git a/_episodes/07-jupyter.md b/_episodes/07-jupyter.md new file mode 100644 index 00000000..b801914d --- /dev/null +++ b/_episodes/07-jupyter.md @@ -0,0 +1,111 @@ +--- +title: Using Jupyter Notebook +teaching: 10 +exercises: 1 +questions: +- "How to write a lesson using Jupyter Notebook?" +objectives: +- "Explain how to use Jupyter Notebook with the new lesson template." +- "Demonstrate how to include pieces of code, figures, and challenges." +keypoints: +- "It shouldn't be difficult" +--- + +The lesson should be written with a mix of code cells and Markdown cells, +just like you'd normally do. + + +~~~ +1 + 1 +~~~ +{: .source .python} + + + +~~~ +2 +~~~ +{: .output} + + +Output with error message: + + +~~~ +x[10] +~~~ +{: .source .python} + +~~~ +--------------------------------------------------------------------------- +NameError Traceback (most recent call last) + in () +----> 1 x[10] + +NameError: name 'x' is not defined +~~~ +{: .error} +Output generating figures: + + +~~~ +% matplotlib inline +~~~ +{: .source .python} + + +~~~ +import matplotlib.pyplot + +matplotlib.pyplot.plot([1,2,3], [1,2,3]) +~~~ +{: .source .python} + + + +~~~ +[] +~~~ +{: .output} + + + + +![png](../07-jupyter_6_1.png) + +For the challenges you need to pay attention +to include `
` before it +and `<\blockquote>` after it. +And for the solutions you need to pay attention +to include `
` before it +and `<\blockquote>` after it. +**This hacks is necessary for allow include Jupyter cells on challenges and solutions.** +
+## Challenge: Can you do it? + +What is the output of this command? + +~~~ +"a" + "b" +~~~ +{: .source} + +
+## Solution + + +~~~ +"a" + "b" +~~~ +{: .source .python} + + + +~~~ +'ab' +~~~ +{: .output} + + +
+
diff --git a/_episodes/07-jupyter_6_1.png b/_episodes/07-jupyter_6_1.png new file mode 100644 index 00000000..5058f764 Binary files /dev/null and b/_episodes/07-jupyter_6_1.png differ diff --git a/_episodes/07-maintenance.md b/_episodes/08-maintenance.md similarity index 100% rename from _episodes/07-maintenance.md rename to _episodes/08-maintenance.md diff --git a/_episodes/08-coffee.md b/_episodes/09-coffee.md similarity index 100% rename from _episodes/08-coffee.md rename to _episodes/09-coffee.md diff --git a/_episodes_ipynb/07-jupyter.ipynb b/_episodes_ipynb/07-jupyter.ipynb new file mode 100644 index 00000000..b91d31a1 --- /dev/null +++ b/_episodes_ipynb/07-jupyter.ipynb @@ -0,0 +1,214 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "title: Using Jupyter Notebook \n", + "teaching: 10\n", + "exercises: 1\n", + "questions:\n", + "- \"How to write a lesson using Jupyter Notebook?\"\n", + "objectives:\n", + "- \"Explain how to use Jupyter Notebook with the new lesson template.\"\n", + "- \"Demonstrate how to include pieces of code, figures, and challenges.\"\n", + "keypoints:\n", + "- \"It shouldn't be difficult\"\n", + "---\n", + "\n", + "The lesson should be written with a mix of code cells and Markdown cells,\n", + "just like you'd normally do." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1.15000000000000" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1 + 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Output with error message:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "TypeError", + "evalue": "'sage.symbolic.expression.Expression' object does not support indexing", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mx\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mInteger\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m: 'sage.symbolic.expression.Expression' object does not support indexing" + ] + } + ], + "source": [ + "x[10]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Output generating figures:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "% matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\nAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot\n", + "\n", + "matplotlib.pyplot.plot([1,2,3], [1,2,3])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For the challenges you need to pay attention\n", + "to include `
` before it\n", + "and `<\\blockquote>` after it.\n", + "And for the solutions you need to pay attention\n", + "to include `
` before it\n", + "and `<\\blockquote>` after it.\n", + "**This hacks is necessary for allow include Jupyter cells on challenges and solutions.**" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "
\n", + "## Challenge: Can you do it?\n", + "\n", + "What is the output of this command?\n", + "\n", + "~~~\n", + "\"a\" + \"b\"\n", + "~~~\n", + "{: .source}\n", + "\n", + "
\n", + "## Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'ab'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"a\" + \"b\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
" + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python [default]", + "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.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/_layouts/ipynb2md.tpl b/_layouts/ipynb2md.tpl new file mode 100644 index 00000000..805dc2b3 --- /dev/null +++ b/_layouts/ipynb2md.tpl @@ -0,0 +1,78 @@ +{% extends 'display_priority.tpl' %} + + +{% block in_prompt %} +{% endblock in_prompt %} + +{% block output_prompt %} +{%- endblock output_prompt %} + +{% block input %} +~~~ +{{ cell.source}} +~~~ +{: .source {% if nb.metadata.language_info %}.{{ nb.metadata.language_info.name }}{% endif %}} +{% endblock input %} + +{% block error %} +~~~ +{{- super()|replace("\n\n", "\n")|replace(" ", "") -}} +~~~ +{: .error} +{% endblock error %} + +{% block traceback_line %} +{{ line | indent | strip_ansi }} +{% endblock traceback_line %} + +{% block execute_result %} +{% block data_priority scoped %} +{{ super() }} +{% endblock %} +{% endblock execute_result %} + +{% block stream %} +~~~ +{{ output.text }} +~~~ +{: .output} +{% endblock stream %} + +{% block data_svg %} +![svg](../{{ output.metadata.filenames['image/svg+xml'] | path2url }}) +{% endblock data_svg %} + +{% block data_png %} +![png](../{{ output.metadata.filenames['image/png'] | path2url }}) +{% endblock data_png %} + +{% block data_jpg %} +![jpeg](../{{ output.metadata.filenames['image/jpeg'] | path2url }}) +{% endblock data_jpg %} + +{% block data_latex %} +{{ output.data['text/latex'] }} +{% endblock data_latex %} + +{% block data_html scoped %} +{{ output.data['text/html'] }} +{% endblock data_html %} + +{% block data_markdown scoped %} +{{ output.data['text/markdown'] }} +{% endblock data_markdown %} + +{% block data_text scoped %} +~~~ +{{ output.data['text/plain'] }} +~~~ +{: .output} +{% endblock data_text %} + +{%- block markdowncell scoped -%} +{{ cell.source }} +{% endblock markdowncell %} + +{% block unknowncell scoped %} +unknown type {{ cell.type }} +{% endblock unknowncell %}