Example #1
0
def _parse_mark_ecdf(mark):
    """Parse mark for ECDF."""
    if mark in ['point', 'circle', 'square', 'line']:
        return alt.MarkDef(type=mark)

    if type(mark) != dict:
        raise RuntimeError("""`mark` must be a dict or be one of:
                'point'
                'circle'
                'square'
                'line'""")

    return alt.MarkDef(**mark)
Example #2
0
 def base(self, internal=False, **kwargs):
     self._parseArgs(call='base', **kwargs)
     if internal:
         if self.double:
             return self._double()
         else:
             base = alt.Chart(
                 self.source,
                 mark=alt.MarkDef(self.kind, **self.baseMark)).encode(
                     x=alt.X(f'{self.x + self.x_type}',
                             title=self.x_label,
                             scale=alt.Scale(**self.xScale),
                             axis=alt.Axis(format=self.x_format,
                                           **self.xAxis),
                             **self.xObj),
                     y=alt.Y(f'value:Q',
                             title=self.y_label,
                             scale=alt.Scale(type=self.scale,
                                             **self.yScale),
                             axis=alt.Axis(format=self.y_format,
                                           **self.yAxis),
                             **self.yObj),
                     **self._color,
                 ).properties(**self.prop).interactive()
             self._base = base
     return self
Example #3
0
    def _double(self):
        if isinstance(self.double, str):
            first, other = self._queries([self.double])
        elif isinstance(self.double, list) or isinstance(self.double, set):
            first, other = self._queries(self.double)
        else:
            raise ValueError('Double arguments not understood.')
        chart_one = alt.Chart(
            self.source,
            mark=alt.MarkDef(self.kind, clip=True, **self.baseMark)).encode(
                x=alt.X(f'{self.x + self.x_type}',
                        title=self.x_label,
                        scale=alt.Scale(**self.xScale),
                        axis=alt.Axis(format=self.x_format,
                                      labelAngle=-25,
                                      **self.xAxis),
                        **self.xObj),
                y=alt.Y(f'value:Q',
                        title=self.y_label,
                        scale=alt.Scale(type=self.scale, **self.yScale),
                        axis=alt.Axis(format=self.y_format, **self.yAxis),
                        **self.yObj),
                **self._color,
            ).transform_filter(first)

        chart_two = alt.Chart(
            self.source,
            mark=alt.MarkDef(self._kind, clip=True, **self.base2Mark)).encode(
                x=alt.X(f'{self.x + self.x_type}',
                        title=self.x_label,
                        scale=alt.Scale(**self.xScale),
                        axis=alt.Axis(format=self.x_format,
                                      labelAngle=-25,
                                      **self.xAxis),
                        **self.xObj),
                y=alt.Y(f'value:Q',
                        title=self._y_label,
                        scale=alt.Scale(type=self._scale, **self.y2Scale),
                        axis=alt.Axis(format=self._y_format, **self.y2Axis),
                        **self.y2Obj),
                **self._color,
            ).transform_filter(other)

        self._base = alt.layer(chart_one, chart_two).properties(
            **self.prop).resolve_scale(y='independent').interactive()
        return self
Example #4
0
def _parse_mark_jitter(mark, horizontal):
    """Parse mark for jitter plot."""
    if mark in ['point', 'circle', 'square']:
        mark_jitter = alt.MarkDef(type=mark)
    elif type(mark) != dict:
        raise RuntimeError("""`mark` must be a dict or be one of:
                'point'
                'circle'
                'square'""")
    else:
        mark_jitter = alt.MarkDef(**mark)

    if horizontal:
        mark_text = alt.MarkDef(type='text',
                                baseline='middle',
                                align='right',
                                dx=-8)
    else:
        mark_text = alt.MarkDef(type='text',
                                baseline='top',
                                align='center',
                                dy=8)

    return mark_jitter, mark_text
Example #5
0
def scatterplot(data=None,
                x=0,
                y=1,
                color=None,
                opacity=1,
                tooltip=None,
                height=600,
                width=800):
    """Generate a scatterplot."""
    if color is not None:
        if isinstance(data[color].iloc[0], Number):
            color = alt.Color(
                color,
                scale=hue_scale_light if opacity == 1 else hue_scale_dark)
    opt_args = choose_kwargs(locals(), ["color", "tooltip"])
    return alt.Chart(
        data,
        height=height,
        width=width,
        mark=alt.MarkDef(type="point" if opacity == 1 else "circle",
                         opacity=opacity),
    ).encode(x=x, y=y, **opt_args)
Example #6
0
def generate_chart(df,
                   y_name,
                   var_name,
                   var_order=None,
                   mark='area',
                   stack=None,
                   zoom=False,
                   unit='M'):
    """
    Generate interactive altair chart from DataFrame:
    - Converts df from wide-form to long-form
    - Transforms index name to lowercase.
    - Sets domain based on min x and max.
    - Formats x based on type (datetime or int)
    - Creates interactive legend based on number of categories

    Parameters
    ==========
    :param df: DataFrame.
    :param y_name: string
        Name for value on the y-axis.
    :param var_name: string
        Name of the category variable.

    Optional keyword arguments
    ==========================
    :param var_order: list, default None
        Order in which the category names in var_name should be displayed in the legend.
    :param mark: {'bar', 'circle', 'square', 'tick', 'line', 'area', 'point', 'rule', and 'text'}, default 'area'
        Mark type.
    :param stack: {'zero', 'normalize', 'center'} or None, default None
        Option to stack chart.
    :param zoom: boolean, default False
        Option to add vertical zoom to chart.
    """
    def to_altair_datetime(dt):
        dt = pd.to_datetime(dt)
        return alt.DateTime(year=dt.year, month=dt.month, date=dt.day)

    x = df.index.name = df.index.name.lower()
    if isinstance(df.index, pd.DatetimeIndex):
        altx = x + ':T'
        xmin = to_altair_datetime(df.index.min())
        xmax = to_altair_datetime(df.index.max())
        formatx = DATE_FORMAT[unit]
        ticks = [
            to_altair_datetime(date) for date in pd.date_range(
                df.index.min(), df.index.max(), freq=unit).tolist()
        ]
    else:
        altx = x + ':Q'
        xmin = df.index.min()
        xmax = df.index.max()
        formatx = 'd'
        ticks = list(range(xmin, xmax))
    domainx = (xmin, xmax)

    df = df.rename(columns=str).reset_index().melt(x,
                                                   var_name=var_name,
                                                   value_name=y_name)

    if not var_order:
        var_order = df[var_name].unique().tolist()

    height = 30 * len(var_order)
    source = df

    # selections
    multi = alt.selection_multi(fields=[var_name], empty='all')
    brushx = alt.selection_interval(encodings=['x'])
    if zoom:
        x = None
        domainx = brushx.ref()

    # interactive legend
    ilegend = alt.Chart(source, width=30,
                        height=height).mark_square(cursor='pointer').encode(
                            y=alt.Y(
                                f'{var_name}:N',
                                axis=alt.Axis(title=var_name,
                                              ticks=False,
                                              labelPadding=5,
                                              domain=False),
                                sort=alt.Sort(var_order),
                            ),
                            size=alt.condition(
                                multi,
                                alt.value(200),
                                alt.value(100),
                            ),
                            color=alt.condition(
                                multi,
                                alt.Color(f'{var_name}:N', legend=None),
                                alt.value('lightgray'),
                            ),
                        ).properties(selection=multi)

    # chart
    chart = alt.Chart(source, width=600,
                      mark=alt.MarkDef(mark, clip=True)).encode(
                          x=alt.X(
                              altx,
                              scale=alt.Scale(domain=domainx, nice=False),
                              axis=alt.Axis(title=x,
                                            format=formatx,
                                            values=ticks),
                          ),
                          y=alt.Y(
                              f'{y_name}:Q',
                              stack=stack,
                          ),
                          color=alt.Color(f'{var_name}:N', legend=None),
                          order=alt.Order(f'{var_name}:N', sort='descending'),
                      ).transform_filter(multi)

    # zoom
    zoomview = chart.encode(
        x=alt.X(
            altx,
            scale=alt.Scale(nice=False),
            axis=alt.Axis(format=formatx),
        ),
        y=alt.Y(
            f'{y_name}:Q',
            axis=alt.Axis(title=None),
        ),
    ).properties(height=60).add_selection(brushx)

    # combine
    if zoom:
        figure = ((chart & zoomview) | ilegend)
    else:
        figure = chart | ilegend

    return figure
Example #7
0
def generate_bin_chart(df, y_name, var_name, var_order=None):
    """
    Generate interactive altair chart from DataFrame:
    - Converts df from wide-form to long-form
    - Transforms index name to lowercase.
    - Creates interactive legend based on number of categories

    Parameters
    ==========
    :param df: DataFrame.
    :param y_name: string
        Name for value on the y-axis.
    :param var_name: string
        Name of categorized variable.

    Optional keyword arguments
    ==========================
    :param var_order: list or None, default None
        Order in which the category names in var_name should be displayed in the legend.
    """

    bin_sort = df.index.tolist()
    x = df.index.name = df.index.name.lower()
    df = df.rename(columns=str).reset_index().melt(x,
                                                   var_name=var_name,
                                                   value_name=y_name)

    if not var_order:
        var_order = df[var_name].unique().tolist()

    height = 30 * len(var_order)
    source = df

    # selections
    multi = alt.selection_multi(fields=[var_name], empty='all')

    # interactive legend
    ilegend = alt.Chart(source, width=30,
                        height=height).mark_square(cursor='pointer').encode(
                            y=alt.Y(
                                f'{var_name}:N',
                                axis=alt.Axis(title=var_name,
                                              ticks=False,
                                              labelPadding=5,
                                              domain=False),
                                sort=alt.Sort(var_order),
                            ),
                            size=alt.condition(
                                multi,
                                alt.value(200),
                                alt.value(100),
                            ),
                            color=alt.condition(
                                multi,
                                alt.Color(f'{var_name}:N', legend=None),
                                alt.value('lightgray'),
                            ),
                        ).properties(selection=multi)

    # chart
    chart = alt.Chart(source, width=600,
                      mark=alt.MarkDef('bar', clip=True)).encode(
                          x=alt.X(f'{x}:O', sort=bin_sort),
                          y=alt.Y(
                              f'{y_name}:Q',
                              stack='zero',
                          ),
                          color=alt.Color(f'{var_name}:N', legend=None),
                          order=alt.Order(f'{var_name}:N', sort='descending'),
                      ).transform_filter(multi)

    # combine
    figure = chart | ilegend

    return figure