Bubble

Note

This help should be accurate and comprehensive. If you see anything missing or that needs to be fixed, see How to Contribute or let us know in the Juice Slack #documentation channel.

A Bubble slice includes a group of categorized circles. Click on or hover over a circle to reveal other circles nested in it, representing a level of hierarchy.

Bubble config

Bubble slices support the Common configuration options for all slices. Additional options are:

descriptionTemplateName

CSS selector of the template that is supposed to render selected node’s details/description in the breadcrumb,

Optional:

Yes, there is a default template that renders the label

Values:

CSS selector

Example:

config:

descriptionTemplateName: “#bubble-description-template”

tooltipTemplateName

CSS selector of the template that is supposed to display the tooltip for the hovered bubble

Optional:

Yes, there is a default template that renders the label

Values:

CSS selector

Example:

config:

descriptionTemplateName: “#bubble-tooltip-template”

colorFieldRange

Min/max values of a color field. This range defines the bubble’s circle fill color. The text label color (on top of that circle) is determined by the front-end dynamically. The app tries to use complimentary/inverse color for text for easier readability (eg. dark text on light circle).

Optional:

yes, by default the app will dynamically calculate the range of the colorField values in the data

Values:

array of two numeric values

Example:

config:

colorFieldRange: “[0, 100]”

colorField

Name of the field in the data item that will be used to map to the color of a bubble. This field defines the bubble’s circle fill color. The text label color (on top of that circle) is determined by the front-end dynamically. The app tries to use complimentary/inverse color for text for easier readability (eg. dark text on light circle).

Optional:

yes, default is value

Values:

string

Example:

config:

colorField: “myColorField”

sizeField

Name of the field in the data item that will be used to map to the size of a bubble

Optional:

yes, default is value

Values:

string

Example:

config:

sizeField: “mySizeField”

popSound

A URL to the sound that should play when a bubble is “popped”

Optional:

yes, by default there is no sound

Values:

URL string

Example:
config:
  popSound: "http://soundbible.com/mp3/Punch_HD-Mark_DiAngelo-1718986183.mp3"

height (bubble)

The height (in px) of the chart

Optional:

yes, default is 400

Values:

number

Example:
config:
  popSound: 500

Flavors of Bubble

There is a default renderer that can be used. This renderer works for fixed hierarchies only (like country/region/city). Dynamic trees (like a company’s reporting structure aren’t supported).

This renderer works by gathering data from a recipe at each level of the hierarchy. The data is then structured into a tree.

sizeField (bubble)

Optional:yes, (uses config.sizeField if not provided). This metric must be used in the recipe(s)
Values:string

colorField (bubble)

Optional:yes, (uses config.colorField if not provided). This metric must be used in the recipe(s)
Values:string

group_by_type

All selections in a slice must have the same group_by_type. If the bubble has more than one level, set a group_by_type.

Optional:yes, uses the first level if not provided.
Values:string

Note

group_by_type and slice item ids

Slices must have a single group by type but hierarchical slices support selection at multiple levels of the hierarchy. For instance if the hierarchy were country/region/city, a user can perform selections at multiple levels, like: Canada, United States/Tennessee and Germany/Bavaria/Munich.

The render_config should include a group_by_type and the ids of the levels will be concatenated using a ‘~’

render_config={'group_by_type': 'country_hierarchy',
'levels': ['country', 'region', 'city']}

The selection that lower slices receive would look like

country_hierarchy: ['Canada', 'United States~Tennessee', 'Germany~Bavaria~Munich']

Slices receiving this filtering need to use custom filters to decide what to do with these selections.

levels

A list of levels to use in the bubble. Generally the same as the dimensions used in the recipe. These have to be specified explicitly because dimension order is not maintained in recipes.

Optional:no, A list of levels to use in the bubble. Generally the same as the dimensions used in the recipe. These have to be specified explicitly because dimension order is not maintained in recipes.
Values:list of strings

levelsData

An optional list of data at each level starting from the root. Must be have length one greater than levels because it includes the root data.

Optional:yes
Values:list of recipe.all()

Note

When to use levelsData

If levelsData isn’t supplied, the renderer will generate recipes for all levels above the rendered recipe. These recipes will be generic, they won’t include any extra filtering that the rendered recipe used. So if the rendered recipe just uses dimensions and metrics you can use this automatic behavior. If the rendered recipe uses filtering, you need to construct a recipe for each level.

Here’s an example of levelsData in action. It’s needed because the recipes use the filter Census.age>60

def build_response(self):
        metrics = ('avgage', 'pop2000')
        dims = ('first_letter_state', 'state')
        recipe = self.recipe().dimensions(*dims).metrics(*metrics)
        levelsData = [
        self.recipe().dimensions().metrics(*metrics).filters(Census.age>60).all(),
        self.recipe().dimensions('first_letter_state').metrics(*metrics).filters(Census.age>60).all(),
        self.recipe().dimensions('first_letter_state', 'state').metrics(*metrics).filters(Census.age>60).all(),
        ]
        self.response['responses'].append(recipe.render(
        render_config={
                'levels': dims,
                'colorField': metrics[0],
                'sizeField': metrics[1],
                'levelsData': levelsData
        }))

Examples of Bubble Renderer

Here are some examples of the bubble slice renderer.

One level (group_by_type will be state)

def build_response(self):
    metrics = ('avgage', 'pop2000')
    dims = ('state',)
    recipe = self.recipe().dimensions(*dims).metrics(*metrics)
    self.response['responses'].append(recipe.render(
        render_config={
            'levels': dims,
        }))
../../../_images/bubble-renderer-onelevel.png

Three level with custom group_by_type

When using multiple levels it’s recommended to use a custom group_by_type

def build_response(self):
    metrics = ('avgage', 'pop2000')
    dims = ('first_letter_state', 'state', 'sex')
    recipe = self.recipe().dimensions(*dims).metrics(*metrics)
    self.response['responses'].append(recipe.render(
        render_config={
            'levels': dims,
            'colorField': metrics[0],
            'sizeField': metrics[1],
            'group_by_type': 'bubble',
        }))
../../../_images/bubble-renderer-threelevel.png

Two level with custom filtering

Custom filtering means you need to supply levelData. This filtering is limiting data to people with age over 60.

def build_response(self):
    metrics = ('avgage', 'pop2000')
    dims = ('first_letter_state', 'state')
    recipe = self.recipe().dimensions(*dims).metrics(*metrics)
    levelsData = [
        self.recipe().dimensions().metrics(*metrics).filters(Census.age>60).all(),
        self.recipe().dimensions('first_letter_state').metrics(*metrics).filters(Census.age>60).all(),
        self.recipe().dimensions('first_letter_state', 'state').metrics(*metrics).filters(Census.age>60).all(),
    ]
    self.response['responses'].append(recipe.render(
        render_config={
            'levels': dims,
            'colorField': metrics[0],
            'sizeField': metrics[1],
            'group_by_type': 'bubble',
            'levelsData': levelsData
        }))
../../../_images/bubble-renderer-customfiltering.png