From c05b1441d2ef674481a3de94e83dc2e5866376d1 Mon Sep 17 00:00:00 2001 From: dcherian Date: Thu, 23 Jun 2022 16:23:43 -0600 Subject: [PATCH] Update plotting notebooks - use "air_temperature_gradient" dataset - delete older plotting notebook --- fundamentals/04.1_basic_plotting.ipynb | 9 +- fundamentals/04.2_faceting.ipynb | 9 +- fundamentals/04.3_geographic_plotting.ipynb | 2 +- .../04_plotting_and_visualization.ipynb | 706 ------------------ 4 files changed, 3 insertions(+), 723 deletions(-) delete mode 100644 fundamentals/04_plotting_and_visualization.ipynb diff --git a/fundamentals/04.1_basic_plotting.ipynb b/fundamentals/04.1_basic_plotting.ipynb index 48dd5cd5..c5bf1aa3 100644 --- a/fundamentals/04.1_basic_plotting.ipynb +++ b/fundamentals/04.1_basic_plotting.ipynb @@ -46,14 +46,7 @@ "metadata": {}, "outputs": [], "source": [ - "ds = xr.tutorial.open_dataset(\"air_temperature.nc\").rename({\"air\": \"Tair\"})\n", - "\n", - "# we will add a gradient field with appropriate attributes\n", - "ds[\"dTdx\"] = ds.Tair.differentiate(\"lon\") / 110e3 / np.cos(ds.lat * np.pi / 180)\n", - "ds[\"dTdy\"] = ds.Tair.differentiate(\"lat\") / 105e3\n", - "ds.dTdx.attrs = {\"long_name\": \"$∂T/∂x$\", \"units\": \"°C/m\"}\n", - "ds.dTdy.attrs = {\"long_name\": \"$∂T/∂y$\", \"units\": \"°C/m\"}\n", - "\n", + "ds = xr.tutorial.open_dataset(\"air_temperature_gradient\")\n", "ds" ] }, diff --git a/fundamentals/04.2_faceting.ipynb b/fundamentals/04.2_faceting.ipynb index 3387a68f..c052cd79 100644 --- a/fundamentals/04.2_faceting.ipynb +++ b/fundamentals/04.2_faceting.ipynb @@ -40,14 +40,7 @@ "metadata": {}, "outputs": [], "source": [ - "ds = xr.tutorial.open_dataset(\"air_temperature.nc\").rename({\"air\": \"Tair\"})\n", - "\n", - "# we will add a gradient field with appropriate attributes\n", - "ds[\"dTdx\"] = ds.Tair.differentiate(\"lon\") / 110e3 / np.cos(ds.lat * np.pi / 180)\n", - "ds[\"dTdy\"] = ds.Tair.differentiate(\"lat\") / 105e3\n", - "ds.dTdx.attrs = {\"long_name\": \"$∂T/∂x$\", \"units\": \"°C/m\"}\n", - "ds.dTdy.attrs = {\"long_name\": \"$∂T/∂y$\", \"units\": \"°C/m\"}\n", - "\n", + "ds = xr.tutorial.open_dataset(\"air_temperature_gradient\")\n", "monthly_means = ds.groupby(\"time.month\").mean()\n", "# xarray's groupby reductions drop attributes. Let's assign them back so we get nice labels.\n", "monthly_means.Tair.attrs = ds.Tair.attrs" diff --git a/fundamentals/04.3_geographic_plotting.ipynb b/fundamentals/04.3_geographic_plotting.ipynb index 9ea70300..25fcb52a 100644 --- a/fundamentals/04.3_geographic_plotting.ipynb +++ b/fundamentals/04.3_geographic_plotting.ipynb @@ -41,7 +41,7 @@ "metadata": {}, "outputs": [], "source": [ - "ds = xr.tutorial.open_dataset(\"air_temperature.nc\").rename({\"air\": \"Tair\"})\n", + "ds = xr.tutorial.open_dataset(\"air_temperature_gradient\")\n", "monthly_means = ds.groupby(\"time.month\").mean()\n", "# xarray's groupby reductions drop attributes. Let's assign them back so we get nice labels.\n", "monthly_means.Tair.attrs = ds.Tair.attrs" diff --git a/fundamentals/04_plotting_and_visualization.ipynb b/fundamentals/04_plotting_and_visualization.ipynb deleted file mode 100644 index 4ba7dfde..00000000 --- a/fundamentals/04_plotting_and_visualization.ipynb +++ /dev/null @@ -1,706 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "toc": true - }, - "source": [ - "\n", - "\n", - "# Plotting and Visualization\n", - "\n", - "At the end of this lesson you will learn:\n", - "\n", - "1. how to use xarray's convenient matplotlib-backed plotting interface to\n", - " visualize your datasets.\n", - "2. that `hvplot` provides an equally convenient interface for bokeh-backed plots\n", - "\n", - "## Table of contents\n", - "\n", - "1. [Basic plotting](#basic)\n", - "1. [Histograms](#hist)\n", - "1. [2D plots](#2d)\n", - "1. [1D line plots](#1d)\n", - "1. [Faceting or multiple subplots](#facet)\n", - "1. [Geography: matplotlib and cartopy](#geo)\n", - "1. [Interactive bokeh plots using hvplot](#bokeh)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib as mpl\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import xarray as xr" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "xr.set_options(display_style=\"html\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Load data\n", - "\n", - "First let's load up a tutorial dataset to visualize.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ds = xr.tutorial.open_dataset(\"air_temperature.nc\").rename({\"air\": \"Tair\"})\n", - "\n", - "# we will add a gradient field with appropriate attributes\n", - "ds[\"dTdx\"] = ds.Tair.differentiate(\"lon\") / 110e3 / np.cos(ds.lat * np.pi / 180)\n", - "ds[\"dTdy\"] = ds.Tair.differentiate(\"lat\") / 105e3\n", - "ds.dTdx.attrs = {\"long_name\": \"$∂T/∂x$\", \"units\": \"°C/m\"}\n", - "ds.dTdy.attrs = {\"long_name\": \"$∂T/∂y$\", \"units\": \"°C/m\"}\n", - "\n", - "ds" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This dataset has three \"data variables\", `Tair` is air temperature and `dTdx`\n", - "and `dTdy` are horizontal gradients of this temperature field. All three \"data\n", - "variables\" are three-dimensional with dimensions `(time, lat, lon)`.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "\n", - "## Basic plotting: .plot()\n", - "\n", - "DataArray objects have a `plot` method. This method creates plots using\n", - "`matplotlib` so all of your existing matplotlib knowledge carries over!\n", - "\n", - "By default `.plot()` makes\n", - "\n", - "1. a line plot for 1-D arrays using `plt.plot()`\n", - "2. a `pcolormesh` plot for 2-D arrays using `plt.pcolormesh()`\n", - "3. a histogram for everything else using `plt.hist()`\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "\n", - "## Histograms\n", - "\n", - "`Tair` is three-dimensional, so we got a histogram of temperature values. Notice\n", - "the label on the x-axis. One of xarray's convenient plotting features is that it\n", - "uses the `attrs` of `Tair` to nicely label axes and colorbars.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ds.Tair.plot()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can pass extra arguments to the underlying `hist()` call. See the matplotlib\n", - "docs (https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.hist.html) for\n", - "all possible keyword arguments.\n", - "\n", - "**Tip:** Note that the returned values are exactly what matplotlib would return\n", - "\n", - "### Exercise\n", - "\n", - "Update the above plot to show 50 bins with unfilled steps instead of filled\n", - "bars.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "\n", - "## 2D plots\n", - "\n", - "Now we will explore 2D plots. Let's select a single timestep of `Tair` to\n", - "visualize.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ds.Tair.isel(time=1).plot()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice how much information is on that plot!\n", - "\n", - "The x- and y-axes are labeled with full names — \"Latitude\", \"Longitude\" — along\n", - "with units. The colorbar has a nice label, again with units. And the title tells\n", - "us the timestamp of the data presented.\n", - "\n", - "`plot` takes many keyword arguments and is quite sophisticated (see\n", - "https://xarray.pydata.org/en/stable/generated/xarray.plot.pcolormesh.html).\n", - "\n", - "Here is a more complicated figure that explicitly sets `time` as the x-axis,\n", - "customizes the colorbar, and overlays two contours at specific levels.\n", - "\n", - "**Tip:** Other options for 2D plots include `.plot.contour`, `.plot.contourf`,\n", - "`.plot.imshow`\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ds.Tair.isel(lon=1).plot(\n", - " x=\"time\", # coordinate to plot on the x-axis of the plot\n", - " robust=True, # set colorbar limits to 2nd and 98th percentile of data\n", - " cbar_kwargs={\n", - " \"orientation\": \"horizontal\",\n", - " \"label\": \"custom label\",\n", - " \"pad\": 0.2,\n", - " }, # passed to plt.colorbar\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise\n", - "\n", - "Update the above plot to use a different matplotlib colormap.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise\n", - "\n", - "Now overlay a contour plot on top of the previous plot\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "\n", - "## 1D line plots\n", - "\n", - "xarray is also able to plot lines by wrapping `plt.plot()`. As in the earlier\n", - "examples, the axes are labelled and keyword arguments can be passed to the\n", - "underlying `matplotlib` call.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ds.Tair.isel(time=1, lon=10).plot(marker=\"o\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Lets say we want to compare line plots of temperature at three different\n", - "latitudes. We can use the `hue` kwarg to do this.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ds.Tair.isel(time=1).sel(lat=[40, 50, 60], method=\"nearest\").plot(x=\"lon\", hue=\"lat\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Customization\n", - "\n", - "All of xarray's plotting functions take an large list kwargs that customize\n", - "behaviour. A full list can be seen here:\n", - "https://xarray.pydata.org/en/stable/generated/xarray.plot.pcolormesh.html. That\n", - "said xarray does not wrap all matplotlib functionality.\n", - "\n", - "The general strategy for making plots that are more complicated that the\n", - "examples above is\n", - "\n", - "1. Create a matplotlib axis `ax`\n", - "2. Use xarray to make a close approximation of the final plot specifying\n", - " `ax=ax`.\n", - "3. Use `ax` methods to fully customize the plot\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "\n", - "## Faceting\n", - "\n", - "Faceting is the art of presenting \"small multiples\" of the data. It is an\n", - "effective way of visualizing variations of 3D data where 2D slices are\n", - "visualized in a panel (subplot) and the third dimensions is varied between\n", - "panels (subplots).\n", - "\n", - "Here is where xarray really augments matplotlib's functionality. We will use\n", - "monthly means to illustrate\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "monthly_means = ds.groupby(\"time.month\").mean()\n", - "# xarray's groupby reductions drop attributes. Let's assign them back so we get nice labels.\n", - "monthly_means.Tair.attrs = ds.Tair.attrs\n", - "monthly_means" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that the dimensions are now `lat, lon, month`.\n", - "\n", - "We want to visualize how the monthly mean air temperature varies with month of\n", - "the year.\n", - "\n", - "The simplest way to facet is to specify the `row` or `col` kwargs which are\n", - "expected to be a dimension name. Here we use `month` so that each panel or\n", - "\"facet\" of the plot presents the mean temperature field in a given month. Since\n", - "a 12 column plot would be too small to interpret, we can \"wrap\" the facets into\n", - "multiple rows using `col_wrap`\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fg = monthly_means.Tair.plot(\n", - " col=\"month\",\n", - " col_wrap=4, # each row has a maximum of 4 columns\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "All the usual customizations are possible\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fg = monthly_means.Tair.plot(\n", - " col=\"month\",\n", - " col_wrap=4,\n", - " # The remaining kwargs customize the plot just as for not-faceted plots\n", - " robust=True,\n", - " cmap=mpl.cm.RdYlBu_r,\n", - " cbar_kwargs={\n", - " \"orientation\": \"horizontal\",\n", - " \"shrink\": 0.8,\n", - " \"aspect\": 40,\n", - " \"pad\": 0.1,\n", - " },\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The returned FacetGrid object `fg` has many useful properties and methods e.g.\n", - "\n", - "1. `fg.fig` provides a handle to the figure\n", - "2. `fg.axes` is a numpy object array with handles to each individual axes\n", - "3. `fg.set_xlabels` and `fg.set_ylabels` can be used to change axes labels.\n", - "\n", - "See https://xarray.pydata.org/en/stable/api.html#faceting for a full list.\n", - "\n", - "### Exercise\n", - "\n", - "Use these methods to set a title for the figure using `suptitle`, as well as\n", - "change the x- and y-labels.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fg" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Modifying all facets of a plot\n", - "\n", - "The FacetGrid object has some more advanced methods that let you customize the\n", - "plot further.\n", - "\n", - "Here we illustrate the use of `map` and `map_dataarray` that let you map custom\n", - "plotting functions to an existing `FacetGrid`. The functions passed to `map` and\n", - "`map_dataarray` must have a particular signature. See the docstring for more\n", - "details.\n", - "\n", - "Alternatively one can loop over `fg.axes` and modify each individual subplot as\n", - "needed\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fg = monthly_means.Tair.plot(col=\"month\", col_wrap=4)\n", - "\n", - "# Use this to plot contours on each panel\n", - "# Note that this plotting call uses the original DataArray gradients\n", - "fg.map_dataarray(xr.plot.contour, x=\"lon\", y=\"lat\", colors=\"k\", levels=13, add_colorbar=False)\n", - "\n", - "# Add a point (or anything else!)\n", - "fg.map(lambda: plt.plot(250, 40, markersize=20, marker=\".\", color=\"w\"))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Faceting tip: Use faceting to plot multiple DataArrays\n", - "\n", - "Faceting can be used to plot multiple DataArrays in a Dataset. The trick is to\n", - "use `to_array()` to convert a Dataset to a DataArray and then facet that.\n", - "\n", - "This trick only works when it is sensible to use the same colormap and color\n", - "scale for all DataArrays like with `dTdx` and `dTdy`\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "gradients = monthly_means[[\"dTdx\", \"dTdy\"]].to_array(\"gradient\")\n", - "gradients" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fg = gradients.isel(month=slice(None, None, 3)).plot.contourf(\n", - " levels=13,\n", - " col=\"month\",\n", - " row=\"gradient\",\n", - " robust=True,\n", - " cmap=mpl.cm.coolwarm,\n", - " cbar_kwargs={\n", - " \"orientation\": \"horizontal\",\n", - " \"shrink\": 0.8,\n", - " \"aspect\": 40,\n", - " \"label\": \"Gradient [°C/m]\",\n", - " },\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "\n", - "## Geography: Matplotlib and Cartopy\n", - "\n", - "Since xarray's default plotting functionality builds on matplotlib, we can\n", - "seamlessly use cartopy to make nice maps:\n", - "\n", - "1. Specify a `projection` for the plot when creating a new figure `fig` with\n", - " axis `axis`.\n", - "2. Explicitly ask xarray to plot to axis `axis` by passing the kwarg `ax=axis`.\n", - "3. Specify the projection of the data using `transform` (`PlateCarree` here) in\n", - " `.plot()`.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import cartopy.crs as ccrs\n", - "\n", - "fig, axis = plt.subplots(1, 1, subplot_kw=dict(projection=ccrs.Orthographic(-90, 30)))\n", - "\n", - "ds.Tair.isel(time=1).plot(\n", - " ax=axis,\n", - " transform=ccrs.PlateCarree(), # this is important!\n", - " # usual xarray stuff\n", - " cbar_kwargs={\"orientation\": \"horizontal\", \"shrink\": 0.7},\n", - " robust=True,\n", - ")\n", - "axis.coastlines() # cartopy function" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Faceting maps\n", - "\n", - "We can make faceted maps. Since `FacetGrid` creates the axes it plots to, we\n", - "need to pass the `projection` kwarg in `subplot_kws`. This makes sure that the\n", - "subplots are set up properly for cartopy.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fg = monthly_means.Tair.isel(month=[1, 2, 3]).plot(\n", - " col=\"month\",\n", - " transform=ccrs.PlateCarree(), # remember to provide this!\n", - " subplot_kws={\"projection\": ccrs.LambertConformal(central_longitude=-95, central_latitude=45)},\n", - " cbar_kwargs={\"orientation\": \"horizontal\", \"shrink\": 0.8, \"aspect\": 40},\n", - " robust=True,\n", - ")\n", - "\n", - "# lets add a coastline to each axis\n", - "# great reason to use FacetGrid.map\n", - "fg.map(lambda: plt.gca().coastlines())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "\n", - "## Interactive bokeh plots using hvplot\n", - "\n", - "Xarray's builtin plotting functionality wraps matplotlib.\n", - "\n", - "The `holoviews` plotting ecosystem provides the `hvplot` package to allow easy\n", - "visualization of xarray (and other) objects (https://hvplot.holoviz.org/). These\n", - "plots build on [Bokeh](https://bokeh.org/).\n", - "\n", - "`hvplot` makes uses of xarray's accessor interface. This means that all xarray\n", - "objects gain a `.hvplot` attribute that lets you access `hvplot` functionality\n", - "as easily as you would use `.plot`\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import hvplot.xarray" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**`hvplot` makes the same default choices as xarray**\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ds.Tair.hvplot()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# 2D array yields a quadmesh plot\n", - "ds.Tair.isel(time=1).hvplot(cmap=\"fire\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# 1D array yields a line plot\n", - "ds.Tair.isel(time=1, lon=1).hvplot()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Interactivity\n", - "\n", - "But `hvplot` shines when interactivity is used. Here we can give it _all_ the\n", - "data and ask it to create a nice slider to control the time slice using the\n", - "`groupby` kwarg.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ds.Tair.hvplot(\n", - " groupby=\"time\",\n", - " clim=(250, 295), # adds a widget for time # sets colorbar limits\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Animations are easy\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# set constant colorbar limits\n", - "ds.Tair.hvplot(\n", - " groupby=\"time\", # adds a widget for time\n", - " clim=(250, 295), # sets colormap limits\n", - " widget_type=\"scrubber\",\n", - " widget_location=\"bottom\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Geography\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ds.Tair.isel(time=1).hvplot(\n", - " projection=ccrs.Orthographic(-90, 30),\n", - " coastline=True,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## More resources\n", - "\n", - "1. Xarray's visualization gallery:\n", - " https://xarray.pydata.org/en/stable/examples/visualization_gallery.html\n", - "2. Xarray's plotting documentation:\n", - " https://xarray.pydata.org/en/stable/plotting.html\n", - "3. hvplot's plotting documentation:\n", - " https://hvplot.holoviz.org/user_guide/Gridded_Data.html\n" - ] - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" - }, - "toc": { - "base_numbering": 1, - "nav_menu": {}, - "number_sections": true, - "sideBar": true, - "skip_h1_title": false, - "title_cell": "Table of Contents", - "title_sidebar": "Contents", - "toc_cell": true, - "toc_position": {}, - "toc_section_display": true, - "toc_window_display": true - } - }, - "nbformat": 4, - "nbformat_minor": 4 -}