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
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
def build_layout(): return flatten_lists([[ dcc.Store(id="saved-chart-config-{}".format(i)), dcc.Store(id="prev-saved-chart-config-{}".format(i)), dcc.Store(id="saved-deletes-{}".format(i), data=0), html.Div( [ html.Div( [ html.H3( "{} {}".format(text("Saved Chart"), i), className="col-auto pr-3", ), html.Div( id="saved-chart-header-{}".format(i), className="col pl-0", ), html.Div( dbc.Button( text("Delete"), id="delete-saved-btn-{}".format(i), color="primary", className="delete-chart", ), className="col-auto", ), ], className="row", ), html.Div(id="saved-chart-{}".format(i)), ], id="saved-chart-div-{}".format(i), className="saved-chart-div pt-5", style=dict(display="none"), ), ] for i in SAVED_CHART_IDS])
def build_selections(*args): """ simple helper function to build a single level list of values based on variable number of inputs which could be equal to None. """ return flatten_lists([[] if a is None else make_list(a) for a in args])
def build_chart(data_id=None, **inputs): """ Factory method that forks off into the different chart building methods (heatmaps are handled separately) - line - bar - scatter - pie - wordcloud - 3D scatter - surface :param data_id: identifier of data to build axis configurations against :type data_id: str :param inputs: Optional keyword arguments containing the following information: - x: column to be used as x-axis of chart - y: column to be used as y-axis of chart - z: column to use for the Z-Axis - agg: points to a specific function that can be applied to :func: pandas.core.groupby.DataFrameGroupBy :return: plotly chart object(s) :rtype: type of (:dash:`dash_core_components.Graph <dash-core-components/graph>`, dict) """ try: if inputs.get('chart_type') == 'heatmap': data = make_timeout_request(threaded_heatmap_builder, kwargs=dict_merge( dict(data_id=data_id), inputs)) data = data.pop() return data, None data = make_timeout_request(threaded_build_figure_data, kwargs=dict_merge(dict(data_id=data_id), inputs)) data = data.pop() if data is None: return None, None if 'error' in data: return build_error(data['error'], data['traceback']), None range_data = dict(min=data['min'], max=data['max']) axis_inputs = inputs.get('yaxis', {}) chart_builder = chart_wrapper(data_id, data, inputs) chart_type, x, y, z, agg = ( inputs.get(p) for p in ['chart_type', 'x', 'y', 'z', 'agg']) z = z if chart_type in ZAXIS_CHARTS else None chart_inputs = { k: v for k, v in inputs.items() if k not in ['chart_type', 'x', 'y', 'z', 'group'] } if chart_type == 'wordcloud': return (chart_builder( dash_components.Wordcloud(id='wc', data=data, y=y, group=inputs.get('group'))), range_data) axes_builder = build_axes(data_id, x, axis_inputs, data['min'], data['max'], z=z, agg=agg) if chart_type == 'scatter': if inputs['cpg']: scatter_charts = flatten_lists([ scatter_builder(data, x, y, axes_builder, chart_builder, group=group, agg=agg) for group in data['data'] ]) else: scatter_charts = scatter_builder(data, x, y, axes_builder, chart_builder, agg=agg) return cpg_chunker(scatter_charts), range_data if chart_type == '3d_scatter': return scatter_builder(data, x, y, axes_builder, chart_builder, z=z, agg=agg), range_data if chart_type == 'surface': return surface_builder(data, x, y, z, axes_builder, chart_builder, agg=agg), range_data if chart_type == 'bar': return bar_builder(data, x, y, axes_builder, chart_builder, **chart_inputs), range_data if chart_type == 'line': return line_builder(data, x, y, axes_builder, chart_builder, **chart_inputs), range_data if chart_type == 'pie': return pie_builder(data, x, y, chart_builder, **chart_inputs), range_data raise NotImplementedError('chart type: {}'.format(chart_type)) except BaseException as e: return build_error(str(e), str(traceback.format_exc())), None
def line_builder(data, x, y, axes_builder, wrapper, cpg=False, **inputs): """ Builder function for :plotly:`plotly.graph_objects.Scatter(mode='lines') <plotly.graph_objects.Scatter>` :param data: raw data to be represented within line chart :type data: dict :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 axes_builder: function for building axis configurations :type axes_builder: func :param wrapper: wrapper function returned by :meth:`dtale.charts.utils.chart_wrapper` :type wrapper: func :param cpg: `True` if charts are split by groups, `False` if all are contained within one chart :type cpg: bool :param inputs: Optional keyword arguments containing information about which aggregation (if any) has been used :type inputs: dict :return: line chart :rtype: :plotly:`plotly.graph_objects.Scatter(mode='lines') <plotly.graph_objects.Scatter>` """ axes = axes_builder(y) name_builder = build_series_name(y, cpg) line_cfg = {'mode': 'lines', 'line': {'shape': 'spline', 'smoothing': 0.3}} if cpg: charts = [ wrapper( dcc.Graph( id='line-{}-graph'.format(series_key), figure={ 'data': [ go.Scatter( **dict_merge(line_cfg, { 'x': series['x'], 'y': series[y2] }, name_builder(y2, series_key), {} if i == 1 else {'yaxis': 'y{}'.format(i)})) for i, y2 in enumerate(y, 1) ], 'layout': build_layout( dict_merge( build_title(x, y, group=series_key, agg=inputs.get('agg')), axes)) })) for series_key, series in data['data'].items() ] return cpg_chunker(charts) data_cfgs = flatten_lists([[ go.Scatter(**dict_merge(line_cfg, { 'x': series['x'], 'y': series[y2] }, name_builder(y2, series_key), {} if i == 1 else {'yaxis': 'y{}'.format(i)})) for i, y2 in enumerate(y, 1) ] for series_key, series in data['data'].items()]) return wrapper( dcc.Graph(id='line-graph', figure={ 'data': data_cfgs, 'layout': build_layout( dict_merge(build_title(x, y, agg=inputs.get('agg')), axes)) }))
def bar_builder(data, x, y, axes_builder, wrapper, cpg=False, barmode='group', barsort=None, **kwargs): """ Builder function for :plotly:`plotly.graph_objects.Surface <plotly.graph_objects.Surface>` :param data: raw data to be represented within surface chart :type data: dict :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 axes_builder: function for building axis configurations :type axes_builder: func :param wrapper: wrapper function returned by :meth:`dtale.charts.utils.chart_wrapper` :type wrapper: func :param group: column(s) to use for grouping :type group: list of str or str :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 :return: surface chart :rtype: :plotly:`plotly.graph_objects.Surface <plotly.graph_objects.Surface>` """ hover_text = dict() multiaxis = barmode is None or barmode == 'group' axes = axes_builder(y) if multiaxis else axes_builder([y[0]]) name_builder = build_series_name(y, cpg) if barsort is not None: for series_key, series in data['data'].items(): barsort_col = 'x' if barsort == x or barsort not in series else barsort if barsort_col != 'x': df = pd.DataFrame(series) df = df.sort_values(barsort_col) data['data'][series_key] = { c: df[c].values for c in df.columns } data['data'][series_key]['x'] = list(range(len(df['x']))) hover_text[series_key] = { 'hovertext': df['x'].values, 'hoverinfo': 'y+text' } axes['xaxis'] = dict_merge(axes.get('xaxis', {}), build_spaced_ticks(df['x'].values)) if cpg: charts = [ wrapper( dcc.Graph(id='bar-{}-graph'.format(series_key), figure={ 'data': [ dict_merge( { 'x': series['x'], 'y': series[y2], 'type': 'bar' }, name_builder(y2, series_key), {} if i == 1 or not multiaxis else {'yaxis': 'y{}'.format(i)}, hover_text.get(series_key) or {}) for i, y2 in enumerate(y, 1) ], 'layout': build_layout( dict_merge( build_title(x, y, series_key, agg=kwargs.get('agg')), axes, dict(barmode=barmode or 'group'))) })) for series_key, series in data['data'].items() ] return cpg_chunker(charts) data_cfgs = flatten_lists([[ dict_merge( { 'x': series['x'], 'y': series[y2], 'type': 'bar' }, name_builder(y2, series_key), {} if i == 1 or not multiaxis else {'yaxis': 'y{}'.format(i)}, hover_text.get(series_key) or {}) for i, y2 in enumerate(y, 1) ] for series_key, series in data['data'].items()]) if barmode == 'group' and len(y or []) > 1: data_cfgs = list(build_grouped_bars_with_multi_yaxis(data_cfgs, y)) return wrapper( dcc.Graph(id='bar-graph', figure={ 'data': data_cfgs, 'layout': build_layout( dict_merge(build_title(x, y, agg=kwargs.get('agg')), axes, dict(barmode=barmode or 'group'))) }))
def build_selections(*args): return flatten_lists([[] if a is None else make_list(a) for a in args])