Log scaling in bar chart for better presentation

421 views
Skip to first unread message

jay0...@gmail.com

unread,
Jan 10, 2018, 9:58:33 AM1/10/18
to vega-js

Hi,

I'm designing a horizontal bar chart using rect marks. 
My data range is pretty large. (Eg: MIn val: 5 to Max val: 900000) due to which the smaller bars nearly look like 0 when using linear scale.
Using sqrt scale, I could overcome this to a range of extents. This shrinks the range on higher end.

My queries:


1. I'm using tickCount property on the x-axis & also set the labelOverlap property to true.
  But in some cases when numbers are huge, I get to see only the last tick's value(below screen shot).
  Is there a way to transform these labels to display in an alternate form such as 1k, 3M, 5B etc within vega.

 2. Is there a better scale setting to display these large ranges on bar. Because even in sqrt scale when range is too long, smaller bars disappear.


Screenshot of my issue:



Roy I

unread,
Jan 10, 2018, 1:38:46 PM1/10/18
to vega-js
Message has been deleted

jay0...@gmail.com

unread,
Jan 11, 2018, 9:00:44 AM1/11/18
to vega-js
Thanks. I figured out the solution for label issue (using format as s in axes).

On the log scaling issue, I'm still not able to solve my case. 

I'm trying the below approach:
I transform all my values to Math.log10(value) before feeding to vega & post this the bars are looking good but the axes labels are getting calculated against these values.


I looked into the below:
https://groups.google.com/forum/#!topic/vega-js/abpBrwNgugU.

They have added a new scale by providing a static set of domain & range & defining custom labels.

I'm more of trying to transform the x-axis labels as: 10 raised to datum(10datum.value) by using the same scale as that of rect mark so that the log10 transform to data is negated & labels will have original data values. 

Could you help/correct me if my approach is wrong.

Updated gist:

Roy I

unread,
Jan 11, 2018, 3:56:34 PM1/11/18
to vega-js
Here is a modified version of your example spec using Vega scale type "log" (base 10). The field "logVal" is not needed and omitted for clarity.

Note: For log scale, data values must not be 0 or negative.


Vega spec (v 3.0.8)
------------------------
{
  "width": 400,
  "height": 300,
  "padding": {
    "left": 20,
    "top": 5,
    "right": 20,
    "bottom": 5
  },
  "autosize": {
    "type": "pad",
    "resize": true
  },
  "data": [
    {
      "name": "table",
      "format": {
        "type": "json",
        "parse": "auto"
      },
      "transform": [
        {
          "type": "collect",
          "sort": {
            "field": {
              "signal": "valueField"
            },
            "order": "descending"
          }
        }
      ],
      "values": [
        {
          "cc": "United States",
          "pt": "A",
          "total1": 11,
          "groupId1": 1,
          "value": 600
        },
        {
          "cc": "Greenland",
          "pt": "A",
          "total1": 4,
          "groupId1": 4,
  "value": 900
        },
        {
          "cc": "Mexico",
          "pt": "G",
          "total1": 2,
          "groupId1": 5,
          "value": 273
        },
        {
          "cc": "Canada",
          "pt": "A",
          "total1": 2,
          "groupId1": 6,
          "value": 30
        },
        {
          "cc": "Chile",
          "pt": "A",
          "total1": 1,
          "groupId1": 7,
          "value": 105
        },
        {
          "cc": "Brazil",
          "pt": "A",
          "total1": 1,
          "groupId1": 7,
          "value": 540
        }
      ]
    }
  ],
  "signals": [
    {
      "name": "valueField",
"value": "value"
    },
    {
      "name": "labelField",
      "value": "cc"
    },
{
      "name": "minValue",
  "value": 10.0
    },
    {
      "name": "maxValue",
  "value": 2000.0
    }

  ],
  "scales": [
    {
      "name": "xscale",
  "type": "log",
  "domain": [{"signal": "minValue"}, {"signal": "maxValue"}],
      "range": "width"
    },
    {
      "name": "yscale",
      "type": "band",
      "domain": {
        "data": "table",
        "field": {
          "signal": "labelField"
        }
      },
      "range": "height",
      "padding": 0.2
    }
  ],
  "axes": [
    {
      "orient": "bottom",
      "scale": "xscale",
      "grid": true,
      "encode": {
        "grid": {
          "update": {
            "stroke": {
              "value": "lightgray"
            },
            "strokeDash": {
              "value": [10, 10]
            }
          }
        },
"labels": {
"update": {
  "fill": {"value": "steelblue"},
  "angle": {"value": -45},
  "fontSize": {"value": 12},
  "align": {"value": "right"},
  "baseline": {"value": "top"},
  "dx": {"value": 2}
}
}
  },
  "tickCount": 10,
      "zindex": 1
    },
    {
      "orient": "left",
      "scale": "yscale",
      "ticks": false,
      "labelPadding": 10,
      "zindex": 1.5
    }
  ],
  "marks": [
    {
      "type": "rect",
      "from": {
        "data": "table"
      },
      "encode": {
        "enter": {
          "y": {
            "scale": "yscale",
            "field": {
              "signal": "labelField"
            }
          },
          "height": {
            "scale": "yscale",
            "band": 1
          },
          "x": {
            "scale": "xscale",
            "field": {
              "signal": "valueField"
            }
          },
          "x2": {
            "scale": "xscale",
"signal": "minValue"
          }
        }
      }
    }
  ]
}





On Wednesday, January 10, 2018 at 9:58:33 AM UTC-5, jay0...@gmail.com wrote:
Message has been deleted

jay0...@gmail.com

unread,
Jan 12, 2018, 6:22:07 AM1/12/18
to vega-js
Thanks. Now I understand my lack of basic knowledge was the issue :(.

I have one issue bugging me due to using log scale - the no of grids(dotted lines) has increased to fit to the scale. 
I want a fixed no. of these(5) dotted lines. I tried looking into manipulating  grid using a custom gridStyle but no luck.
Tried referring docs for further info. But link seems to be broken for rule mark:

What are the ways for achieving the same.


Meanwhile, I was able to get to a point with my approach of passing log transformed values & reversing the same on labels using format on label. Now I know this is not the efficient approach, I can't use it anymore:

{
 "width": 120,
- show quoted text -
 "logVal": 2.7781512503836434

 },
 {
 "cc": "Greenland",
 "pt": "A",
 "total1": 4,
 "groupId1": 4,
 "value": 900,
 "logVal": 2.9542425094393248

 },
 {
 "cc": "Mexico",
 "pt": "G",
 "total1": 2,
 "groupId1": 5,
 "value": 273,
 "logVal": 2.436162647040756

 },
 {
 "cc": "Canada",
 "pt": "A",
 "total1": 2,
 "groupId1": 6,
 "value": 30,
 "logVal": 1.4771212547196624

 },
 {
 "cc": "Chile",
 "pt": "A",
 "total1": 1,
 "groupId1": 7,
 "value": 105,
 "logVal": 2.0211892990699383

 },
 {
 "cc": "Brazil",
 "pt": "A",
 "total1": 1,
 "groupId1": 7,
 "value": 540,
 "logVal": 2.7323937598229686

 }
 ]
 }
 ],
 "signals": [
 {
 "name": "valueField",
 "value": "logVal"

 },
 {
 "name": "labelField",
 "value": "cc"
 },
 {
 "name": "maxValue"

 }
 ],
 "scales": [
 {
 "name": "xscale",
 "type": "sqrt",

 "domain": {
 "data": "table",
 "field": {
 "signal": "valueField"
- show quoted text -
    "labels": {
 "interactive": true,
 "update":{
 "text": {"signal": "round(pow(10,datum.value))"},
 "fill": {"value": "steelblue"},
 "fontSize": {"value": 10}
 }

 
 }
 },
 "ticks": false,
 "labelOverlap": true,
 "tickCount": 5,
- show quoted text -
 "value": 0
 }
 }
 }
 }
 ]

Roy I

unread,
Jan 12, 2018, 3:27:51 PM1/12/18
to vega-js
Vega documentation for marks "rule":

Here is the above example spec modified to draw custom vertical grid lines using "rule".


Vega spec (v3.0.8)
{ "name": "data_grid_x",
"values": [50, 100, 500, 1000]
  "grid": false,
  "encode": {
    },
{
      "type": "rule",
      "from": {
        "data": "data_grid_x"
     },
      "encode": {
        "enter": {
"y": {"value": 0},
"y2": {"signal": "height"},
"x": {
"scale": "xscale",
"field": "data"
            },
"stroke": {"value": "#ccc"},
"strokeWidth": {"value": 0.5}
          }

        }
      }

  ]
}  




On Wednesday, January 10, 2018 at 9:58:33 AM UTC-5, jay0...@gmail.com wrote:

Kanit Wongsuphasawat

unread,
Jan 18, 2018, 12:10:02 PM1/18/18
to Roy I, vega-js
I think it's worth saying that it's actually better to use symbol marks with log scale instead of bars. 

See https://www.graphpad.com/guides/prism/7/user-guide/bar_graphs_with_a_log_y_axis.htm?toc=0&printWindow for an explanation. 

--
You received this message because you are subscribed to the Google Groups "vega-js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vega-js+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Roy I

unread,
Jan 23, 2018, 10:21:27 AM1/23/18
to vega-js
Traditional bar chart with log scale can lead to misinterpretation of the data.

With just minor changes, the "bars" can appear as lines or boxes  (similar to boxplot or using symbols).





On Wednesday, January 10, 2018 at 9:58:33 AM UTC-5, jay0...@gmail.com wrote:
Reply all
Reply to author
Forward
0 new messages