diff --git a/doc/Tutorials/Dynamic_Map.ipynb b/doc/Tutorials/Dynamic_Map.ipynb index 21111ac71d..228143db31 100644 --- a/doc/Tutorials/Dynamic_Map.ipynb +++ b/doc/Tutorials/Dynamic_Map.ipynb @@ -4,9 +4,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The [Containers](Containers.ipynb) Tutorial introduced the [HoloMap](Containers.ipynb#HoloMap), a core HoloViews datastructure that allows easy exploration of parameter spaces. The essence of a HoloMap is that it contains a collection of [Elements](Elements.ipynb) that you can easily visualize and slice.\n", + "The [Containers](Containers.ipynb) Tutorial introduced the [HoloMap](Containers.ipynb#HoloMap), a core HoloViews data structure that allows easy exploration of parameter spaces. The essence of a HoloMap is that it contains a collection of [Elements](Elements.ipynb) (e.g. Images and Curves) that you can easily select and visualize.\n", "\n", - "HoloMaps are containers that hold elements at sampled points in a multidimensional space. Although this makes them useful for exploring high-dimensional parameter spaces, they can very quickly consume huge amounts of memory as a result. For instance, a hundred samples along four orthogonal dimensions would need a HoloMap containing a hundred *million* elements. This highlights some of the limitations of ``HoloMaps``:\n", + "HoloMaps hold Elements at sampled points in a multidimensional space. Although this property makes them useful for exploring high-dimensional parameter spaces, HoloMaps can very quickly consume huge amounts of memory for such spaces. For instance, a hundred samples along four orthogonal dimensions would need a HoloMap containing a hundred *million* Elements, each of which could be a substantial object. Thus ``HoloMaps`` have some clear limitations:\n", "\n", "* HoloMaps may require the generation of millions of elements before they are fully defined.\n", "* HoloMaps can easily exhaust all the memory available to Python.\n", @@ -32,7 +32,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "
To use visualize and use a DynamicMap you need to be running a live Jupyter server.
This tutorial assumes that it will be run in a live notebook environment.
" + "
To use visualize and use a DynamicMap you need to be running a live Jupyter server.
This tutorial assumes that it will be run in a live notebook environment.
\n", + "When viewed statically, DynamicMaps will only show the first available Element.
" ] }, { @@ -66,7 +67,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We will now create the ``DynamicMap`` equivalent of the ``HoloMap`` introduced in the [Containers Tutorial](Containers.ipynb#HoloMap). The ``HoloMap`` in that tutorial consisted of ``Image`` elements containing sine ring arrays s defined by the ``sine_array`` function:" + "We will now create the ``DynamicMap`` equivalent of the ``HoloMap`` introduced in the [Containers Tutorial](Containers.ipynb#HoloMap). The ``HoloMap`` in that tutorial consisted of ``Image`` elements containing sine ring arrays as defined by the ``sine_array`` function:" ] }, { @@ -140,11 +141,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "A 'closed' mode ``DynamicMap`` is simply one where all the key dimensions have finite bounds. Bounded mode has the following properties:\n", + "A 'bounded' mode ``DynamicMap`` is simply one where all the key dimensions have finite bounds. Bounded mode has the following properties:\n", "\n", "* The limits of the space and/or the allowable values must be declared for all the key dimensions (unless [sampled mode](#SampledMode) is enabled).\n", "* You can explore within the declared bounds at any resolution.\n", - "* The ``DynamicMap`` is defined using a callable that *must* be a function of its arguments (i.e the output is strictly determined by the input arguments).\n", + "* The ``DynamicMap`` is defined using a callable that *must* be a function of its arguments (i.e., the output is strictly determined by the input arguments).\n", "\n", "We can now create a DynamicMap by simply declaring the ranges of the two dimensions and passing the ``sine_image`` function as the ``.data``:\n", "\n" @@ -166,7 +167,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This object is created instantly as no data has been generated yet. We can now look at the repr of this object: " + "This object is created instantly as no data has been generated yet. We can now look at the ``repr`` of this object: " ] }, { @@ -202,7 +203,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "As with every other component in HoloViews, you can generate ``Layouts`` using the ``+`` operator:" + "You can combine ``DynamicMaps`` with each other (and any other HoloViews Element) to create a ``Layout`` using the ``+`` operator:" ] }, { @@ -221,7 +222,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "As both elements are ``DynamicMaps`` with the same dimension ranges, the continuous sliders are retained. If a ``HoloMap`` is used the sliders will snap to the available samples across the ``HoloMaps`` in the layout. For bounded ``DynamicMaps`` that do not require ranges to be declared, see [sampled mode](#SampledMode)" + "As both elements are ``DynamicMaps`` with the same dimension ranges, the continuous sliders are retained. If one or more ``HoloMaps`` is used with a ``DynamicMap``, the sliders will snap to the samples available in any ``HoloMap`` in the layout. For bounded ``DynamicMaps`` that do not require ranges to be declared, see [sampled mode](#SampledMode)." ] }, { @@ -281,11 +282,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This is exactly the same sort of ``.data`` as the equivalent ``HoloMap`` except this value will vary according to how much you explored the parameter space of ``dmap`` using the sliders above. In a ``HoloMap``, ``.data`` contains a defined sampling along the different dimensions whereas in a ``DynamicMap``, the ``.data`` is the the *cache*.\n", + "This is exactly the same sort of ``.data`` as the equivalent ``HoloMap``, except that this value will vary according to how much you explored the parameter space of ``dmap`` using the sliders above. In a ``HoloMap``, ``.data`` contains a defined sampling along the different dimensions, whereas in a ``DynamicMap``, the ``.data`` is simply the *cache*.\n", "\n", "The cache serves two purposes:\n", "\n", - "* Avoids recomputation of an element should we revisit a particular point in the parameter space. This works well for categorical data but doesn't help much when using continuous sliders.\n", + "* Avoids recomputation of an element should we revisit a particular point in the parameter space. This works well for categorical data, but doesn't help much when using continuous sliders.\n", "* Records the space that has been explored with the ``DynamicMap`` when converting to a ``HoloMap``.\n", "* Ensures a finite history of generator output when using [open mode](#OpenMode) together with infinite generators.\n", "\n", @@ -360,7 +361,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that you can index a ``DynamicMap`` with a literal key in exactly the same way as a ``HoloMap`` so long as you use an exact key value that exists in the cache:" + "Note that you can index a ``DynamicMap`` with a literal key in exactly the same way as a ``HoloMap``, so long as you use an exact key value that already exists in the cache:" ] }, { @@ -378,7 +379,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The default cache size is the reasonably high value of 500 elements. You can set the cache size using the ``cache_size`` parameter if you find you are running into issues with memory consumption. A bounded ``DynamicMap`` with ``cache_size`` of one requires the least memory but will recompute a new element every time the sliders are moved." + "The default cache size is the reasonably high value of 500 Elements. You can set the size using the ``cache_size`` parameter if you find you are running into issues with memory consumption. A bounded ``DynamicMap`` with ``cache_size=1`` requires the least memory, but will recompute a new Element every time the sliders are moved." ] }, { @@ -443,7 +444,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We have now seen one way of sampling a DynamicMap which is to populate the cache with a set of keys. This approach is designed to make conversion of a ``DynamicMap`` into a ``HoloMap`` easy. One disadvantage of this type of sampling is that populating the cache consumes memory resulting in many of the same limitations as ``HoloMap``. To avoid this, there are two other ways of sampling a bounded ``DynamicMap``" + "We have now seen one way of sampling a ``DynamicMap``, which is to populate the cache with a set of keys. This approach is designed to make conversion of a ``DynamicMap`` into a ``HoloMap`` easy. One disadvantage of this type of sampling is that populating the cache consumes memory, resulting in many of the same limitations as ``HoloMap``. To avoid this, there are two other ways of sampling a bounded ``DynamicMap``:" ] }, { @@ -459,7 +460,7 @@ "collapsed": true }, "source": [ - "If you want a fixed sampling instead of continuous sliders but wish to retain the online generation of elements as the sliders are moved, you can simply set the dimension values. Here is an example that matches the cached sampled HoloMaps above but which generates elements as they are requested:" + "If you want a fixed sampling instead of continuous sliders, yet still wish to retain the online generation of elements as the sliders are moved, you can simply set the dimension values. The result appears to the user just like a ``HoloMap``, and has the same data as the pre-cached version above, but now generates the data dynamically:" ] }, { @@ -485,7 +486,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "A bounded ``DynamicMap`` in sampled mode is the least restricted type of ``DynamicMap`` as it can be declared without any information about the allowable dimension ranges or values:" + "A bounded ``DynamicMap`` in sampled mode is the least restricted type of ``DynamicMap``, as it can be declared without any information about the allowable dimension ranges or values:" ] }, { @@ -504,7 +505,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "As you can see, this type of ``DynamicMap`` cannot be visualized in isolation. As before, you can sample the cache and cast it to a HoloMap as necessary:" + "As you can see, this type of ``DynamicMap`` cannot be visualized in isolation. As before, you can sample the cache and thereby cast it to a HoloMap as necessary:" ] }, { @@ -522,7 +523,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The real value of a sampled ``DynamicMap`` is how it interacts with ``HoloMaps`` in a layout. As a sampled ``DynamicMap`` doesn't have explicitly declared dimension ranges, it can always adopt set of sample values from ``HoloMaps`` in the layout." + "The important usage of a sampled ``DynamicMap`` is how it interacts with ``HoloMaps`` in a Layout. As a sampled ``DynamicMap`` doesn't have explicitly declared dimension ranges, it can always adopt the set of sample values from ``HoloMaps`` in the layout." ] }, { @@ -560,12 +561,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "``DynamicMap`` also allows unbounded exploration with unbounded dimensions in 'open' mode. There are two key differences with bounded mode:\n", + "``DynamicMap`` also allows unbounded exploration with unbounded dimensions in 'open' mode. There are two key differences of this mode with bounded mode:\n", "\n", "* Instead of a callable, the input to an open ``DynamicMap`` is a generator. Once created, the generator is only used via ``next()``.\n", - "* At least one of the declared key dimensions have an unbounded range. (upper range only? check!)\n", - "* An open mode ``DynamicMap`` can run forever or until a ``StopIteration`` exception is raised.\n", - "* Open mode ``DynamicMaps`` can be stateful with an irreversible direction of time.\n" + "* At least one of the declared key dimensions must have an unbounded range. (upper range only? need to check!)\n", + "* An open mode ``DynamicMap`` can run forever, or until a ``StopIteration`` exception is raised.\n", + "* Open mode ``DynamicMaps`` can be stateful, with an irreversible direction of time.\n" ] }, { @@ -660,7 +661,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that if you pause the dynamicmap, you can scrub back to previous frames in the cache. In other words you can view a limited history of elements output by the generator which does *not* re-execute the generator in any way as there is impossible to rewind generator state. If you have a stateful generator that say, depends on the current wind speed in Scotland, this history may be misleading in which case you can simply set the ``cache_size`` parameter to 1." + "Note that if you pause the ``DynamicMap``, you can scrub back to previous frames in the cache. In other words, you can view a limited history of elements already output by the generator, which does *not* re-execute the generator in any way (as it is indeed impossible to rewind generator state). If you have a stateful generator that, say, depends on the current wind speed in Scotland, this history may be misleading, in which case you can simply set the ``cache_size`` parameter to 1." ] }, { @@ -705,7 +706,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Open mode ``DynamicMaps`` are finite and terminate if ``StopIteration`` is raised. This example uses a generator expression that is identical to the first open ``DynamicMap`` example above except it terminates after 20 phases:\n" + "Open mode ``DynamicMaps`` are finite and terminate if ``StopIteration`` is raised. This example uses a generator expression that is identical to the first open ``DynamicMap`` example above, except that it terminates after 20 phases:\n" ] }, { @@ -724,9 +725,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "It is trivial to adapt this generator expression to return (key, tuple) pairs where the key may have one or more dimensions.\n", + "It is trivial to adapt this generator expression to return (key, tuple) pairs, where the key may have one or more dimensions.\n", "\n", - "Now if you are familiar with generators in Python, you might be wondering what happens when a finite generator is exhausted. First we should mention that casting a ``DynamicMap`` to a list is always finite because ``__iter__`` returns the cache instead of a potentially infinite generator:" + "Now if you are familiar with generators in Python, you might be wondering what happens when a finite generator is exhausted. First we should mention that casting a ``DynamicMap`` to a list is always finite, because ``__iter__`` returns the cache instead of a potentially infinite generator:" ] }, { @@ -799,7 +800,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Open mode is intended to interface live data streams or simulations with HoloViews. The ``DynamicMap`` to generate live visualizations for as long as new data is requested. Although this works for simple cases, Python generators have problematic limitations that can be resolved using 'counter' mode.\n", + "Open mode is intended to interface live data streams or ongoing simulations with HoloViews. The ``DynamicMap`` will generate live visualizations for as long as new data is requested. Although this works for simple cases, Python generators have problematic limitations that can be resolved using 'counter' mode.\n", "\n", "In this example, lets say we have a simulation or data recording where time increases in integer steps:" ] @@ -875,9 +876,9 @@ "source": [ "If you pause the animation, you'll see that these two outputs are *not* in phase, despite the fact that the generators are defined identically (modulo the additive noise)!\n", "\n", - "The issue is that generators are used via the ``next()`` interface and when either generator is called, the simultation time is increased. In other words, the noisy version in subfigure **B** is actually displayed at a later time than in subfigure **A**.\n", + "The issue is that generators are used via the ``next()`` interface, and so when either generator is called, the simulation time is increased. In other words, the noisy version in subfigure **B** actually corresponds to a later time than in subfigure **A**.\n", "\n", - "This is a fundamental issue as the ``next`` method does not take arguments. What we want is for all the ``DynamicMaps`` presented in a Layout to share a common simulation time that is only incremented by interaction with the scrubber widget. This is exactly the sort of situation where you want to use counter mode." + "This is a fundamental issue, as the ``next`` method does not take arguments. What we want is for all the ``DynamicMaps`` presented in a Layout to share a common simulation time, which is only incremented by interaction with the scrubber widget. This is exactly the sort of situation where you want to use counter mode." ] }, { @@ -945,7 +946,7 @@ "source": [ "Now **A** and **B** are correctly in phase.\n", "\n", - "Unfortunately, a counter is too simple to describe simultation time which is typically a float with real world units. To address this, we can simply return the actual key values we want along the time dimension, just as was demonstrated in open mode using generators:" + "Unfortunately, an integer counter is often too simple to describe simulation time, which is more often a float with real-world units. To address this, we can simply return the actual key values we want along the time dimension, just as was demonstrated in open mode using generators:" ] }, { @@ -1009,7 +1010,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Slicing open and counter mode ``DynamicMaps`` has the exact same semantics as normal ``HoloMap`` slicing except now the ``.data`` attribute corresponds to the cache. For instance:" + "Slicing open and counter mode ``DynamicMaps`` has the exact same semantics as normal ``HoloMap`` slicing, except now the ``.data`` attribute corresponds to the cache. For instance:" ] }, { @@ -1060,6 +1061,15 @@ "sliced = dmap[1:3.1]\n", "print(\"Min key value in cache:%s\\nMax key value in cache:%s\" % (min(sliced.keys()), max(sliced.keys())))" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using DynamicMaps in your code\n", + "\n", + "As you can see, ``DynamicMaps`` let you use HoloViews with a very wide range of dynamic data formats and sources, making it simple to visualize ongoing processes or very large data spaces." + ] } ], "metadata": {