Example #1
0
    def group_values(chart_type, group_cols, map_group_cols, pathname, inputs,
                     prev_group_vals):
        group_cols = make_list(group_cols)
        if show_input_handler(chart_type
                              or 'line')('group') and not len(group_cols):
            return [], None
        elif chart_type == 'maps':  # all maps have a group input
            group_cols = make_list(map_group_cols)
            if not len(group_cols):
                return [], None
        data_id = get_data_id(pathname)
        group_vals = run_query(global_state.get_data(data_id),
                               inputs.get('query'),
                               global_state.get_context_variables(data_id))
        group_vals = build_group_val_options(group_vals, group_cols)
        selections = []
        available_vals = [gv['value'] for gv in group_vals]
        if prev_group_vals is not None:
            selections = [
                pgv for pgv in prev_group_vals if pgv in available_vals
            ]
        if not len(selections) and len(group_vals) <= MAX_GROUPS:
            selections = available_vals

        return group_vals, selections
Example #2
0
def build_drilldown_title(data_id, all_inputs, click_point, props, val_prop):
    data = global_state.get_data(data_id)

    def _build_val(col, val):
        if classify_type(find_dtype(data[col])) == "D":
            return json_date(convert_date_val_to_date(val))
        return val

    if "text" in click_point:  # Heatmaps
        strs = []
        for dim in click_point["text"].split("<br>"):
            prop, val = dim.split(": ")
            strs.append("{} ({})".format(prop, val))
        return "{}: {}".format(text("Drilldown for"), ", ".join(strs))

    strs = []
    frame_col = all_inputs.get("animate_by")
    if frame_col:
        strs.append("{} ({})".format(frame_col, click_point.get("customdata")))
    for prop in props:
        prop = make_list(prop)
        val_key = prop[0]
        if click_point.get(val_key) is not None:
            col = make_list(all_inputs.get(prop[-1]))[0]
            strs.append("{} ({})".format(
                col, _build_val(col, click_point.get(val_key))))

    val_prop = make_list(val_prop)
    val_key = val_prop[0]
    val_col = make_list(all_inputs.get(val_prop[-1]))[0]
    agg = AGGS[all_inputs.get("agg") or "raw"]
    strs.append("{} {} ({})".format(
        agg, val_col, _build_val(val_col, click_point.get(val_key))))
    return "{}: {}".format(text("Drilldown for"), ", ".join(strs))
Example #3
0
def retrieve_chart_data(df, *args, **kwargs):
    """
    Retrieves data from a dataframe for x, y, z & group inputs complete with date frequency
    formatting (:meth:`dtale.charts.utils.date_freq_handler`) if specified

    :param df: dataframe that contains data for chart
    :type df: :class:`pandas:pandas.DataFrame`
    :param args: columns to use
    :type args: iterable of str
    :return: dataframe of data required for chart construction
    :rtype: :class:`pandas:pandas.DataFrame`
    """
    freq_handler = date_freq_handler(df)
    cols = flatten_lists([make_list(a) for a in args])
    all_code = []
    all_data = []
    for col in cols:
        if col is not None:
            s, code = freq_handler(col)
            all_data.append(s)
            if code is not None:
                all_code.append(code)
    all_data = pd.concat(all_data, axis=1)
    all_code = ["chart_data = pd.concat(["] + all_code + ["], axis=1)"]
    if len(make_list(kwargs.get("group_val"))):
        filters = build_group_inputs_filter(all_data, kwargs["group_val"])
        all_data = run_query(all_data, filters)
        all_code.append("chart_data = chart_data.query({})".format(
            triple_quote(filters)))
    return all_data, all_code
Example #4
0
 def on_data(
     _ts1,
     _ts2,
     _ts3,
     _ts4,
     pathname,
     inputs,
     chart_inputs,
     yaxis_data,
     map_data,
     last_chart_inputs,
 ):
     """
     dash callback controlling the building of dash charts
     """
     all_inputs = dict_merge(inputs, chart_inputs,
                             dict(yaxis=yaxis_data or {}), map_data)
     if all_inputs == last_chart_inputs:
         raise PreventUpdate
     if is_app_root_defined(dash_app.server.config.get("APPLICATION_ROOT")):
         all_inputs["app_root"] = dash_app.server.config["APPLICATION_ROOT"]
     charts, range_data, code = build_chart(get_data_id(pathname),
                                            **all_inputs)
     return (
         charts,
         all_inputs,
         range_data,
         "\n".join(make_list(code)),
         get_yaxis_type_tabs(make_list(inputs.get("y") or [])),
     )
Example #5
0
    def input_toggles(_ts, inputs):
        """
        dash callback controlling showing/hiding of chart-specific inputs (for example z-axis) as well as chart
        formatting inputs (sorting for bars in bar chart, bar chart style (stacked) or y-axis ranges.
        """
        [chart_type, x, y, group, agg] = [inputs.get(p) for p in ['chart_type', 'x', 'y', 'group', 'agg']]
        settings = CHART_INPUT_SETTINGS[chart_type]
        x_settings, y_settings, z_settings, group_settings = (settings.get(p) for p in ['x', 'y', 'z', 'group'])

        def show(cfg, input_type='single'):
            return cfg.get('display', True) and cfg.get('type', 'single') == input_type

        y_multi_style = {'display': 'block' if show(y_settings, 'multi') else 'none'}
        y_single_style = {'display': 'block' if show(y_settings) else 'none'}
        z_style = {'display': 'block' if show(z_settings) else 'none'}
        group_style = {'display': 'block' if show(group_settings) else 'none'}
        rolling_style = {'display': 'inherit' if agg == 'rolling' else 'none'}
        show_cpg = show(group_settings) and len(group or []) and chart_type not in ['pie', 'wordcloud']
        cpg_style = {'display': 'block' if show_cpg else 'none'}
        bar_style = {'display': 'block' if chart_type == 'bar' else 'none'}
        barsort_options = make_list(x) if x is not None else []
        barsort_options += make_list(y) if y is not None else []
        barsort_options = [build_option(o) for o in barsort_options]

        yaxis_style, yaxis_options = {'display': 'none'}, []
        if chart_type in YAXIS_CHARTS and len(y or []):
            yaxis_style, yaxis_options = {'display': 'block'}, [build_option(y2) for y2 in y]

        return (
            y_multi_style, y_single_style, z_style, group_style, rolling_style, cpg_style, bar_style,
            bar_style, barsort_options, yaxis_style, yaxis_options
        )
Example #6
0
def retrieve_chart_data(df, x, y, z, group=None):
    """
    Retrieves data from a dataframe for x, y, z & group inputs complete with date frequency
    formatting (:meth:`dtale.charts.utils.date_freq_handler`) if specified

    :param df: dataframe that contains data for chart
    :type df: :class:`pandas:pandas.DataFrame`
    :param x: column to use for the X-Axis
    :type x: str
    :param y: columns to use for the Y-Axes
    :type y: list of str
    :param z: column to use for the Z-Axis
    :type z: str
    :param group: column(s) to use for grouping
    :type group: list of str or str
    :return: dataframe of data required for chart construction
    :rtype: :class:`pandas:pandas.DataFrame`
    """
    freq_handler = date_freq_handler(df)
    cols = [x] + make_list(y) + [z] + make_list(group)
    all_code = []
    all_data = []
    for col in cols:
        if col is not None:
            s, code = freq_handler(col)
            all_data.append(s)
            if code is not None:
                all_code.append(code)
    all_code = ["chart_data = pd.concat(["] + all_code + ["], axis=1)"]
    return pd.concat(all_data, axis=1), all_code
Example #7
0
def build_agg_data(df, x, y, inputs, agg, z=None):
    """
    Builds aggregated data when an aggregation (sum, mean, max, min...) is selected from the front-end.

    :param df: dataframe that contains data for chart
    :type df: :class:`pandas:pandas.DataFrame`
    :param x: column to use for the X-Axis
    :type x: str
    :param y: columns to use for the Y-Axes
    :type y: list of str
    :param inputs: additional chart configurations (chart_type, group, rolling_win, rolling_comp...)
    :type inputs: dict
    :param agg: points to a specific function that can be applied to
                :func: pandas.core.groupby.DataFrameGroupBy.  Possible values are: count, first, last mean,
                median, min, max, std, var, mad, prod, sum
    :type agg: str
    :param z: column to use for the Z-Axis
    :type z: str, optional
    :return: dataframe of aggregated data
    :rtype: :class:`pandas:pandas.DataFrame`
    """
    if agg == 'raw':
        return df, []
    z_exists = len(make_list(z))
    if agg == 'corr':
        if not z_exists:
            raise NotImplementedError(
                'Correlation aggregation is only available for 3-dimensional charts!'
            )
    if agg == 'rolling':
        if z_exists:
            raise NotImplementedError(
                'Rolling computations have not been implemented for 3-dimensional charts!'
            )
        window, comp = map(inputs.get, ['rolling_win', 'rolling_comp'])
        agg_df = df.set_index(x).rolling(window=window)
        agg_df = pd.DataFrame({c: getattr(agg_df[c], comp)() for c in y})
        agg_df = agg_df.reset_index()
        code = [
            "chart_data = chart_data.set_index('{x}').rolling(window={window})"
            .format(x=x, window=window),
            "chart_data = pd.DataFrame({'" + ', '.join([
                "'{c}': chart_data['{c}'].{comp}()".format(c=c, comp=comp)
                for c in y
            ]) + '})', "chart_data = chart_data.reset_index()"
        ]
        return agg_df, code

    if z_exists:
        groups = df.groupby([x] + make_list(y))
        return getattr(groups[make_list(z)], agg)().reset_index(), [
            "chart_data = chart_data.groupby(['{cols}'])[['{z}']].{agg}().reset_index()"
            .format(cols="', '".join([x] + make_list(y)), z=z, agg=agg)
        ]
    groups = df.groupby(x)
    return getattr(groups[y], agg)().reset_index(), [
        "chart_data = chart_data.groupby('{x}')[['{y}']].{agg}().reset_index()"
        .format(x=x, y=make_list(y)[0], agg=agg)
    ]
Example #8
0
def main_inputs_and_group_val_display(inputs):
    chart_type = inputs.get('chart_type')
    show_group = show_input_handler(inputs.get('chart_type', 'line'))('group')
    if chart_type == 'maps' and not len(make_list(inputs.get('map_group'))):
        return dict(display='none'), 'col-md-12'
    elif show_group and not len(make_list(inputs.get('group'))):
        return dict(display='none'), 'col-md-12'
    return dict(display='block'), 'col-md-8'
Example #9
0
 def populate_col_dropdowns(is_open, input_data):
     if not is_open:
         raise PreventUpdate
     y = make_list(input_data.get("y"))
     z = make_list(input_data.get("z"))
     col_options = [
         build_option(sub_col) for sub_col in (y if not len(z) else z)
     ]
     return [col_options for _ in range(10)]
Example #10
0
def build_final_chart_code(code):
    is_charts = (next(
        (c for c in make_list(code)
         if c.startswith("figure = go.Figure(data=charts,")),
        None,
    ) is not None)
    return "\n".join(
        make_list(code) +
        [CHARTS_EXPORT_CODE if is_charts else CHART_EXPORT_CODE])
Example #11
0
def flatten_columns(df, columns=None):
    if columns is not None:
        return [
            ' '.join([
                '{}-{}'.format(c1, str(c2))
                for c1, c2 in zip(make_list(columns), make_list(col_val))
            ]).strip() for col_val in df.columns.values
        ]
    return [
        ' '.join([str(c) for c in make_list(col)]).strip()
        for col in df.columns.values
    ]
Example #12
0
def build_aggs(y, z=None, agg=None, extended_aggregation=[]):
    z_exists = len(make_list(z))
    agg_cols = make_list(y)
    if z_exists:
        agg_cols = make_list(z)

    aggs = {}
    if not len(extended_aggregation or []):
        aggs[agg] = agg_cols
    else:
        for ext_agg in extended_aggregation:
            aggs[ext_agg["agg"]] = aggs.get(ext_agg["agg"], []) + [ext_agg["col"]]
    return aggs
Example #13
0
    def input_data(_ts, chart_type, x, y_multi, y_single, z, group, agg, window, rolling_comp, pathname, query):
        """
        dash callback for maintaining chart input state and column-based dropdown options.  This will guard against
        users selecting the same column for multiple axes.
        """
        y_val = make_list(y_single if chart_type in ZAXIS_CHARTS else y_multi)
        inputs = dict(query=query, chart_type=chart_type, x=x, y=y_val, z=z, group=group, agg=agg, window=window,
                      rolling_comp=rolling_comp)
        data_id = get_data_id(pathname)
        cols = DATA[data_id].columns
        dtypes = get_dtypes(DATA[data_id])

        def build_selections(*args):
            return flatten_lists([[] if a is None else make_list(a) for a in args])

        def build_cols():
            for c in cols:
                if classify_type(dtypes[c]) == 'D':
                    for freq in FREQS:
                        if freq in FREQ_LABELS:
                            yield '{}|{}'.format(c, freq), '{} ({})'.format(c, FREQ_LABELS[freq])
                        else:
                            yield c, c
                else:
                    yield c, c

        col_opts = list(build_cols())
        group_val, z_val = (None, z) if chart_type in ZAXIS_CHARTS else (group, None)
        x_options = [build_option(c, l) for c, l in col_opts if c not in build_selections(y_val, z_val, group_val)]
        y_filter = build_selections(x, group_val, z_val)
        y_multi_options = [build_option(c, l) for c, l in col_opts if c not in y_filter]
        y_single_options = [build_option(c, l) for c, l in col_opts if c not in y_filter]
        z_options = [build_option(c) for c in cols if c not in build_selections(x, y_val, group_val)]
        group_options = [build_option(c, l) for c, l in col_opts if c not in build_selections(x, y_val, z_val)]
        return inputs, x_options, y_single_options, y_multi_options, z_options, group_options
Example #14
0
    def build_filter(self):
        if self.cfg is None:
            return super(NumericFilter, self).handle_missing(None)
        cfg_val, cfg_operand, cfg_min, cfg_max = (
            self.cfg.get(p) for p in ["value", "operand", "min", "max"])

        if cfg_operand in ["=", "ne"]:
            state = make_list(cfg_val or [])
            if not len(state):
                return super(NumericFilter, self).handle_missing(None)
            fltr = dict(value=cfg_val, operand=cfg_operand)
            if len(state) == 1:
                fltr["query"] = "{} {} {}".format(
                    build_col_key(self.column),
                    "==" if cfg_operand == "=" else "!=",
                    state[0],
                )
            else:
                fltr["query"] = "{} {} ({})".format(
                    build_col_key(self.column),
                    "in" if cfg_operand == "=" else "not in",
                    ", ".join(map(str, state)),
                )
            return super(NumericFilter, self).handle_missing(fltr)
        if cfg_operand in ["<", ">", "<=", ">="]:
            if cfg_val is None:
                return super(NumericFilter, self).handle_missing(None)
            fltr = dict(
                value=cfg_val,
                operand=cfg_operand,
                query="{} {} {}".format(build_col_key(self.column),
                                        cfg_operand, cfg_val),
            )
            return super(NumericFilter, self).handle_missing(fltr)
        if cfg_operand in ["[]", "()"]:
            fltr = dict(operand=cfg_operand)
            queries = []
            if cfg_min is not None:
                fltr["min"] = cfg_min
                queries.append("{} >{} {}".format(
                    build_col_key(self.column),
                    "=" if cfg_operand == "[]" else "",
                    cfg_min,
                ))
            if cfg_max is not None:
                fltr["max"] = cfg_max
                queries.append("{} <{} {}".format(
                    build_col_key(self.column),
                    "=" if cfg_operand == "[]" else "",
                    cfg_max,
                ))
            if len(queries) == 2 and cfg_max == cfg_min:
                queries = [
                    "{} == {}".format(build_col_key(self.column), cfg_max)
                ]
            if not len(queries):
                return super(NumericFilter, self).handle_missing(None)
            fltr["query"] = " and ".join(queries)
            return super(NumericFilter, self).handle_missing(fltr)
        return super(NumericFilter, self).handle_missing(None)
Example #15
0
def startup(data=None, data_loader=None, port=None):
    """
    Loads and stores data globally
    - If data has indexes then it will lock save those columns as locked on the front-end
    - If data has column named index it will be dropped so that it won't collide with row numbering (dtale_index)
    - Create location in memory for storing settings which can be manipulated from the front-end (sorts, filter, ...)

    :param data: pandas.DataFrame or pandas.Series
    :param data_loader: function which returns pandas.DataFrame
    :param port: integer port for running Flask process
    """
    global DATA, SETTINGS

    if data_loader is not None:
        data = data_loader()
    elif data is None:
        logger.debug('pytest: {}, flask: {}'.format(running_with_pytest(),
                                                    running_with_flask()))

    if data is not None:
        curr_index = [
            i for i in make_list(data.index.name or data.index.names)
            if i is not None
        ]
        logger.debug('pre-locking index columns ({}) to settings[{}]'.format(
            curr_index, port))
        SETTINGS[str(port)] = dict(locked=curr_index)
        DATA = data.reset_index().drop('index', axis=1, errors='ignore')
Example #16
0
    def notebook_charts(self, x, y, group=None, aggregation=None, width='100%', height=350):
        """
        Helper function to build an `ipython:IPython.display.IFrame` pointing at the charts popup

        :param x: column to be used as x-axis of chart
        :type x: str
        :param y: column to be used as y-axis of chart
        :type y: str
        :param group: comma-separated string of columns to group chart data by
        :type group: str, optional
        :param aggregation: points to a specific function that can be applied to
                            :func: pandas.core.groupby.DataFrameGroupBy.  Possible values are: count, first, last mean,
                            median, min, max, std, var, mad, prod, sum
        :type aggregation: str, optional
        :param width: width of the ipython cell
        :type width: str or int, optional
        :param height: height of the ipython cell
        :type height: str or int, optional
        :return: :class:`ipython:IPython.display.IFrame`
        """
        params = dict(x=x, y=y)
        if group:
            params['group'] = ','.join(make_list(group))
        if aggregation:
            params['aggregation'] = aggregation
        self.notebook('/dtale/popup/charts/', params=params, width=width, height=height)
Example #17
0
    def _build_iframe(self, route='/dtale/iframe/', params=None, width='100%', height=350):
        """
        Helper function to build an :class:`ipython:IPython.display.IFrame` if that module exists within
        your environment

        :param route: the :class:`flask:flask.Flask` route to hit on D-Tale
        :type route: str, optional
        :param params: properties & values passed as query parameters to the route
        :type params: dict, optional
        :param width: width of the ipython cell
        :type width: str or int, optional
        :param height: height of the ipython cell
        :type height: str or int, optional
        :return: :class:`ipython:IPython.display.IFrame`
        """
        try:
            from IPython.display import IFrame
        except ImportError:
            logger.info('in order to use this function, please install IPython')
            return None
        iframe_url = '{}{}{}'.format(self._url, route, self._data_id)
        if params is not None:
            formatted_params = ['{}={}'.format(k, ','.join(make_list(params[k]))) for k in sorted(params)]
            iframe_url = '{}?{}'.format(iframe_url, '&'.join(formatted_params))
        return IFrame(iframe_url, width=width, height=height)
Example #18
0
 def group_values(
     chart_type,
     group_cols,
     map_group_cols,
     cs_group_cols,
     treemap_group_cols,
     pathname,
     inputs,
     prev_group_vals,
 ):
     data_id = get_data_id(pathname)
     group_cols = group_cols
     if chart_type == "maps":
         group_cols = map_group_cols
     elif chart_type == "candlestick":
         group_cols = cs_group_cols
     elif chart_type == "treemap":
         group_cols = treemap_group_cols
     group_cols = make_list(group_cols)
     group_types = get_group_types(inputs, data_id, group_cols)
     if "groups" not in group_types:
         return [], None
     group_vals = run_query(
         global_state.get_data(data_id),
         inputs.get("query"),
         global_state.get_context_variables(data_id),
     )
     group_vals = build_group_val_options(group_vals, group_cols)
     selections = []
     available_vals = [gv["value"] for gv in group_vals]
     if prev_group_vals is not None:
         selections = [pgv for pgv in prev_group_vals if pgv in available_vals]
     if not len(selections) and len(group_vals) <= MAX_GROUPS:
         selections = available_vals
     return group_vals, selections
Example #19
0
 def input_data(_ts, chart_type, x, y_multi, y_single, z, group, group_val,
                agg, window, rolling_comp, pathname, query):
     """
     dash callback for maintaining chart input state and column-based dropdown options.  This will guard against
     users selecting the same column for multiple axes.
     """
     y_val = make_list(y_single if chart_type in ZAXIS_CHARTS else y_multi)
     if group_val is not None:
         group_val = [json.loads(gv) for gv in group_val]
     inputs = dict(query=query,
                   chart_type=chart_type,
                   x=x,
                   y=y_val,
                   z=z,
                   group=group,
                   group_val=group_val,
                   agg=agg,
                   window=window,
                   rolling_comp=rolling_comp)
     data_id = get_data_id(pathname)
     options = build_input_options(global_state.get_data(data_id), **inputs)
     x_options, y_multi_options, y_single_options, z_options, group_options, barsort_options, yaxis_options = options
     show_map = chart_type == 'maps'
     map_style = {} if show_map else {'display': 'none'}
     non_map_style = {'display': 'none'} if show_map else {}
     cscale_style = colorscale_input_style(chart_type=chart_type)
     return (inputs, x_options, y_single_options, y_multi_options,
             z_options, group_options, barsort_options, yaxis_options,
             non_map_style, map_style, cscale_style)
Example #20
0
def build_input(label,
                input,
                className="col-auto",
                label_class="input-group-addon",
                **kwargs):
    """
    Helper function to build a standard label/input component in dash.

    :param label: name of the input you are displaying
    :type label: str
    :param input: dash component for storing state
    :param className: style class to be applied to encapsulating div
    :type className: str
    :param kwargs: Optional keyword arguments to be applied to encapsulating div (style, title, id...)
    :type kwargs: dict
    :return: dash components for label/input
    :rtype: :dash:`dash_html_components.Div <dash-html-components/div>`
    """
    return html.Div([
        html.Div(
            [html.Span(label, className=label_class)] + make_list(input),
            className="input-group mr-3",
        )
    ],
                    className=className,
                    **kwargs)
Example #21
0
 def yaxis_min_max_values(yaxis_type, yaxis, inputs, yaxis_inputs,
                          range_data):
     """
     dash callback controlling values for selected y-axis in y-axis range editor
     """
     y = make_list(inputs.get('y'))
     dd_style = dict(display='block'
                     if yaxis_type == 'multi' and len(y) > 1 else 'none')
     type_style = {
         'borderRadius': '0 0.25rem 0.25rem 0'
     } if yaxis_type == 'default' else None
     min_max_style = 'none' if (yaxis_type == 'default') or (
         yaxis_type == 'multi' and yaxis is None) else 'block'
     label_style = dict(display=min_max_style)
     input_style = {'lineHeight': 'inherit', 'display': min_max_style}
     curr_min, curr_max = (None, None)
     range_min, range_max = ((range_data or {}).get(p) or {}
                             for p in ['min', 'max'])
     if yaxis:
         curr_vals = (yaxis_inputs or {}).get('data', {}).get(yaxis) or {}
         curr_min = curr_vals.get('min') or range_min.get(yaxis)
         curr_max = curr_vals.get('max') or range_max.get(yaxis)
     elif yaxis_type == 'single':
         curr_vals = (yaxis_inputs or {}).get('data', {}).get('all') or {}
         curr_min = curr_vals.get('min')
         if curr_min is None:
             curr_min = get_default_range(range_min, y)
         curr_max = curr_vals.get('max')
         if curr_max is None:
             curr_max = get_default_range(range_max, y, max=True)
     return curr_min, curr_max, dd_style, label_style, input_style, label_style, input_style, type_style
Example #22
0
def get_loader_options(key, properties, options):
    """
    Filters dictionary of click parameters for ones which start with a certain prefix

    :param key: click option prefix
    :type key: str
    :param properties: sub-properties of the click command key
    :type properties: list of str
    :param options: click options
    :type options: dict
    :return: dictionary of click options with start with key
    :rtype: dict
    """
    def _build_key(option):
        segs = option.split("_")
        if len(segs) == 1:
            return ""
        return option.split("{}_".format(key))[-1]

    final_key = "_".join(key.split("-"))
    selected_opts = ([final_key] if not len(make_list(properties)) else [
        "{}_{}".format(final_key,
                       prop["name"] if isinstance(prop, dict) else prop)
        for prop in properties
    ])

    return dict(((_build_key(k), v) for k, v in options.items()
                 if k in selected_opts if v is not None))
Example #23
0
    def update_yaxis_data(yaxis_type, yaxis_min, yaxis_max, yaxis, yaxis_data,
                          range_data, inputs):
        """
        dash callback controlling updates to y-axis range state
        """
        yaxis_data = yaxis_data or dict(data={})
        yaxis_data["type"] = yaxis_type
        yaxis_name = "all" if yaxis_type == "single" else yaxis
        if yaxis_name == "all":
            y = make_list(inputs.get("y"))
            mins = range_data.get("min", {})
            maxs = range_data.get("max", {})
            range_min = get_default_range(mins, y)
            range_max = get_default_range(maxs, y, max=True)
        elif yaxis is None:
            raise PreventUpdate
        else:
            range_min, range_max = (range_data[p].get(yaxis_name)
                                    for p in ["min", "max"])

        if yaxis_name in yaxis_data["data"]:
            if (yaxis_min, yaxis_max) == (range_min, range_max):
                del yaxis_data["data"][yaxis_name]
            else:
                yaxis_data["data"][yaxis_name] = dict(min=yaxis_min,
                                                      max=yaxis_max)
        else:
            if (yaxis_min, yaxis_max) != (range_min, range_max):
                yaxis_data["data"][yaxis_name] = dict(min=yaxis_min,
                                                      max=yaxis_max)
        return yaxis_data
Example #24
0
def build_title(x, y, group=None, z=None, agg=None):
    """
    Helper function to build chart titles based on the inputs for x, y, z, group & aggregation.
        - (x='a', y='b') => 'b by a'
        - (x='a', y=['b','c']) => 'b, c by a'
        - (x='a', y='b', z='c') => 'b by a weighted by c'
        - (x='a', y='b', group='d') => 'd - b by a'
        - (x='a', y='b', agg='corr') => 'b by a (Correlation)'
        - (x='a', y='b', z='c', agg='sum') => 'b by a weighted by c (Sum)'

    :param x: column to use for the X-Axis
    :type x: str
    :param y: columns to use for the Y-Axes
    :type y: list of str
    :param group: column(s) to use for grouping
    :type group: list of str or str, optional
    :param z: column to use for the Z-Axis
    :type z: str, optional
    :param agg: specific aggregation that can be applied to y or z axes.  Possible values are: count, first, last mean,
                median, min, max, std, var, mad, prod, sum.  This is included in label of axis it is being applied to.
    :type agg: str, optional
    :return: chart title
    :rtype: str
    """
    y_title = ', '.join([update_label_for_freq(y2) for y2 in make_list(y)])
    x_title = update_label_for_freq(x)
    title = '{} by {}'.format(y_title, x_title)
    if z:
        title = '{} weighted by {}'.format(title, z)
    if agg:
        agg_title = AGGS[agg]
        title = '{} ({})'.format(title, agg_title)
    if group:
        title = '{} - {}'.format(group, title)
    return {'title': {'text': title}}
Example #25
0
    def update_yaxis_data(yaxis_type, yaxis_min, yaxis_max, yaxis, yaxis_data,
                          range_data, inputs):
        """
        dash callback controlling updates to y-axis range state
        """
        yaxis_data = yaxis_data or dict(data={})
        yaxis_data['type'] = yaxis_type
        yaxis_name = 'all' if yaxis_type == 'single' else yaxis
        if yaxis_name == 'all':
            y = make_list(inputs.get('y'))
            mins = range_data.get('min', {})
            maxs = range_data.get('max', {})
            range_min = get_default_range(mins, y)
            range_max = get_default_range(maxs, y, max=True)
        elif yaxis is None:
            raise PreventUpdate
        else:
            range_min, range_max = (range_data[p].get(yaxis_name)
                                    for p in ['min', 'max'])

        if yaxis_name in yaxis_data['data']:
            if (yaxis_min, yaxis_max) == (range_min, range_max):
                del yaxis_data['data'][yaxis_name]
            else:
                yaxis_data['data'][yaxis_name] = dict(min=yaxis_min,
                                                      max=yaxis_max)
        else:
            if (yaxis_min, yaxis_max) != (range_min, range_max):
                yaxis_data['data'][yaxis_name] = dict(min=yaxis_min,
                                                      max=yaxis_max)
        return yaxis_data
Example #26
0
 def on_data(
     _ts1,
     _ts2,
     _ts3,
     _ts4,
     _ts5,
     _ts6,
     load,
     inputs,
     chart_inputs,
     yaxis_data,
     map_data,
     cs_data,
     treemap_data,
     last_chart_inputs,
     auto_load,
     prev_load_clicks,
 ):
     """
     dash callback controlling the building of dash charts
     """
     all_inputs = dict_merge(
         inputs,
         chart_inputs,
         dict(yaxis=yaxis_data or {}),
         map_data,
         cs_data,
         treemap_data,
     )
     if not auto_load and load == prev_load_clicks:
         raise PreventUpdate
     if all_inputs == last_chart_inputs:
         raise PreventUpdate
     if is_app_root_defined(dash_app.server.config.get("APPLICATION_ROOT")):
         all_inputs["app_root"] = dash_app.server.config["APPLICATION_ROOT"]
     charts, range_data, code = build_chart(**all_inputs)
     return (
         charts,
         all_inputs,
         range_data,
         "\n".join(make_list(code) + [CHART_EXPORT_CODE]),
         get_yaxis_type_tabs(make_list(inputs.get("y") or [])),
         load,
         dict(display="block" if valid_chart(**all_inputs) else "none"),
     )
Example #27
0
 def funnel_callback(selected_value, selected_label, group, stacked, data_id):
     label_value_data, value_options, label_options = label_value_callback("funnel")(
         selected_value, selected_label, group, data_id, funnel_stacked=stacked
     )
     return (
         label_value_data,
         value_options,
         label_options,
         show_style(len(make_list(group)) > 0),
     )
Example #28
0
def retrieve_chart_data(df, *args, **kwargs):
    """
    Retrieves data from a dataframe for x, y, z & group inputs complete with date frequency
    formatting (:meth:`dtale.charts.utils.date_freq_handler`) if specified

    :param df: dataframe that contains data for chart
    :type df: :class:`pandas:pandas.DataFrame`
    :param args: columns to use
    :type args: iterable of str
    :return: dataframe of data required for chart construction
    :rtype: :class:`pandas:pandas.DataFrame`
    """
    freq_handler = date_freq_handler(df)
    cols = flatten_lists([make_list(a) for a in args])
    all_code = []
    all_data = []
    for col in cols:
        if col is not None:
            s, code = freq_handler(col)
            all_data.append(s)
            if code is not None:
                all_code.append(code)
    all_data = pd.concat(all_data, axis=1)
    all_code = ["chart_data = pd.concat(["] + all_code + ["], axis=1)"]
    if len(make_list(kwargs.get('group_val'))):
        dtypes = get_dtypes(all_data)

        def _group_filter(group_val):
            for gc, gv in group_val.items():
                classifier = classify_type(dtypes[gc])
                yield group_filter_handler(gc, gv, classifier)

        def _full_filter():
            for group_val in kwargs['group_val']:
                group_filter = ' and '.join(list(_group_filter(group_val)))
                yield group_filter

        filters = list(_full_filter())
        filters = '({})'.format(') or ('.join(filters))
        all_data = all_data.query(filters)
        all_code.append('chart_data = chart_data.query({})'.format(filters))
    return all_data, all_code
Example #29
0
def build_final_cols(y, z, agg, extended_aggregation):
    if not len(extended_aggregation or []):
        z = make_list(z)
        cols = y if not len(z) else z
        if agg is not None and agg != "raw":
            return ["{}|{}".format(col, agg) for col in cols]
        return cols
    return [
        "{}|{}".format(ext_agg["col"], ext_agg["agg"])
        for ext_agg in extended_aggregation
    ]
Example #30
0
def retrieve_chart_data(df, x, y, z, group=None):
    """
    Retrieves data from a dataframe for x, y, z & group inputs complete with date frequency
    formatting (:meth:`dtale.charts.utils.date_freq_handler`) if specified

    :param df: dataframe that contains data for chart
    :type df: :class:`pandas:pandas.DataFrame`
    :param x: column to use for the X-Axis
    :type x: str
    :param y: columns to use for the Y-Axes
    :type y: list of str
    :param z: column to use for the Z-Axis
    :type z: str
    :param group: column(s) to use for grouping
    :type group: list of str or str
    :return: dataframe of data required for chart constructiuon
    :rtype: :class:`pandas:pandas.DataFrame`
    """
    freq_handler = date_freq_handler(df)
    cols = [x] + make_list(y) + [z] + make_list(group)
    return pd.concat([freq_handler(c) for c in cols if c is not None], axis=1)