<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 HoloViews encapsulates your continuous or discrete data into storable, composable, sliceable objects, leveraging matplotlib for visualization and IPython Notebook for maximum productivity.
Main features
Step1:  For simplicity in this showcase, we use an unqualified "import *", but in general we recommend using qualified imports and namespaces (as in "from holoviews import Image" or "import holoviews as hv" followed by "hv.Image").
A simple function
First, let us define a mathematical function to explore, using the Numpy array library
Step2:  We will examine the effect of varying phase and frequency
Step3:  Over a specific spatial area, sampled on a grid
Step4:  Compact data visualization
With HoloViews, we can immediately view our simple function by creating Image and Curve objects to visualize the 2D arrays and 1D cross-sections generated by the sine function, respectively
Step5:  As you can see, Image takes a 2D numpy array as input and Curve accepts a list of (x,y) points. With the + operator we can lay these elements out together and with .cols(2) we can arrange them into two columns.
HoloViews objects like Image and Curve are a great way to work with your data, because they display so easily and flexibly, yet preserve the raw data (the Numpy array in this case) in the .data attribute. Calling matplotlib directly to generate such a figure would take much, much more code, e.g., to label each of the axes, to create a figure with subfigures, etc.  Moreover, such code would be focused on the plotting, whereas with HoloViews you can focus directly on what matters
Step6:  Now we create a high-dimensional HoloMap to explore
Step7:  You can still compose as many visualization elements as you wish together. Here is a demonstration of how to generate the horizontal cross-section of the circular wave using Curve elements. This is then positioned next to our circular wave
Step8:  You can then easily export your HoloMap objects to an interactive notebook, video formats, or GIF animations to use on a web page.
Succinct Analysis
HoloViews is focused on making your data readily available, both for visualization and for numerical analysis.  Because HoloViews objects preserve your raw data, you can use any Python analysis tools you wish, such as those in the SciPy library.  We also support some very general-purpose data analysis and manipulation operations directly in HoloViews, exploiting the generality of the HoloViews data structures to simplify common tasks. 
Here, we pick a point on the circular wave at (0,0.25) and plot the amplitude value as a function of phase. The circular wave is shown annotated with a point at the chosen position. Note how we can still interactively explore the remaining dimensions, namely Frequency.
Step9:  Note that the spatial frequency of our curve plot is not affected by the frequency of our wave. That is because the phase always spans exactly one cycle at any of the chosen frequencies.
Here is the circular wave annotated with contours at the 0.5 level, followed by a thresholded version of the same wave, and then the gradient of this pattern, along with a histogram of the gradient values
Step10:  (The %% syntax for specifying options will be briefly explained in the next section below.)  
You can see that this data is shown as an animation, because the data covers multiple phases; each frame of the animation shows the result from one phase.  To get a static plot, just select one phase out of this space instead of a whole list of phases as done here.  Throughout HoloViews, if there are more dimensions of data than will fit into the plot as it has been laid out, they will simply be displayed as an animation or using slider bars.  Supplied operations include gradient, fft_power, convolve, histogram and other common general-purpose analysis tools.
Flexible display system
Remember the initial test of the sine function? Those two composite objects are still in the namespace and even though the objects have already been created, we can still style the display in any way we like.  This styling is done separately from specifying your data, so that your data's specification is always clearly visible, independently of how it is being viewed
Step11:  For convenience, the IPython-magic syntax for setting options like %%opts is used throughout these tutorials.  However, you can use pure Python code to control the options in a similar way, e.g. from within an external non-IPython program where you want to render a HoloViews plot straight to a file, though it requires a few more curly brackets and quote marks
Step12:  Understanding your data
HoloViews is designed to make it easy to understand your data. For instance, consider two circular waves with very different amplitudes
Step13:  HoloViews ensures that these differences are visible by default, by normalizing across any elements of the same type that are displayed together, and even across the frames of an animation
Step14:  This default visualization makes it clear that the two patterns differ greatly in amplitude. However, it is difficult to see the structure of the low-amplitude wave in B.  If you wish to focus on the spatial structure rather than the amplitude, you can instruct HoloViews to normalize data in different axes separately
<ASSISTANT_TASK:>
Python Code:
import holoviews as hv
from holoviews.operation import contours, threshold, gradient
import numpy as np
%reload_ext holoviews.ipython
Explanation: HoloViews encapsulates your continuous or discrete data into storable, composable, sliceable objects, leveraging matplotlib for visualization and IPython Notebook for maximum productivity.
Main features:
Preserves your raw data while allowing rapid, interactive exploratory analysis.
Builds even complex, composite visualizations that are easily customized.
Succinct, declarative style allows you to keep all the necessary code visible, ensuring your workflow is transparent and fully reproducible.
You can select, slice, or transform only the relevant data that is currently of interest.
You can store your raw data as HoloViews objects via pickling, for later analysis or visualization even without the code that generated it.
Strong support for the IPython Notebook, including tab-completion throughout and powerful IPython magics (with all functionality also available in pure Python).
Seamless (optional) interaction with Pandas Dataframes.
And much, much more!
The IPython notebook environment and matplotlib allow you to do interactive exploration and analysis of your data and measurements, using the rich ecosystem of tools available in Python.  However, your notebooks can very quickly fill up with verbose, specialized plotting code whenever you want to visualize your data, which is often.  To make all this practical, you can use HoloViews to greatly improve your productivity, requiring orders of magnitude fewer lines of code and letting you focus on your data itself, not on writing code to visualize and display it.
Here we will show some of the main features of HoloViews, and why it is useful for scientists and engineers.
End of explanation
def sine(x, phase=0, freq=100):
    return np.sin((freq * x + phase))
Explanation: For simplicity in this showcase, we use an unqualified "import *", but in general we recommend using qualified imports and namespaces (as in "from holoviews import Image" or "import holoviews as hv" followed by "hv.Image").
A simple function
First, let us define a mathematical function to explore, using the Numpy array library:
End of explanation
phases = np.linspace(0,2*np.pi,11) # Explored phases
freqs = np.linspace(50,150,5)      # Explored frequencies
Explanation: We will examine the effect of varying phase and frequency:
End of explanation
dist = np.linspace(-0.5,0.5,202)   # Linear spatial sampling
x,y = np.meshgrid(dist, dist)
grid = (x**2+y**2)                 # 2D spatial sampling
Explanation: Over a specific spatial area, sampled on a grid:
End of explanation
freq1 = hv.Image(sine(grid, freq=50))  + hv.Curve(zip(dist, sine(dist**2, freq=50)))
freq2 = hv.Image(sine(grid, freq=200)) + hv.Curve(zip(dist, sine(dist**2, freq=200)))
(freq1 + freq2).cols(2)
Explanation: Compact data visualization
With HoloViews, we can immediately view our simple function by creating Image and Curve objects to visualize the 2D arrays and 1D cross-sections generated by the sine function, respectively:
End of explanation
dimensions = ['Phase', 'Frequency']
keys = [(p,f) for p in phases for f in freqs]
Explanation: As you can see, Image takes a 2D numpy array as input and Curve accepts a list of (x,y) points. With the + operator we can lay these elements out together and with .cols(2) we can arrange them into two columns.
HoloViews objects like Image and Curve are a great way to work with your data, because they display so easily and flexibly, yet preserve the raw data (the Numpy array in this case) in the .data attribute. Calling matplotlib directly to generate such a figure would take much, much more code, e.g., to label each of the axes, to create a figure with subfigures, etc.  Moreover, such code would be focused on the plotting, whereas with HoloViews you can focus directly on what matters: your data, letting it plot itself.  Because the HoloViews code is so succinct, you don't need to hide it away in some difficult-to-maintain external script; you can simply type what you want to see right in the notebook, changing it at will and being able to come back to your analysis just as you left it.
Only two element types are shown above, but HoloViews supports many other types of element that behave in the same way: scatter points, histograms, tables, vectorfields, RGB images, 3D plots, annotations, and many more as shown in the Elements overview.  All of these can be combined easily to create even quite complex plots with a minimum of code to write or maintain.
Interactive exploration
We can interactively explore this simple function if we declare the dimensions of the parameter space to be explored (dimensions) as well as the specific samples to take in this parameter space (keys):
End of explanation
items = [(k, hv.Image(sine(grid, *k), vdims=['Amplitude'])) for k in keys]
circular_wave = hv.HoloMap(items, kdims=dimensions)
circular_wave
Explanation: Now we create a high-dimensional HoloMap to explore: The tuple keys are the points in the parameter space, and the values are the corresponding Image objects:
End of explanation
items = [(k, hv.Curve(zip(dist, sine(dist**2, *k)))) for k in keys]
sections = hv.HoloMap(items, kdims=dimensions)
circular_wave + sections
Explanation: You can still compose as many visualization elements as you wish together. Here is a demonstration of how to generate the horizontal cross-section of the circular wave using Curve elements. This is then positioned next to our circular wave:
End of explanation
sample_pos = (0,0.25)
annotated = circular_wave * hv.Points([sample_pos])
sample = circular_wave.sample(samples=[sample_pos]).to.curve('Phase', 'Amplitude', ['Frequency'])
annotated + sample
Explanation: You can then easily export your HoloMap objects to an interactive notebook, video formats, or GIF animations to use on a web page.
Succinct Analysis
HoloViews is focused on making your data readily available, both for visualization and for numerical analysis.  Because HoloViews objects preserve your raw data, you can use any Python analysis tools you wish, such as those in the SciPy library.  We also support some very general-purpose data analysis and manipulation operations directly in HoloViews, exploiting the generality of the HoloViews data structures to simplify common tasks. 
Here, we pick a point on the circular wave at (0,0.25) and plot the amplitude value as a function of phase. The circular wave is shown annotated with a point at the chosen position. Note how we can still interactively explore the remaining dimensions, namely Frequency.
End of explanation
%output holomap='gif'
%%opts Image (cmap='gray') Contours (color='r')
m = hv.HoloMap([(p, hv.Image(sine(grid, phase=p))) for p in phases], kdims=['Phase'])
contours(m, levels=[0.5]) + threshold(m, level=0.5) + gradient(m).hist(bin_range=(0,0.7))
Explanation: Note that the spatial frequency of our curve plot is not affected by the frequency of our wave. That is because the phase always spans exactly one cycle at any of the chosen frequencies.
Here is the circular wave annotated with contours at the 0.5 level, followed by a thresholded version of the same wave, and then the gradient of this pattern, along with a histogram of the gradient values:
End of explanation
%%opts Image (cmap='RdYlGn') Curve (color='g')
(freq1 + freq2).cols(2)
Explanation: (The %% syntax for specifying options will be briefly explained in the next section below.)  
You can see that this data is shown as an animation, because the data covers multiple phases; each frame of the animation shows the result from one phase.  To get a static plot, just select one phase out of this space instead of a whole list of phases as done here.  Throughout HoloViews, if there are more dimensions of data than will fit into the plot as it has been laid out, they will simply be displayed as an animation or using slider bars.  Supplied operations include gradient, fft_power, convolve, histogram and other common general-purpose analysis tools.
Flexible display system
Remember the initial test of the sine function? Those two composite objects are still in the namespace and even though the objects have already been created, we can still style the display in any way we like.  This styling is done separately from specifying your data, so that your data's specification is always clearly visible, independently of how it is being viewed:
End of explanation
red_wave = circular_wave(options={'Image':{'style':{'cmap':'RdGy'}}})
red_wave
Explanation: For convenience, the IPython-magic syntax for setting options like %%opts is used throughout these tutorials.  However, you can use pure Python code to control the options in a similar way, e.g. from within an external non-IPython program where you want to render a HoloViews plot straight to a file, though it requires a few more curly brackets and quote marks:
End of explanation
comparison = hv.Image(sine(grid)) + hv.Image(sine(grid, phase=np.pi)*0.02)
Explanation: Understanding your data
HoloViews is designed to make it easy to understand your data. For instance, consider two circular waves with very different amplitudes:
End of explanation
%%opts Image (cmap='gray')
comparison = hv.Image(sine(grid)) + hv.Image(sine(grid, phase=np.pi)*0.02)
comparison
Explanation: HoloViews ensures that these differences are visible by default, by normalizing across any elements of the same type that are displayed together, and even across the frames of an animation:
End of explanation
%%opts Image {+axiswise} (cmap='gray')
comparison
Explanation: This default visualization makes it clear that the two patterns differ greatly in amplitude. However, it is difficult to see the structure of the low-amplitude wave in B.  If you wish to focus on the spatial structure rather than the amplitude, you can instruct HoloViews to normalize data in different axes separately:
End of explanation
<END_TASK>