Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Area element #427

Merged
merged 7 commits into from
Jan 29, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions doc/Tutorials/Elements.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
" <dt><a href=\"#Curve\"><code>Curve</code></a></dt><dd>A continuous relation between a dependent and an independent variable.</dd>\n",
" <dt><a href=\"#ErrorBars\"><code>ErrorBars</code></a></dt><dd>A collection of x-/y-coordinates with associated error magnitudes.</dd>\n",
" <dt><a href=\"#Spread\"><code>Spread</code></a></dt><dd>Continuous version of ErrorBars.</dd>\n",
" <dt><a href=\"#Area\"><code>Area</code></a></dt><dd></dd>\n",
" <dt><a href=\"#Bars\"><code>Bars</code></a></dt><dd>Data collected and binned into categories.</dd>\n",
" <dt><a href=\"#Histogram\"><code>Histogram</code></a></dt><dd>Data collected and binned in a continuous space using specified bin edges.</dd>\n",
" <dt><a href=\"#BoxWhisker\"><code>BoxWhisker</code></a></dt><dd>Distributions of data varying by 0-N key dimensions.</dd>\n",
Expand Down Expand Up @@ -280,6 +281,58 @@
" vdims=['y', 'yerrneg', 'yerrpos'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### ``Area`` <a id='Area'></a>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"** *Area under the curve* **\n",
"\n",
"By default the Area Element draws just the area under the curve, i.e. the region between the curve and the origin."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"xs = np.linspace(0, np.pi*4, 40)\n",
"hv.Area((xs, np.sin(xs)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"** * Area between curves * **\n",
"\n",
"When supplied a second value dimension the area is defined as the area between two curves."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"X = np.linspace(0,3,200)\n",
"Y = X**2 + 3\n",
"Y2 = np.exp(X) + 2\n",
"Y3 = np.cos(X)\n",
"hv.Area((X, Y, Y2), vdims=['y', 'y2']) * hv.Area((X, Y, Y3), vdims=['y', 'y3'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down
2 changes: 1 addition & 1 deletion doc/reference_data
Submodule reference_data updated 196 files
13 changes: 13 additions & 0 deletions holoviews/element/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,3 +379,16 @@ class Spikes(Chart):

_1d = True


class Area(Curve):
"""
An Area Element represents the area under a Curve
and is specified in the same format as a regular
Curve, with the key dimension corresponding to a
column of x-values and the value dimension
corresponding to a column of y-values. Optionally
a second value dimension may be supplied to shade
the region between the curves.
"""

group = param.String(default='Area', constant=True)
5 changes: 5 additions & 0 deletions holoviews/element/comparison.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ def register(cls):
cls.equality_type_funcs[Curve] = cls.compare_curve
cls.equality_type_funcs[ErrorBars] = cls.compare_errorbars
cls.equality_type_funcs[Spread] = cls.compare_spread
cls.equality_type_funcs[Area] = cls.compare_area
cls.equality_type_funcs[Scatter] = cls.compare_scatter
cls.equality_type_funcs[Scatter3D] = cls.compare_scatter3d
cls.equality_type_funcs[Trisurface] = cls.compare_trisurface
Expand Down Expand Up @@ -471,6 +472,10 @@ def compare_errorbars(cls, el1, el2, msg='ErrorBars'):
def compare_spread(cls, el1, el2, msg='Spread'):
cls.compare_columns(el1, el2, msg)

@classmethod
def compare_area(cls, el1, el2, msg='Area'):
cls.compare_columns(el1, el2, msg)

@classmethod
def compare_scatter(cls, el1, el2, msg='Scatter'):
cls.compare_columns(el1, el2, msg)
Expand Down
8 changes: 6 additions & 2 deletions holoviews/plotting/bokeh/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
RGB, Histogram, Spread, HeatMap, Contours, Bars,
Box, Bounds, Ellipse, Polygons, BoxWhisker,
ErrorBars, Text, HLine, VLine, Spline, Spikes,
Table, ItemTable, Surface, Scatter3D, Trisurface)
Table, ItemTable, Surface, Scatter3D, Trisurface,
Area)
from ...core.options import Options, Cycle
from ...interface import DFrame
from ..plot import PlotSelector
Expand All @@ -14,7 +15,8 @@
from .callbacks import Callbacks # noqa (API import)
from .element import OverlayPlot, BokehMPLWrapper, BokehMPLRawWrapper
from .chart import (PointPlot, CurvePlot, SpreadPlot, ErrorPlot, HistogramPlot,
SideHistogramPlot, BoxPlot, BarPlot, SpikesPlot, SideSpikesPlot)
SideHistogramPlot, BoxPlot, BarPlot, SpikesPlot,
SideSpikesPlot, AreaPlot)
from .path import PathPlot, PolygonPlot
from .plot import GridPlot, LayoutPlot, AdjointLayoutPlot
from .raster import RasterPlot, RGBPlot, HeatmapPlot
Expand All @@ -40,6 +42,7 @@
Spikes: SpikesPlot,
BoxWhisker: BoxPlot,
Bars: BarPlot,
Area: AreaPlot,

# Rasters
Image: RasterPlot,
Expand Down Expand Up @@ -118,6 +121,7 @@
options.Histogram = Options('style', fill_color="#036564", line_color="#033649")
options.Points = Options('style', color=Cycle())
options.Spikes = Options('style', color='black')
options.Area = Options('style', color=Cycle(), line_color='black')

# Paths
options.Contours = Options('style', color=Cycle())
Expand Down
33 changes: 29 additions & 4 deletions holoviews/plotting/bokeh/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import param

from ...element import Raster, Points, Polygons, Spikes
from ...core.util import max_range
from ..util import compute_sizes, get_sideplot_ranges, match_spec
from .element import ElementPlot, line_properties, fill_properties
from .path import PathPlot, PolygonPlot
Expand Down Expand Up @@ -111,13 +112,38 @@ def get_data(self, element, ranges=None, empty=False):
dict(x=x, y=y))


class AreaPlot(PolygonPlot):

def get_extents(self, element, ranges):
vdims = element.vdims
vdim = vdims[0].name
if len(vdims) > 1:
ranges[vdim] = max_range([ranges[vd.name] for vd in vdims])
else:
vdim = vdims[0].name
ranges[vdim] = (np.nanmin([0, ranges[vdim][0]]), ranges[vdim][1])
return super(AreaPlot, self).get_extents(element, ranges)

def get_data(self, element, ranges=None, empty=False):
mapping = dict(self._mapping)
if empty: return {'xs': [], 'ys': []}
xs = element.dimension_values(0)
x2 = np.hstack((xs[::-1], xs))

if len(element.vdims) > 1:
bottom = element.dimension_values(2)
else:
bottom = np.zeros(len(element))
ys = np.hstack((bottom[::-1], element.dimension_values(1)))

data = dict(xs=[x2], ys=[ys])
return data, mapping


class SpreadPlot(PolygonPlot):

style_opts = ['color'] + line_properties + fill_properties

def __init__(self, *args, **kwargs):
super(SpreadPlot, self).__init__(*args, **kwargs)

def get_data(self, element, ranges=None, empty=None):
if empty:
return dict(xs=[], ys=[]), self._mapping
Expand Down Expand Up @@ -477,4 +503,3 @@ def _init_chart(self, element, ranges):
plot = Bar(element.dframe(), values=vdim,
continuous_range=crange, **kwargs)
return plot

3 changes: 3 additions & 0 deletions holoviews/plotting/mpl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ def grid_selector(grid):
Spread: SpreadPlot,
Spikes: SpikesPlot,
BoxWhisker: BoxPlot,
Area: AreaPlot,

# General plots
GridSpace: GridPlot,
Expand Down Expand Up @@ -180,8 +181,10 @@ def grid_selector(grid):
options.Scatter3D = Options('plot', fig_size=150)
options.Surface = Options('plot', fig_size=150)
options.Spikes = Options('style', color='black')
options.Area = Options('style', facecolor=Cycle(), edgecolor='black')
options.BoxWhisker = Options('style', boxprops=dict(color='k'),
whiskerprops=dict(color='k'))

# Rasters
options.Image = Options('style', cmap='hot', interpolation='nearest')
options.Raster = Options('style', cmap='hot', interpolation='nearest')
Expand Down
66 changes: 44 additions & 22 deletions holoviews/plotting/mpl/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
import param

from ...core import OrderedDict
from ...core.util import match_spec, unique_iterator, safe_unicode, basestring
from ...core.util import (match_spec, unique_iterator, safe_unicode,
basestring, max_range)
from ...element import Points, Raster, Polygons
from ..util import compute_sizes, get_sideplot_ranges
from .element import ElementPlot, ColorbarPlot, LegendPlot
Expand Down Expand Up @@ -228,18 +229,12 @@ def update_handles(self, axis, element, key, ranges=None):
[xvals[i], tdata[i]]])


class SpreadPlot(ChartPlot):
"""
SpreadPlot plots the Spread Element type.
"""

style_opts = ['alpha', 'color', 'linestyle', 'linewidth',
'edgecolor', 'facecolor', 'hatch']

def __init__(self, *args, **kwargs):
super(SpreadPlot, self).__init__(*args, **kwargs)
self._extent = None
class AreaPlot(ChartPlot):

style_opts = ['color', 'facecolor', 'alpha', 'edgecolor', 'linewidth',
'hatch', 'linestyle', 'joinstyle',
'fill', 'capstyle', 'interpolate']

def initialize_plot(self, ranges=None):
element = self.hmap.last
Expand All @@ -248,27 +243,54 @@ def initialize_plot(self, ranges=None):

ranges = self.compute_ranges(self.hmap, key, ranges)
ranges = match_spec(element, ranges)

self.update_handles(axis, element, key, ranges)

return self._finalize_axis(self.keys[-1], ranges=ranges)
ylabel = str(element.vdims[0])
return self._finalize_axis(self.keys[-1], ranges=ranges, ylabel=ylabel)

def get_data(self, element):
xs = element.dimension_values(0)
ys = [element.dimension_values(vdim) for vdim in element.vdims]
return tuple([xs]+ys)

def get_extents(self, element, ranges):
vdims = element.vdims
vdim = vdims[0].name
ranges[vdim] = max_range([ranges[vd.name] for vd in vdims])
return super(AreaPlot, self).get_extents(element, ranges)

def update_handles(self, axis, element, key, ranges=None):
if 'paths' in self.handles:
self.handles['paths'].remove()
if 'artist' in self.handles:
self.handles['artist'].remove()

xvals = element.dimension_values(0)
# Create line segments and apply style
style = self.style[self.cyclic_index]
data = self.get_data(element)
fill_fn = axis.fill_betweenx if self.invert_axes else axis.fill_between
stack = fill_fn(*data, zorder=self.zorder, **style)
self.handles['artist'] = stack



class SpreadPlot(AreaPlot):
"""
SpreadPlot plots the Spread Element type.
"""


def __init__(self, element, **params):
self.table = element.table()
super(SpreadPlot, self).__init__(element, **params)
self._extents = None

def get_data(self, element):
xs = element.dimension_values(0)
mean = element.dimension_values(1)
neg_error = element.dimension_values(2)
pos_idx = 3 if len(element.dimensions()) > 3 else 2
pos_error = element.dimension_values(pos_idx)

paths = axis.fill_between(xvals, mean-neg_error,
mean+pos_error, zorder=self.zorder,
label=element.label if self.show_legend else None,
**self.style[self.cyclic_index])
self.handles['paths'] = paths

return xs, mean-neg_error, mean+pos_error


class HistogramPlot(ChartPlot):
Expand Down