コード例 #1
0
 def test_Float(self):
     p = Float()
     with pytest.raises(ValueError) as e:
         p.validate("junk")
     assert matches(
         str(e.value),
         r"expected a value of type Real, got junk of type (str|unicode)")
コード例 #2
0
class IonRangeSlider(InputWidget):
    # The special class attribute ``__implementation__`` should contain a string
    # of JavaScript, TypeScript or CoffeeScript code that implements the web broser
    # side of the custom extension model or a string name of a file with the implementation.

    __implementation__ = 'extensions_ion_range_slider.ts'
    __javascript__ = ["https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js",
                      "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/js/ion.rangeSlider.js"]
    __css__ = ["https://cdnjs.cloudflare.com/ajax/libs/normalize/4.2.0/normalize.css",
               "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/css/ion.rangeSlider.css",
               "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/css/ion.rangeSlider.skinFlat.min.css",
               "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/img/sprite-skin-flat.png"]

    # Below are all the "properties" for this model. Bokeh properties are
    # class attributes that define the fields (and their types) that can be
    # communicated automatically between Python and the browser. Properties
    # also support type validation. More information about properties in
    # can be found here:
    #
    #    https://bokeh.pydata.org/en/latest/docs/reference/core.html#bokeh-core-properties

    disable = Bool(default=True, help="""
    Enable or disable the slider.
    """)

    grid = Bool(default=True, help="""
    Show or hide the grid beneath the slider.
    """)

    start = Float(default=0, help="""
    The minimum allowable value.
    """)

    end = Float(default=1, help="""
    The maximum allowable value.
    """)

    range = Tuple(Float, Float, help="""
    The start and end values for the range.
    """)

    step = Float(default=0.1, help="""
    The step between consecutive values.
    """)

    callback = Instance(Callback, help="""
    A callback to run in the browser whenever the current Slider value changes.
    """)

    callback_throttle = Float(default=200, help="""
    Number of microseconds to pause between callback calls as the slider is moved.
    """)

    callback_policy = Enum(SliderCallbackPolicy, default="throttle", help="""
    When the callback is initiated. This parameter can take on only one of three options:
       "continuous": the callback will be executed immediately for each movement of the slider
       "throttle": the callback will be executed at most every ``callback_throttle`` milliseconds.
       "mouseup": the callback will be executed only once when the slider is released.
       The `mouseup` policy is intended for scenarios in which the callback is expensive in time.
    """)
コード例 #3
0
class AudioButton(Button):
    ''' A button that implements client-side audio playback.
    '''

    # TODO: Figure out why installation fails when the TypeScript code
    # is  included as a separate .ts file. It isn't copied along with
    # the .py file.
    #__implementation__ = 'audio_button.ts'
    __implementation__ = TypeScript(TS_CODE)

    channels = List(String,
                    help="""
    The list of column names in `source` that identify the audio channels.
    """)
    end = Float(np.Inf,
                help="""
    The time in seconds of the last sample in `source` for playback.
    """)
    fs = Float(help="""
    The sample rate of the audio signal in `source`.
    """)
    source = Instance(ColumnDataSource,
                      help="""
    A dict of audio signal data, including at least one column of sample
    data and a column of sample times (named 'seconds').
    """)
    start = Float(0.0,
                  help="""
    The time in seconds of the first sample in `source` for playback.
    """)
コード例 #4
0
class IonRangeSlider(InputWidget):
    # The special class attribute ``__implementation__`` should contain a string
    # of JavaScript or TypeScript code that implements the web browser
    # side of the custom extension model or a string name of a file with the implementation.

    __implementation__ = 'extensions_ion_range_slider.ts'
    __javascript__ = [
        "https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js",
        "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/js/ion.rangeSlider.js"
    ]
    __css__ = [
        "https://cdnjs.cloudflare.com/ajax/libs/normalize/4.2.0/normalize.css",
        "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/css/ion.rangeSlider.css",
        "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/css/ion.rangeSlider.skinFlat.min.css",
        "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/img/sprite-skin-flat.png"
    ]

    # Below are all the "properties" for this model. Bokeh properties are
    # class attributes that define the fields (and their types) that can be
    # communicated automatically between Python and the browser. Properties
    # also support type validation. More information about properties in
    # can be found here:
    #
    #    https://docs.bokeh.org/en/latest/docs/reference/core/properties.html#bokeh-core-properties

    disable = Bool(default=True,
                   help="""
    Enable or disable the slider.
    """)

    grid = Bool(default=True,
                help="""
    Show or hide the grid beneath the slider.
    """)

    start = Float(default=0, help="""
    The minimum allowable value.
    """)

    end = Float(default=1, help="""
    The maximum allowable value.
    """)

    range = Tuple(Float,
                  Float,
                  help="""
    The start and end values for the range.
    """)

    step = Float(default=0.1,
                 help="""
    The step between consecutive values.
    """)

    callback = Instance(Callback,
                        help="""
    A callback to run in the browser whenever the current Slider value changes.
    """)
コード例 #5
0
ファイル: __init__.py プロジェクト: w1xm/gnuradio
class Knob(HTMLBox):
    title = String(default="")
    value = Float(default=0)
    writable = Bool(default=False)
    scrollable = Bool(default=False)
    digits = Int(default=3)
    decimals = Int(default=3)
    max = Float()
    min = Float()
    wrap = Bool(default=False)
    unit = String()
    active = Bool(default=True)
コード例 #6
0
class DotBuilder(BarBuilder):
    """Produces Dot Glyphs for groups of data.

    Handles dot plot options to produce one to many dots,
    which are used to describe the values of aggregated groups of data.

    """

    line_alpha = Float(default=1.0)

    # ToDo: Support easier adding of one attr without reimplementation
    default_attributes = {
        'label': CatAttr(),
        'color': ColorAttr(),
        'line_color': ColorAttr(),
        'stack': CatAttr(),
        'group': CatAttr(),
        'marker': MarkerAttr(),
    }

    stem = Bool(False,
                help="""
    Whether to draw a stem from each do to the axis.
    """)

    glyph = DotGlyph
コード例 #7
0
def test_Property_wrap() -> None:
    types = [
        Bool(),
        Int(),
        Float(),
        Complex(),
        String(),
        Enum("Some", "a", "b"),
        Color(),
        Regex("^$"),
        Seq(Any),
        Tuple(Any, Any),
        Instance(_TestModel),
        Any(),
        Interval(Float, 0, 1),
        Either(Int, String),
        DashPattern(),
        Size(),
        Percent(),
        Angle(),
        MinMaxBounds(),
    ]

    for x in types:
        for y in (0, 1, 2.3, "foo", None, (), [], {}):
            r = x.wrap(y)
            assert r == y
            assert isinstance(r, type(y))
コード例 #8
0
class FontAwesomeIcon(AbstractIcon):
    """ A "stock" icon based on FontAwesome. """

    __implementation__ = "fontawesome_icon.ts"
    __dependencies__ = {"font-awesome": "^4.6.3"}

    icon_name = Enum(NamedIcon,
                     default="check",
                     help="""
    What icon to use. See http://fortawesome.github.io/Font-Awesome/icons/
    for the list of available icons.
    """)

    size = Float(1,
                 help="""
    The size multiplier (1x, 2x, ..., 5x).
    """)

    flip = Enum("horizontal",
                "vertical",
                default=None,
                help="""
    Optionally flip the icon horizontally or vertically.
    """)

    spin = Bool(False,
                help="""
    Indicates a spinning (animated) icon. This value is ignored for
    icons that do not support spinning.
    """)
コード例 #9
0
ファイル: custom.py プロジェクト: PaulGureghian1/Bokeh
class MyPlot(Plot):

    __implementation__ = """
import {Plot, PlotView} from "models/plots/plot"
import * as p from "core/properties"
import "./custom.less"

export class MyPlotView extends PlotView
  render: () ->
    super()
    @el.classList.add("bk-my-plot")

    angle = "#{@model.gradient_angle}deg"

    offset = 0
    colors = []
    step = @model.gradient_step

    for color in @model.gradient_colors
      colors.push("#{color} #{offset}px")
      offset += step
      colors.push("#{color} #{offset}px")

    @el.style.backgroundImage = "repeating-linear-gradient(#{angle}, #{colors.join(', ')})"

export class MyPlot extends Plot
  type: "MyPlot"
  default_view: MyPlotView

  @define {
    gradient_angle:  [ p.Number, 0                      ]
    gradient_step:   [ p.Number, 20                     ]
    gradient_colors: [ p.Array,  ["white", "lightgray"] ]
  }

  @override {
    background_fill_alpha: 0.0
    border_fill_alpha: 0.0
  }
"""

    gradient_angle = Float(default=0)
    gradient_step = Float(default=20)
    gradient_colors = List(Color, default=["white", "gray"])

    background_fill_alpha = Override(default=0.0)
    border_fill_alpha = Override(default=0.0)
コード例 #10
0
class DotGlyph(Interval):
    """Special case of Interval where the span represents a value.

    A bar always begins from 0, or the value that is being compared to, and
    extends to some positive or negative value.
    """

    marker = String(default='circle')
    size = Float(default=8)
    stem = Bool(False,
                help="""
    Whether to draw a stem from each do to the axis.
    """)
    stem_line_width = Float(default=1)
    stem_color = String(default='black')

    def __init__(self, label, values, agg='sum', **kwargs):
        kwargs['end_agg'] = agg
        super(DotGlyph, self).__init__(label, values, **kwargs)
        self.setup()

    def get_start(self):
        return 0.0

    def get_glyph(self):
        return marker_types[self.marker]

    def build_renderers(self):
        if self.stem:
            yield GlyphRenderer(glyph=Segment(x0='x',
                                              y0=0,
                                              x1='x',
                                              y1='height',
                                              line_width=self.stem_line_width,
                                              line_color=self.stem_color,
                                              line_alpha='fill_alpha'))

        glyph_type = self.get_glyph()
        glyph = glyph_type(x='x',
                           y='height',
                           line_color=self.line_color,
                           fill_color=self.color,
                           size=self.size,
                           fill_alpha='fill_alpha',
                           line_alpha='line_alpha')
        yield GlyphRenderer(glyph=glyph)
コード例 #11
0
class WaterfallRenderer(Renderer):
    __implementation__ = join(dirname(__file__), "waterfall.ts")

    latest = Seq(Float, default=[])

    palette = Seq(Color)

    time_length = Int()

    fft_length = Int()

    min_value = Float()

    max_value = Float()

    update = Bool()

    level = Override(default = "glyph")
コード例 #12
0
class BinStats(Stat):
    """A set of statistical calculations for binning values.

    Bin counts using: https://en.wikipedia.org/wiki/Freedman%E2%80%93Diaconis_rule
    """
    bins = Either(Int,
                  Float,
                  List(Float),
                  default=None,
                  help="""
    If bins is an int, it defines the number of equal-width bins in the
    given range. If bins is a sequence, it defines the
    bin edges, including the rightmost edge, allowing for non-uniform
    bin widths.

    (default: None, use Freedman-Diaconis rule)
    """)
    bin_width = Float(default=None, help='Use Freedman-Diaconis rule if None.')
    q1 = Quantile(interval=0.25)
    q3 = Quantile(interval=0.75)
    labels = List(String)

    def __init__(self, values=None, column=None, **properties):
        properties['values'] = values
        properties['column'] = column or 'values'

        super(BinStats, self).__init__(**properties)

    def update(self):
        values = self.get_data()
        self.q1.set_data(values)
        self.q3.set_data(values)
        if self.bins is None:
            self.calc_num_bins(values)

    def calc_num_bins(self, values):
        """Calculate optimal number of bins using IQR.

        From: http://stats.stackexchange.com/questions/114490/optimal-bin-width-for-two-dimensional-histogram

        """
        iqr = self.q3.value - self.q1.value

        if iqr == 0:
            self.bin_width = np.sqrt(values.size)
        else:
            self.bin_width = 2 * iqr * (len(values)**-(1. / 3.))

        self.bins = int(np.ceil(
            (values.max() - values.min()) / self.bin_width))

        if self.bins <= 1:
            self.bins = 3

    def calculate(self):
        pass
コード例 #13
0
class Quantile(Stat):
    """Produces the cutpoint that divides the input data by the interval.

    Quartiles are a special case of quartiles that divide a dataset into four
    equal-size groups. (https://en.wikipedia.org/wiki/Quantile)
    """
    interval = Float(default=0.5)

    def calculate(self):
        self.value = self.get_data().quantile(self.interval)
コード例 #14
0
class TrendIndicator(HTMLBox):
    """
    A Bokeh model indicating trends.
    """

    description = String()
    change_formatter = Instance(
        TickFormatter, default=lambda: NumeralTickFormatter(format='0.00%'))
    formatter = Instance(TickFormatter, default=lambda: BasicTickFormatter())
    layout = String()
    source = Instance(ColumnDataSource)
    plot_x = String()
    plot_y = String()
    plot_color = String()
    plot_type = String()
    pos_color = String()
    neg_color = String()
    title = String()
    value = Float()
    value_change = Float()
コード例 #15
0
class ParallelSelectionTool(BoxSelectTool):
    """ Selection tool for parallel plot
    To create a selection box, drag the selection around an axe
    When hovering a selection the box can be dragged upside-down
    Double click on a selection to remove it
    Escape key remove all selections
    """

    __implementation__ = 'parallel_selection_tool.ts'
    renderer_select = Instance(Renderer, help="Rectangular Selections glyphs")
    renderer_data = Instance(Renderer, help="MultiLine glyph of the data")
    box_width = Float(
        help="Width size in the screen coordinate of selection boxes")
コード例 #16
0
class VTKAxes(Model):
    """
    A Bokeh model for axes
    """

    xticker = Dict(String, Any)

    yticker = Dict(String, Any)

    zticker = Dict(String, Any)

    origin = Any()

    digits = Int(default=1)

    show_grid = Bool(default=True)

    grid_opacity = Float(default=0.1)

    axes_opacity = Float(default=1)

    fontsize = PositiveInt(default=12)
コード例 #17
0
ファイル: widgets.py プロジェクト: weiplanet/panel
class Video(HTMLBox):

    loop = Bool(False, help="""Whether the video should loop""")

    paused = Bool(False, help="""Whether the video is paused""")

    time = Float(0, help="""
        The current time stamp of the video playback""")

    throttle = Int(250, help="""
        The frequency at which the time value is updated in milliseconds.""")

    value = Any(help="Encoded file data")

    volume = Int(0, help="""The volume of the video player.""")
コード例 #18
0
class PCPSelectionTool(BoxSelectTool):
    """Selection tool for parallel plot
    To create a selection box, drag the selection around an axe
    When hovering a selection the box can be dragged upside-down
    Double click on a selection to remove it
    Escape key remove all selections
    """

    renderer_select = Instance(Renderer, help="Rectangular Selections glyphs")

    renderer_data = Instance(Renderer, help="MultiLine glyph of the data")

    box_width = Float(
        help="Width size in the screen coordinate of selection boxes")

    indices_throttled = List(item_type=Int)
コード例 #19
0
class LatexLegend(Legend):
    """
    A subclass of the built-in `Legend` that supports rendering
    LaTeX using the KaTeX typesetting library.

    Only vertical legends are supported, the `orientation` keyword
    is overwritten.
    """
    __javascript__ = [katex_js]
    __css__ = [katex_css]
    __implementation__ = "latex_legend.ts"

    max_label_width = Float(default=0,
                            help="""
        Maximum width of the legend box. Automatic calculation of the width is not supported yet.
        """)
コード例 #20
0
ファイル: widgets.py プロジェクト: weiplanet/panel
class VideoStream(HTMLBox):

    format = Enum('png', 'jpeg', default='png')

    paused = Bool(False, help="""Whether the video is paused""")

    snapshot = Bool(False, help="""On change generate a snapshot of the current video frame""")

    timeout = Float(None, help="""
        The timeout between snapshots (if None snapshot only generated
        when snapshot property is changed""")

    value = Any(help="""Snapshot Data""")

    height = Override(default=240)

    width = Override(default=320)
コード例 #21
0
class PointGlyph(XyGlyph):
    """A set of glyphs placed in x,y coordinates with the same attributes."""

    fill_color = Override(default=DEFAULT_PALETTE[1])
    fill_alpha = Override(default=0.7)
    marker = String(default='circle')
    size = Float(default=8)

    def __init__(self,
                 x=None,
                 y=None,
                 color=None,
                 line_color=None,
                 fill_color=None,
                 marker=None,
                 size=None,
                 **kwargs):
        kwargs['x'] = x
        kwargs['y'] = y
        if marker is not None: kwargs['marker'] = marker
        if size is not None: kwargs['size'] = size

        if color:
            line_color = color
            fill_color = color

        kwargs['line_color'] = line_color
        kwargs['fill_color'] = fill_color

        super(PointGlyph, self).__init__(**kwargs)
        self.setup()

    def get_glyph(self):
        return marker_types[self.marker]

    def build_renderers(self):
        glyph_type = self.get_glyph()
        glyph = glyph_type(x='x_values',
                           y='y_values',
                           line_color=self.line_color,
                           fill_color=self.fill_color,
                           size=self.size,
                           fill_alpha=self.fill_alpha,
                           line_alpha=self.line_alpha)
        yield GlyphRenderer(glyph=glyph)
コード例 #22
0
class VTKVolumePlot(AbstractVTKPlot):
    """
    Bokeh model dedicated to plot a volumetric object with the help of vtk-js
    """

    ambient = Float(default=0.2)

    colormap = String(help="Colormap Name")

    controller_expanded = Bool(default=True,
                               help="""
        If True the volume controller panel options is expanded in the view""")

    data = Nullable(Dict(String, Any))

    diffuse = Float(default=0.7)

    display_slices = Bool(default=False)

    display_volume = Bool(default=True)

    edge_gradient = Float(default=0.2)

    interpolation = Enum(enumeration('fast_linear', 'linear', 'nearest'))

    mapper = Dict(String, Any)

    nan_opacity = Float(default=1)

    render_background = String(default='#52576e')

    rescale = Bool(default=False)

    sampling = Float(default=0.4)

    shadow = Bool(default=True)

    slice_i = Int(default=0)

    slice_j = Int(default=0)

    slice_k = Int(default=0)

    specular = Float(default=0.3)

    specular_power = Float(default=8.)
コード例 #23
0
ファイル: widgets.py プロジェクト: zachlewis/panel
class Audio(Widget):

    __implementation__ = os.path.join(
        os.path.abspath(os.path.dirname(__file__)), 'audio.ts')

    loop = Bool(False, help="""Whether the audio should loop""")

    paused = Bool(False, help="""Whether the audio is paused""")

    time = Float(0,
                 help="""
        The current time stamp of the audio playback""")

    throttle = Int(250,
                   help="""
        The frequency at which the time value is updated in milliseconds.""")

    value = Any(help="Encoded file data")

    volume = Int(0, help="""The volume of the audio player.""")
コード例 #24
0
ファイル: vtk.py プロジェクト: EthanB911/geoVisualization
class VTKVolumePlot(AbstractVTKPlot):
    """
    Bokeh model dedicated to plot a volumetric object with the help of vtk-js
    (3D geometry objects are not suported)
    """

    data = Dict(String, Any)

    colormap = String(help="Colormap Name")

    rescale = Bool(default=False)

    shadow = Bool(default=True)

    sampling = Float(default=0.4)

    edge_gradient = Float(default=0.2)

    ambient = Float(default=0.2)

    diffuse = Float(default=0.7)

    specular = Float(default=0.3)

    specular_power = Float(default=8.)

    slice_i = Int(default=0)

    slice_j = Int(default=0)

    slice_k = Int(default=0)

    display_volume = Bool(default=True)

    display_slices = Bool(default=False)

    render_background = String(default='#52576e')

    interpolation = Enum(enumeration('fast_linear', 'linear', 'nearest'))

    mapper = Dict(String, Any)
コード例 #25
0
class BoxGlyph(AggregateGlyph):
    """Summarizes the distribution with a collection of glyphs.

    A box glyph produces one "box" for a given array of vales. The box
    is made up of multiple other child composite glyphs (intervals,
    scatter) and directly produces glyph renderers for the whiskers,
    as well.
    """

    q1 = Float(help="""Derived value for 25% of all values.""")
    q2 = Float(help="""Derived value for 50% of all values.""")
    q3 = Float(help="""Derived value for 75% of all values.""")
    iqr = Float()

    w0 = Float(help='Lower whisker')
    w1 = Float(help='Upper whisker')

    q2_glyph = Instance(QuartileGlyph)
    q3_glyph = Instance(QuartileGlyph)

    whisker_glyph = Instance(GlyphRenderer)

    outliers = Either(Bool, Instance(PointGlyph))

    marker = String(default='circle')
    whisker_width = Float(default=0.3)
    whisker_line_width = Float(default=2)
    whisker_span_line_width = Float(default=2)
    whisker_color = String(default='black')

    outlier_fill_color = String(default='red')
    outlier_line_color = String(default='red')
    outlier_size = Float(default=5)

    bar_color = String(default='DimGrey')

    def __init__(self, label, values, outliers=True, **kwargs):
        width = kwargs.pop('width', None)

        bar_color = kwargs.pop('color', None) or kwargs.get(
            'bar_color') or self.lookup('bar_color').class_default()

        kwargs['outliers'] = kwargs.pop('outliers', None) or outliers
        kwargs['label'] = label
        kwargs['values'] = values

        x_label = kwargs.get('x_label')
        kwargs['q2_glyph'] = QuartileGlyph(label=label,
                                           x_label=x_label,
                                           values=values,
                                           interval1=0.25,
                                           interval2=0.5,
                                           width=width,
                                           color=bar_color)
        kwargs['q3_glyph'] = QuartileGlyph(label=label,
                                           x_label=x_label,
                                           values=values,
                                           interval1=0.5,
                                           interval2=0.75,
                                           width=width,
                                           color=bar_color)
        super(BoxGlyph, self).__init__(**kwargs)
        self.setup()

    def build_renderers(self):
        """Yields all renderers that make up the BoxGlyph."""

        self.calc_quartiles()
        outlier_values = self.values[((self.values < self.w0) |
                                      (self.values > self.w1))]

        self.whisker_glyph = GlyphRenderer(
            glyph=Segment(x0='x0s',
                          y0='y0s',
                          x1='x1s',
                          y1='y1s',
                          line_width=self.whisker_line_width,
                          line_color=self.whisker_color))

        if len(outlier_values) > 0 and self.outliers:
            self.outliers = PointGlyph(label=self.label,
                                       y=outlier_values,
                                       x=[self.get_dodge_label()] *
                                       len(outlier_values),
                                       line_color=self.outlier_line_color,
                                       fill_color=self.outlier_fill_color,
                                       size=self.outlier_size,
                                       marker=self.marker)

        for comp_glyph in self.composite_glyphs:
            for renderer in comp_glyph.renderers:
                yield renderer

        yield self.whisker_glyph

    def calc_quartiles(self):
        """Sets all derived stat properties of the BoxGlyph."""
        self.q1 = self.q2_glyph.start
        self.q2 = self.q2_glyph.end
        self.q3 = self.q3_glyph.end
        self.iqr = self.q3 - self.q1

        mx = Max()
        mx.set_data(self.values)

        mn = Min()
        mn.set_data(self.values)

        self.w0 = max(self.q1 - (1.5 * self.iqr), mn.value)
        self.w1 = min(self.q3 + (1.5 * self.iqr), mx.value)

    def build_source(self):
        """Calculate stats and builds and returns source for whiskers."""
        self.calc_quartiles()
        x_label = self.get_dodge_label()
        x_w0_label = self.get_dodge_label(shift=(self.whisker_width / 2.0))
        x_w1_label = self.get_dodge_label(shift=-(self.whisker_width / 2.0))

        # span0, whisker bar0, span1, whisker bar1
        x0s = [x_label, x_w0_label, x_label, x_w0_label]
        y0s = [self.w0, self.w0, self.q3, self.w1]
        x1s = [x_label, x_w1_label, x_label, x_w1_label]
        y1s = [self.q1, self.w0, self.w1, self.w1]

        return dict(x0s=x0s, y0s=y0s, x1s=x1s, y1s=y1s)

    def _set_sources(self):
        """Set the column data source on the whisker glyphs."""
        self.whisker_glyph.data_source = self.source

    def get_extent(self, func, prop_name):
        return func([
            getattr(renderer, prop_name) for renderer in self.composite_glyphs
        ])

    @property
    def composite_glyphs(self):
        """Returns list of composite glyphs, excluding the regular glyph renderers."""
        comp_glyphs = [self.q2_glyph, self.q3_glyph]
        if isinstance(self.outliers, PointGlyph):
            comp_glyphs.append(self.outliers)
        return comp_glyphs

    @property
    def x_max(self):
        return self.get_extent(max, 'x_max') + self.right_buffer

    @property
    def x_min(self):
        return self.get_extent(min, 'x_min') - self.left_buffer

    @property
    def y_max(self):
        return max(self.w1, self.get_extent(max, 'y_max')) + self.top_buffer

    @property
    def y_min(self):
        return min(self.w0, self.get_extent(min, 'y_min')) - self.bottom_buffer
コード例 #26
0
class Interval(AggregateGlyph):
    """A rectangle representing aggregated values.

    The interval is a rect glyph where two of the parallel sides represent a
    summary of values. Each of the two sides is derived from a separate aggregation of
    the values provided to the interval.

    .. note::
        A bar is a special case interval where one side is pinned and used to
        communicate a value relative to it.
    """

    width = Float(default=0.8)
    start_agg = Either(Instance(Stat),
                       Enum(*list(stats.keys())),
                       default=Min(),
                       help="""
        The stat used to derive the starting point of the composite glyph.""")
    end_agg = Either(Instance(Stat),
                     Enum(*list(stats.keys())),
                     default=Max(),
                     help="""
        The stat used to derive the end point of the composite glyph.""")

    start = Float(default=0.0)
    end = Float()

    def __init__(self, label, values, **kwargs):

        kwargs['label'] = label
        kwargs['values'] = values

        super(Interval, self).__init__(**kwargs)
        self.setup()

    def get_start(self):
        """Get the value for the start of the glyph."""
        if len(self.values.index) == 1:
            self.start_agg = None
            return self.values[0]
        elif isinstance(self.start_agg, str):
            self.start_agg = stats[self.start_agg]()

        self.start_agg.set_data(self.values)
        return self.start_agg.value

    def get_end(self):
        """Get the value for the end of the glyph."""
        if isinstance(self.end_agg, str):
            self.end_agg = stats[self.end_agg]()

        self.end_agg.set_data(self.values)
        return self.end_agg.value

    def get_span(self):
        """The total range between the start and end."""
        return self.end - self.start

    def build_source(self):
        # ToDo: Handle rotation
        self.start = self.get_start()
        self.end = self.get_end()
        self.span = self.get_span()

        width = [self.width]
        if self.dodge_shift is not None:
            x = [self.get_dodge_label()]
        else:
            x = [self.x_label]
        height = [self.span]
        y = [self.stack_shift + (self.span / 2.0) + self.start]
        color = [self.color]
        fill_alpha = [self.fill_alpha]
        line_color = [self.line_color]
        line_alpha = [self.line_alpha]
        label = [self.label]

        return dict(x=x,
                    y=y,
                    width=width,
                    height=height,
                    color=color,
                    fill_alpha=fill_alpha,
                    line_color=line_color,
                    line_alpha=line_alpha,
                    label=label)

    @property
    def x_max(self):
        """The maximum extent of the glyph in x.

        .. note::
            Dodging the glyph can affect the value.
        """
        return (self.dodge_shift or self.x_label_value) + (self.width / 2.0)

    @property
    def x_min(self):
        """The maximum extent of the glyph in y.

        .. note::
            Dodging the glyph can affect the value.
        """
        return (self.dodge_shift or self.x_label_value) - (self.width / 2.0)

    @property
    def y_max(self):
        """Maximum extent of all `Glyph`s.

        How much we are stacking + the height of the interval + the base of the interval

        .. note::
            the start and end of the glyph can swap between being associated with the
            min and max when the glyph end represents a negative value.
        """
        return max(self.bottom, self.top)

    @property
    def y_min(self):
        """The minimum extent of all `Glyph`s in y.

        .. note::
            the start and end of the glyph can swap between being associated with the
            min and max when the glyph end represents a negative value.
        """
        return min(self.bottom, self.top)

    @property
    def bottom(self):
        """The value associated with the start of the stacked glyph."""
        return self.stack_shift + self.start

    @property
    def top(self):
        """The value associated with the end of the stacked glyph."""
        return self.stack_shift + self.span + self.start

    def build_renderers(self):
        """Yields a `GlyphRenderer` associated with a `Rect` glyph."""
        glyph = Rect(x='x',
                     y='y',
                     width='width',
                     height='height',
                     fill_color='color',
                     fill_alpha='fill_alpha',
                     line_color='line_color')
        yield GlyphRenderer(glyph=glyph)
コード例 #27
0
class AggregateGlyph(NestedCompositeGlyph):
    """A base composite glyph for aggregating an array.

    Implements default stacking and dodging behavior that other composite
    glyphs can inherit.
    """

    x_label = String()
    x_label_value = Any()

    stack_label = String()
    stack_shift = Float(default=0.0)

    dodge_label = String(
        help="""Where on the scale the glyph should be placed.""")
    dodge_shift = Float(default=None)

    agg = Instance(Stat, default=Sum())

    span = Float(help="""The range of values represented by the aggregate.""")

    def __init__(self, x_label=None, **kwargs):

        label = kwargs.get('label')
        if x_label is not None:
            kwargs['x_label_value'] = x_label

            if not isinstance(x_label, str):
                x_label = str(x_label)

            kwargs['x_label'] = x_label
        elif label is not None:
            kwargs['x_label'] = str(label)

        super(AggregateGlyph, self).__init__(**kwargs)

    def get_dodge_label(self, shift=0.0):
        """Generate the label defining an offset in relation to a position on a scale."""
        if self.dodge_shift is None:
            shift_str = ':' + str(0.5 + shift)
        elif self.dodge_shift is not None:
            shift_str = ':' + str(self.dodge_shift + shift)
        else:
            shift_str = ''

        return str(label_from_index_dict(self.x_label)) + shift_str

    def filter_glyphs(self, glyphs):
        """Return only the glyphs that are of the same class."""
        return [glyph for glyph in glyphs if isinstance(glyph, self.__class__)]

    @staticmethod
    def groupby(glyphs, prop):
        """Returns a dict of `CompositeGlyph`s, grouped by unique values of prop.

        For example, if all glyphs had a value of 'a' or 'b' for glyph.prop, the dict
        would contain two keys, 'a' and 'b', where each value is a list of the glyphs
        that had each of the values.
        """
        grouped = defaultdict(list)
        labels = [getattr(glyph, prop) for glyph in glyphs]
        labels = [
            tuple(label.values()) if isinstance(label, dict) else label
            for label in labels
        ]
        [grouped[label].append(glyph) for label, glyph in zip(labels, glyphs)]
        labels = pd.Series(labels).drop_duplicates().values
        return labels, grouped

    def __stack__(self, glyphs):
        """Apply relative shifts to the composite glyphs for stacking."""
        filtered_glyphs = self.filter_glyphs(glyphs)
        labels, grouped = self.groupby(filtered_glyphs, 'x_label')

        for label in labels:
            group = grouped[label]

            # separate the negative and positive aggregates into separate groups
            neg_group = [glyph for glyph in group if glyph.span < 0]
            pos_group = [glyph for glyph in group if glyph.span >= 0]

            # apply stacking to each group separately
            for group in [neg_group, pos_group]:
                shift = []
                for i, glyph in enumerate(group):
                    # save off the top of each rect's height
                    shift.append(glyph.span)
                    if i > 0:
                        glyph.stack_shift = sum(shift[0:i])
                        glyph.refresh()

    def __dodge__(self, glyphs):
        """Apply relative shifts to the composite glyphs for dodging."""
        if self.dodge_label is not None:
            filtered_glyphs = self.filter_glyphs(glyphs)
            labels, grouped = self.groupby(filtered_glyphs, 'dodge_label')

            # calculate transformations
            step = np.linspace(0, 1.0, len(grouped.keys()) + 1, endpoint=False)
            width = min(0.2, (1. / len(grouped.keys()))**1.1)

            # set bar attributes and re-aggregate
            for i, label in enumerate(labels):
                group = grouped[label]
                for glyph in group:
                    glyph.dodge_shift = step[i + 1]
                    glyph.width = width
                    glyph.refresh()
コード例 #28
0
class HorizonGlyph(AreaGlyph):
    num_folds = Int(default=3,
                    help="""The count of times the data is overlapped.""")

    series = Int(default=0,
                 help="""The id of the series as the order it will appear,
    starting from 0.""")

    series_count = Int()

    fold_height = Float(help="""The height of one fold.""")

    bins = List(Float,
                help="""The binedges calculated from the number of folds,
    and the maximum value of the entire source data.""")

    graph_ratio = Float(
        help="""Scales heights of each series based on number of folds
    and the number of total series being plotted.
    """)

    pos_color = Color("#006400",
                      help="""The color used for positive values.""")
    neg_color = Color("#6495ed",
                      help="""The color used for negative values.""")

    flip_neg = Bool(default=True,
                    help="""When True, the negative values will be
    plotted as their absolute value, then their individual axes is flipped. If False,
    then the negative values will still be taken as their absolute value, but the base
    of their shape will start from the same origin as the positive values.
    """)

    def __init__(self, bins=None, **kwargs):

        # fill alpha depends on how many folds will be layered
        kwargs['fill_alpha'] = 1.0 / kwargs['num_folds']

        if bins is not None:
            kwargs['bins'] = bins

            # each series is shifted up to a synthetic y-axis
            kwargs['base'] = kwargs['series'] * max(
                bins) / kwargs['series_count']
            kwargs['graph_ratio'] = float(kwargs['num_folds']) / float(
                kwargs['series_count'])

        super(HorizonGlyph, self).__init__(**kwargs)

    def build_source(self):
        data = {}

        # Build columns for the positive values
        pos_y = self.y.copy()
        pos_y[pos_y < 0] = 0
        xs, ys = self._build_dims(self.x, pos_y)

        # list of positive colors and alphas
        colors = [self.pos_color] * len(ys)
        alphas = [(bin_idx * self.fill_alpha)
                  for bin_idx in range(0, len(self.bins))]

        # If we have negative values at all, add the values for those as well
        if self.y.min() < 0:
            neg_y = self.y.copy()
            neg_y[neg_y > 0] = 0
            neg_y = abs(neg_y)
            neg_xs, neg_ys = self._build_dims(self.x, neg_y, self.flip_neg)

            xs += neg_xs
            ys += neg_ys
            colors += ([self.neg_color] * len(neg_ys))
            alphas += alphas

        # create clipped representation of each band
        data['x_values'] = xs
        data['y_values'] = ys
        data['fill_color'] = colors
        data['fill_alpha'] = colors
        data['line_color'] = colors

        return data

    def _build_dims(self, x, y, flip=False):
        """ Creates values needed to plot each fold of the horizon glyph.

        Bins the data based on the binning passed into the glyph, then copies and clips
        the values for each bin.

        Args:
            x (`pandas.Series`): array of x values
            y (`pandas.Series`): array of y values
            flip (bool): whether to flip values, used when handling negative values

        Returns:
            tuple(list(`numpy.ndarray`), list(`numpy.ndarray`)): returns a list of
                arrays for the x values and list of arrays for the y values. The data
                has been folded and transformed so the patches glyph presents the data
                in a way that looks like an area chart.
        """

        # assign bins to each y value
        bin_idx = pd.cut(y, bins=self.bins, labels=False, include_lowest=True)

        xs, ys = [], []
        for idx, bin in enumerate(self.bins[0:-1]):

            # subtract off values associated with lower bins, to get into this bin
            temp_vals = y.copy() - (idx * self.fold_height)

            # clip the values between the fold range and zero
            temp_vals[bin_idx > idx] = self.fold_height * self.graph_ratio
            temp_vals[bin_idx < idx] = 0
            temp_vals[bin_idx ==
                      idx] = self.graph_ratio * temp_vals[bin_idx == idx]

            # if flipping, we must start the values from the top of each fold's range
            if flip:
                temp_vals = (self.fold_height * self.graph_ratio) - temp_vals
                base = self.base + (self.fold_height * self.graph_ratio)
            else:
                base = self.base

            # shift values up based on index of series
            temp_vals += self.base
            val_idx = temp_vals > 0
            if pd.Series.any(val_idx):
                ys.append(temp_vals)
                xs.append(x)

        # transform clipped data so it always starts and ends at its base value
        if len(ys) > 0:
            xs, ys = map(
                list,
                zip(*[
                    generate_patch_base(xx, yy, base=base)
                    for xx, yy in zip(xs, ys)
                ]))

        return xs, ys

    def build_renderers(self):
        # parse all series. We exclude the first attr as it's the x values
        # added for the index
        glyph = Patches(xs='x_values',
                        ys='y_values',
                        fill_alpha=self.fill_alpha,
                        fill_color='fill_color',
                        line_color='line_color')
        renderer = GlyphRenderer(data_source=self.source, glyph=glyph)
        yield renderer
コード例 #29
0
class AreaGlyph(LineGlyph):

    # ToDo: should these be added to composite glyph?
    stack = Bool(default=False)
    dodge = Bool(default=False)

    base = Float(default=0.0, help="""Lower bound of area.""")

    def __init__(self, **kwargs):
        line_color = kwargs.get('line_color')
        fill_color = kwargs.get('fill_color')
        color = kwargs.get('color')

        if color is not None:
            # apply color to line and fill
            kwargs['fill_color'] = color
            kwargs['line_color'] = color
        elif line_color is not None and fill_color is None:
            # apply line color to fill color by default
            kwargs['fill_color'] = line_color

        super(AreaGlyph, self).__init__(**kwargs)
        self.setup()

    def build_source(self):
        data = super(AreaGlyph, self).build_source()

        x0, y0 = generate_patch_base(pd.Series(list(data['x_values'])),
                                     pd.Series(list(data['y_values'])))

        data['x_values'] = [x0]
        data['y_values'] = [y0]

        return data

    def build_renderers(self):

        # parse all series. We exclude the first attr as it's the x values
        # added for the index
        glyph = Patches(xs='x_values',
                        ys='y_values',
                        fill_alpha=self.fill_alpha,
                        fill_color=self.fill_color,
                        line_color=self.line_color)
        renderer = GlyphRenderer(data_source=self.source, glyph=glyph)
        yield renderer

    def __stack__(self, glyphs):

        # ToDo: need to handle case of non-aligned indices, see pandas concat
        # ToDo: need to address how to aggregate on an index when required

        # build a list of series
        areas = []
        for glyph in glyphs:
            areas.append(
                pd.Series(glyph.source.data['y_values'][0],
                          index=glyph.source.data['x_values'][0]))

        # concat the list of indexed y values into dataframe
        df = pd.concat(areas, axis=1)

        # calculate stacked values along the rows
        stacked_df = df.cumsum(axis=1)

        # lower bounds of each area series are diff between stacked and orig values
        lower_bounds = stacked_df - df

        # reverse the df so the patch is drawn in correct order
        lower_bounds = lower_bounds.iloc[::-1]

        # concat the upper and lower bounds together
        stacked_df = pd.concat([stacked_df, lower_bounds])

        # update the data in the glyphs
        for i, glyph in enumerate(glyphs):
            glyph.source.data['x_values'] = [stacked_df.index.values]
            glyph.source.data['y_values'] = [stacked_df.ix[:, i].values]

    def get_nested_extent(self, col, func):
        return [getattr(arr, func)() for arr in self.source.data[col]]

    @property
    def x_max(self):
        return max(self.get_nested_extent('x_values', 'max'))

    @property
    def x_min(self):
        return min(self.get_nested_extent('x_values', 'min'))

    @property
    def y_max(self):
        return max(self.get_nested_extent('y_values', 'max'))

    @property
    def y_min(self):
        return min(self.get_nested_extent('y_values', 'min'))
コード例 #30
0
class BinGlyph(XyGlyph):
    """Represents a group of data that was aggregated and is represented by a glyph.

    """
    bins = Instance(Bins)
    column = String()
    stat = String()

    glyph_name = String()

    width = Float()
    height = Float()

    def __init__(self,
                 x,
                 y,
                 values,
                 column=None,
                 stat='count',
                 glyph='rect',
                 width=1,
                 height=1,
                 **kwargs):
        df = pd.DataFrame(dict(x_vals=x, y_vals=y, values_vals=values))
        df.drop_duplicates(inplace=True)

        kwargs['x'] = df.x_vals
        kwargs['y'] = df.y_vals
        kwargs['values'] = df.values_vals
        kwargs['column'] = column
        kwargs['stat'] = stat
        kwargs['glyph_name'] = glyph
        kwargs['height'] = height
        kwargs['width'] = width
        if 'glyphs' not in kwargs:
            kwargs['glyphs'] = {'rect': Rect}
        super(XyGlyph, self).__init__(**kwargs)
        self.setup()

    def build_source(self):
        return {'x': self.x, 'y': self.y, 'values': self.values}

    def build_renderers(self):
        glyph_class = self.glyphs[self.glyph_name]
        glyph = glyph_class(x='x',
                            y='y',
                            height=self.height,
                            width=self.width,
                            fill_color=self.fill_color,
                            line_color=self.line_color,
                            dilate=True)
        yield GlyphRenderer(glyph=glyph)

    @property
    def x_max(self):
        return self.get_data_range('x')[1] + self.width / 2.0

    @property
    def x_min(self):
        return self.get_data_range('x')[0] - self.width / 2.0

    @property
    def y_max(self):
        return self.get_data_range('y')[1] + self.height / 2.0

    @property
    def y_min(self):
        return self.get_data_range('y')[0] - self.height / 2.0

    def get_data_range(self, col):
        data = self.source.data[col]
        if ChartDataSource.is_number(data):
            return min(data), max(data)
        else:
            return 1, len(data.drop_duplicates())
コード例 #31
0
ファイル: test_validation.py プロジェクト: jakirkham/bokeh
 def test_Float(self, detail):
     p = Float()
     with pytest.raises(ValueError) as e:
         p.validate("junk", detail)
     assert str(e).endswith("ValueError") == (not detail)
コード例 #32
0
ファイル: test_validation.py プロジェクト: jakirkham/bokeh
 def test_Float(self):
     p = Float()
     with pytest.raises(ValueError) as e:
         p.validate("junk")
     assert not str(e).endswith("ValueError")