diff --git a/TODO.md b/TODO.md index 9f652acf3..6d900d8d9 100644 --- a/TODO.md +++ b/TODO.md @@ -12,12 +12,10 @@ List of TODO items for Panoramix * in/notin filters autocomplete ## First Class Line Charts -* Contribution to total +* Contribution to total (added to line chart already) * Time comparison * Time ratios * Use legend shapes that match line markers (useful?) -* Hover line highlighting -* More colors! the Airbnb palette is currently pretty limited * Line types (dash, dotted) ## New Features diff --git a/panoramix/forms.py b/panoramix/forms.py index f8828caa9..5185ff083 100644 --- a/panoramix/forms.py +++ b/panoramix/forms.py @@ -135,6 +135,9 @@ def form_factory(viz): 'donut': BooleanField( "Donut", default=False, description="Do you want a donut or a pie?"), + 'contribution': BooleanField( + "Contribution", default=False, + description="Compute the contribution to the total"), } field_css_classes = {k: ['form-control'] for k in px_form_fields.keys()} select2 = [ diff --git a/panoramix/templates/panoramix/viz_nvd3.html b/panoramix/templates/panoramix/viz_nvd3.html index d36f36373..741b740b6 100644 --- a/panoramix/templates/panoramix/viz_nvd3.html +++ b/panoramix/templates/panoramix/viz_nvd3.html @@ -53,6 +53,9 @@ .tickFormat(function (d) {return tickMultiFormat(new Date(d)); }); chart.showLegend({{ "{}".format(viz.args.show_legend=='y')|lower }}); chart.yAxis.tickFormat(d3.format('.3s')); + {% if viz.args.contribution=='y' %} + chart.yAxis.tickFormat(d3.format('.3p')); + {% endif %} {% elif viz.chart_type == 'nvd3_bar' %} var chart = nv.models.multiBarChart() @@ -74,7 +77,9 @@ chart.cornerRadius(true); {% elif viz.chart_type == 'column' %} - var chart = nv.models.multiBarChart(); + var chart = nv.models.multiBarChart() + .reduceXTicks(false) + .rotateLabels(45) ; chart.yAxis.tickFormat(d3.format('.3s')); {% elif viz.chart_type == 'compare' %} @@ -104,7 +109,7 @@ {% endif %} - {% if viz.chart_type == "nvd3_line" and viz.args.rich_tooltip == 'y' %} + {% if viz.chart_type in ("line", "stacked") and viz.args.rich_tooltip == 'y' %} chart.useInteractiveGuideline(true); {% endif %} {% if viz.args.y_axis_zero == 'y' %} diff --git a/panoramix/utils.py b/panoramix/utils.py index 48531cd91..73ec16f00 100644 --- a/panoramix/utils.py +++ b/panoramix/utils.py @@ -89,8 +89,10 @@ def color(s): '#FF5A5F' """ colors = [ - "#FF5A5F", "#007A87", "#7B0051", "#00D1C1", "#8CE071", "#FFB400", - "#FFAA91", "#B4A76C", "#9CA299", "#565A5C" + "#FF5A5F", "#007A87", "#7B0051", "#00D1C1", "#8CE071", "#FFB400", + "#FFAA91", "#B4A76C", "#9CA299", "#565A5C", + "#A14D83", "#4FA3AB", "#4EDED2", "#4EDED2", "#FFCA4F", "#FFC4B3", + "#C9BF97", "#C9BF97", "#898C8C", ] h = hashlib.md5(s) i = int(h.hexdigest(), 16) diff --git a/panoramix/viz.py b/panoramix/viz.py index 117c3d9cc..0799e8038 100644 --- a/panoramix/viz.py +++ b/panoramix/viz.py @@ -315,6 +315,7 @@ class BigNumberViz(BaseViz): class NVD3TimeSeriesViz(NVD3Viz): verbose_name = "Time Series - Line Chart" chart_type = "nvd3_line" + sort_series = False form_fields = [ 'viz_type', 'granularity', ('since', 'until'), @@ -323,18 +324,28 @@ class NVD3TimeSeriesViz(NVD3Viz): ('rolling_type', 'rolling_periods'), ('show_brush', 'show_legend'), ('rich_tooltip', 'y_axis_zero'), - ('y_log_scale', None) + ('y_log_scale', 'contribution') ] def get_df(self): args = self.args df = super(NVD3TimeSeriesViz, self).get_df() + df = df.fillna(0) metrics = self.metrics df = df.pivot_table( index="timestamp", columns=self.groupby, values=metrics,) + if self.sort_series: + dfs = df.sum() + dfs.sort(ascending=False) + df = df[dfs.index] + + if self.args.get("contribution") == "y": + dft = df.T + df = (dft / dft.sum()).T + rolling_periods = args.get("rolling_periods") rolling_type = args.get("rolling_type") if rolling_periods and rolling_type: @@ -348,10 +359,10 @@ class NVD3TimeSeriesViz(NVD3Viz): def get_json(self): df = self.get_df() - df = df.fillna(0) series = df.to_dict('series') datas = [] - for name, ys in series.items(): + for name in df.T.index.tolist(): + ys = series[name] if df[name].dtype.kind not in "biufc": continue df['timestamp'] = pd.to_datetime(df.index, utc=False) @@ -401,12 +412,14 @@ class NVD3CompareTimeSeriesViz(NVD3TimeSeriesViz): class NVD3TimeSeriesStackedViz(NVD3TimeSeriesViz): verbose_name = "Time Series - Stacked" chart_type = "stacked" + sort_series = True form_fields = [ 'viz_type', 'granularity', ('since', 'until'), 'metrics', 'groupby', 'limit', ('rolling_type', 'rolling_periods'), + ('rich_tooltip', 'show_legend'), ] @@ -447,7 +460,7 @@ class DistributionBarViz(DistributionPieViz): chart_type = "column" def get_df(self): - df = super(DistributionBarViz, self).get_df() + df = super(DistributionPieViz, self).get_df() df = df.pivot_table( index=self.groupby, values=self.metrics) @@ -482,7 +495,6 @@ class DistributionBarViz(DistributionPieViz): viz_types = OrderedDict([ ['table', TableViz], ['line', NVD3TimeSeriesViz], - ['big_number', BigNumberViz], ['compare', NVD3CompareTimeSeriesViz], ['area', NVD3TimeSeriesStackedViz], ['bar', NVD3TimeSeriesBarViz], @@ -491,4 +503,5 @@ viz_types = OrderedDict([ ['bubble', BubbleViz], ['markup', MarkupViz], ['word_cloud', WordCloudViz], + ['big_number', BigNumberViz], ])