{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Fastpages Notebook Blog Post\n", "> A tutorial of fastpages for Jupyter notebooks.\n", "\n", "- toc: true \n", "- badges: true\n", "- comments: true\n", "- categories: [jupyter]\n", "- image: images/chart-preview.png" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# About\n", "\n", "This notebook is a demonstration of some of capabilities of [fastpages](https://github.com/fastai/fastpages) with notebooks.\n", "\n", "\n", "With `fastpages` you can save your jupyter notebooks into the `_notebooks` folder at the root of your repository, and they will be automatically be converted to Jekyll compliant blog posts!\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Front Matter\n", "\n", "The first cell in your Jupyter Notebook or markdown blog post contains front matter. Front matter is metadata that can turn on/off options in your Notebook. It is formatted like this:\n", "\n", "```\n", "# Title\n", "> Awesome summary\n", "\n", "- toc: true- branch: master- badges: true\n", "- comments: true\n", "- author: Hamel Husain & Jeremy Howard\n", "- categories: [fastpages, jupyter]\n", "```\n", "\n", "- Setting `toc: true` will automatically generate a table of contents\n", "- Setting `badges: true` will automatically include GitHub and Google Colab links to your notebook.\n", "- Setting `comments: true` will enable commenting on your blog post, powered by [utterances](https://github.com/utterance/utterances).\n", "\n", "More details and options for front matter can be viewed on the [front matter section](https://github.com/fastai/fastpages#front-matter-related-options) of the README." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Markdown Shortcuts" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A `#hide` comment at the top of any code cell will hide **both the input and output** of that cell in your blog post.\n", "\n", "A `#hide_input` comment at the top of any code cell will **only hide the input** of that cell." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The comment #hide_input was used to hide the code that produced this.\n" ] } ], "source": [ "#hide_input\n", "print('The comment #hide_input was used to hide the code that produced this.')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "put a `#collapse-hide` flag at the top of any cell if you want to **hide** that cell by default, but give the reader the option to show it:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "#collapse-hide\n", "import pandas as pd\n", "import altair as alt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "put a `#collapse-show` flag at the top of any cell if you want to **show** that cell by default, but give the reader the option to hide it:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "#collapse-show\n", "cars = 'https://vega.github.io/vega-datasets/data/cars.json'\n", "movies = 'https://vega.github.io/vega-datasets/data/movies.json'\n", "sp500 = 'https://vega.github.io/vega-datasets/data/sp500.csv'\n", "stocks = 'https://vega.github.io/vega-datasets/data/stocks.csv'\n", "flights = 'https://vega.github.io/vega-datasets/data/flights-5k.json'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Interactive Charts With Altair\n", "\n", "Charts made with Altair remain interactive. Example charts taken from [this repo](https://github.com/uwdata/visualization-curriculum), specifically [this notebook](https://github.com/uwdata/visualization-curriculum/blob/master/altair_interaction.ipynb)." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# hide\n", "df = pd.read_json(movies) # load movies data\n", "genres = df['Major_Genre'].unique() # get unique field values\n", "genres = list(filter(lambda d: d is not None, genres)) # filter out None values\n", "genres.sort() # sort alphabetically" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "#hide\n", "mpaa = ['G', 'PG', 'PG-13', 'R', 'NC-17', 'Not Rated']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example 1: DropDown" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", "" ], "text/plain": [ "alt.Chart(...)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# single-value selection over [Major_Genre, MPAA_Rating] pairs\n", "# use specific hard-wired values as the initial selected values\n", "selection = alt.selection_single(\n", " name='Select',\n", " fields=['Major_Genre', 'MPAA_Rating'],\n", " init={'Major_Genre': 'Drama', 'MPAA_Rating': 'R'},\n", " bind={'Major_Genre': alt.binding_select(options=genres), 'MPAA_Rating': alt.binding_radio(options=mpaa)}\n", ")\n", " \n", "# scatter plot, modify opacity based on selection\n", "alt.Chart(movies).mark_circle().add_selection(\n", " selection\n", ").encode(\n", " x='Rotten_Tomatoes_Rating:Q',\n", " y='IMDB_Rating:Q',\n", " tooltip='Title:N',\n", " opacity=alt.condition(selection, alt.value(0.75), alt.value(0.05))\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example 2: Tooltips" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", "" ], "text/plain": [ "alt.Chart(...)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "alt.Chart(movies).mark_circle().add_selection(\n", " alt.selection_interval(bind='scales', encodings=['x'])\n", ").encode(\n", " x='Rotten_Tomatoes_Rating:Q',\n", " y=alt.Y('IMDB_Rating:Q', axis=alt.Axis(minExtent=30)), # use min extent to stabilize axis title placement\n", " tooltip=['Title:N', 'Release_Date:N', 'IMDB_Rating:Q', 'Rotten_Tomatoes_Rating:Q']\n", ").properties(\n", " width=600,\n", " height=400\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example 3: More Tooltips" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "\n", "
\n", "" ], "text/plain": [ "alt.LayerChart(...)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# select a point for which to provide details-on-demand\n", "label = alt.selection_single(\n", " encodings=['x'], # limit selection to x-axis value\n", " on='mouseover', # select on mouseover events\n", " nearest=True, # select data point nearest the cursor\n", " empty='none' # empty selection includes no data points\n", ")\n", "\n", "# define our base line chart of stock prices\n", "base = alt.Chart().mark_line().encode(\n", " alt.X('date:T'),\n", " alt.Y('price:Q', scale=alt.Scale(type='log')),\n", " alt.Color('symbol:N')\n", ")\n", "\n", "alt.layer(\n", " base, # base line chart\n", " \n", " # add a rule mark to serve as a guide line\n", " alt.Chart().mark_rule(color='#aaa').encode(\n", " x='date:T'\n", " ).transform_filter(label),\n", " \n", " # add circle marks for selected time points, hide unselected points\n", " base.mark_circle().encode(\n", " opacity=alt.condition(label, alt.value(1), alt.value(0))\n", " ).add_selection(label),\n", "\n", " # add white stroked text to provide a legible background for labels\n", " base.mark_text(align='left', dx=5, dy=-5, stroke='white', strokeWidth=2).encode(\n", " text='price:Q'\n", " ).transform_filter(label),\n", "\n", " # add text labels for stock prices\n", " base.mark_text(align='left', dx=5, dy=-5).encode(\n", " text='price:Q'\n", " ).transform_filter(label),\n", " \n", " data=stocks\n", ").properties(\n", " width=700,\n", " height=400\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Data Tables\n", "\n", "You can display tables per the usual way in your blog:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
TitleWorldwide_GrossProduction_BudgetDistributorMPAA_RatingIMDB_RatingRotten_Tomatoes_Rating
0The Land Girls146083.08000000.0GramercyR6.1NaN
1First Love, Last Rites10876.0300000.0StrandR6.9NaN
2I Married a Strange Person203134.0250000.0LionsgateNone6.8NaN
3Let's Talk About Sex373615.0300000.0Fine LineNoneNaN13.0
4Slam1087521.01000000.0TrimarkR3.462.0
\n", "
" ], "text/plain": [ " Title Worldwide_Gross Production_Budget Distributor \\\n", "0 The Land Girls 146083.0 8000000.0 Gramercy \n", "1 First Love, Last Rites 10876.0 300000.0 Strand \n", "2 I Married a Strange Person 203134.0 250000.0 Lionsgate \n", "3 Let's Talk About Sex 373615.0 300000.0 Fine Line \n", "4 Slam 1087521.0 1000000.0 Trimark \n", "\n", " MPAA_Rating IMDB_Rating Rotten_Tomatoes_Rating \n", "0 R 6.1 NaN \n", "1 R 6.9 NaN \n", "2 None 6.8 NaN \n", "3 None NaN 13.0 \n", "4 R 3.4 62.0 " ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "movies = 'https://vega.github.io/vega-datasets/data/movies.json'\n", "df = pd.read_json(movies)\n", "# display table with pandas\n", "df[['Title', 'Worldwide_Gross', \n", " 'Production_Budget', 'Distributor', 'MPAA_Rating', 'IMDB_Rating', 'Rotten_Tomatoes_Rating']].head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Images\n", "\n", "### Local Images\n", "\n", "You can reference local images and they will be copied and rendered on your blog automatically. You can include these with the following markdown syntax:\n", "\n", "`![](my_icons/fastai_logo.png)`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![](my_icons/fastai_logo.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Remote Images\n", "\n", "Remote images can be included with the following markdown syntax:\n", "\n", "`![](https://image.flaticon.com/icons/svg/36/36686.svg)`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![](https://image.flaticon.com/icons/svg/36/36686.svg)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Animated Gifs\n", "\n", "Animated Gifs work, too!\n", "\n", "`![](https://upload.wikimedia.org/wikipedia/commons/7/71/ChessPawnSpecialMoves.gif)`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![](https://upload.wikimedia.org/wikipedia/commons/7/71/ChessPawnSpecialMoves.gif)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Captions\n", "\n", "You can include captions with markdown images like this:\n", "\n", "```\n", "![](https://www.fast.ai/images/fastai_paper/show_batch.png \"Credit: https://www.fast.ai/2020/02/13/fastai-A-Layered-API-for-Deep-Learning/\")\n", "```\n", "\n", "\n", "![](https://www.fast.ai/images/fastai_paper/show_batch.png \"Credit: https://www.fast.ai/2020/02/13/fastai-A-Layered-API-for-Deep-Learning/\")\n", "\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Other Elements" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tweetcards\n", "\n", "Typing `> twitter: https://twitter.com/jakevdp/status/1204765621767901185?s=20` will render this:\n", "\n", "> twitter: https://twitter.com/jakevdp/status/1204765621767901185?s=20" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Youtube Videos\n", "\n", "Typing `> youtube: https://youtu.be/XfoYk_Z5AkI` will render this:\n", "\n", "\n", "> youtube: https://youtu.be/XfoYk_Z5AkI" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Boxes / Callouts \n", "\n", "Typing `> Warning: There will be no second warning!` will render this:\n", "\n", "\n", "> Warning: There will be no second warning!\n", "\n", "\n", "\n", "Typing `> Important: Pay attention! It's important.` will render this:\n", "\n", "> Important: Pay attention! It's important.\n", "\n", "\n", "\n", "Typing `> Tip: This is my tip.` will render this:\n", "\n", "> Tip: This is my tip.\n", "\n", "\n", "\n", "Typing `> Note: Take note of this.` will render this:\n", "\n", "> Note: Take note of this.\n", "\n", "\n", "\n", "Typing `> Note: A doc link to [an example website: fast.ai](https://www.fast.ai/) should also work fine.` will render in the docs:\n", "\n", "> Note: A doc link to [an example website: fast.ai](https://www.fast.ai/) should also work fine." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Footnotes\n", "\n", "You can have footnotes in notebooks, however the syntax is different compared to markdown documents. [This guide provides more detail about this syntax](https://github.com/fastai/fastpages/blob/master/_fastpages_docs/NOTEBOOK_FOOTNOTES.md), which looks like this:\n", "\n", "```\n", "{% raw %}For example, here is a footnote {% fn 1 %}.\n", "And another {% fn 2 %}\n", "{{ 'This is the footnote.' | fndetail: 1 }}\n", "{{ 'This is the other footnote. You can even have a [link](www.github.com)!' | fndetail: 2 }}{% endraw %}\n", "```\n", "\n", "For example, here is a footnote {% fn 1 %}.\n", "\n", "And another {% fn 2 %}\n", "\n", "{{ 'This is the footnote.' | fndetail: 1 }}\n", "{{ 'This is the other footnote. You can even have a [link](www.github.com)!' | fndetail: 2 }}" ] } ], "metadata": { "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.3" } }, "nbformat": 4, "nbformat_minor": 4 }