1
votes

I'm using vega to create a grouped bar chart and I would want to make some numbers (in my label data field) appear when I hover my mouse over one bar or a subgroup of bars. The json object below seems to work, but it shows all the number of all the bars when I move over a part of the graph.

{
  "scales": [
    {
      "padding": 0.2, 
      "range": "height", 
      "type": "ordinal", 
      "domain": {
        "field": "category", 
        "data": "table"
      }, 
      "name": "cat"
    }, 
    {
      "domain": {
        "field": "value", 
        "data": "table"
      }, 
      "name": "val", 
      "range": "width", 
      "type": "linear", 
      "round": "true", 
      "nice": "true"
    }, 
    {
      "range": "category20", 
      "type": "ordinal", 
      "domain": {
        "field": "position", 
        "data": "table"
      }, 
      "name": "color"
    }
  ], 
  "axes": [
    {
      "tickSize": 0, 
      "scale": "cat", 
      "type": "y", 
      "tickPadding": 8
    }, 
    {
      "scale": "val", 
      "type": "x"
    }
  ], 
  "signals": [
    {
      "name": "tooltip",
      "init": {},
      "streams": [
        {"type": "rect:mouseover", "expr": "datum"},
        {"type": "rect:mouseout", "expr": "{}"}
      ]
    }
  ],
  "predicates": [
    {
      "name": "tooltip", "type": "==", 
      "operands": [{"signal": "tooltip._id"}, {"arg": "id"}]
    }
  ],  
  "height": 800, 
  "width": 600, 
  "marks": [
    {
      "from": {
        "data": "table", 
        "transform": [
          {
            "type": "facet", 
            "groupby": [
              "category"
            ]
          }
        ]
      }, 
      "marks": [
        {
          "type": "rect", 
          "name": "bars", 
          "properties": {
            "enter": {
              "y": {
                "field": "position", 
                "scale": "pos"
              }, 
              "x": {
                "field": "value", 
                "scale": "val"
              }, 
              "x2": {
                "scale": "val", 
                "value": 0
              }, 
              "fill": {
                "field": "position", 
                "scale": "color"
              }, 
              "height": {
                "band": "true", 
                "scale": "pos"
              }
            }
          }
        }, 
        {
          "from": {
            "mark": "bars"
          }, 
          "type": "text", 
          "properties": {
            "enter": {
              "align": {"value": "center"},
              "fill": {"value": "#333"}
            },
            "update": {
              "x": { "field": "x2"},
              "dy": {"field":"height", "mult": 0.5},
              "y": {"field":"y"},
              "text": {"field": "datum.label"},
              "align": {"value":"center"},
              "baseline":{"value":"middle"},
              "fillOpacity": {
                "rule": [
                  {
                    "predicate": {"name": "tooltip", "id": {"value": null}},
                    "value": 0
                  },
                  {"value": 1}
                ]
              }
            }
          }
        }
      ], 
      "type": "group", 
      "properties": {
        "enter": {
          "y": {
            "field": "key", 
            "scale": "cat"
          }, 
          "height": {
            "band": "true", 
            "scale": "cat"
          }
        }
      }, 
      "scales": [
        {
          "range": "height", 
          "type": "ordinal", 
          "name": "pos", 
          "domain": {
            "field": "position"
          }
        }
      ]
    }
  ], 
  "data": [
    {
      "values": [
        {
          "category": "A", 
          "position": 1, 
          "value": 1661.0, 
          "label": 40.0
        }, 
        {
          "category": "A", 
          "position": 2, 
          "value": 2928.0, 
          "label": 35.0
        }, 
        {
          "category": "A", 
          "position": 3, 
          "value": 9010.0, 
          "label": 69.0
        }, 
        {
          "category": "A", 
          "position": 4, 
          "value": 6459.0, 
          "label": 97.0
        }, 
        {
          "category": "B", 
          "position": 1, 
          "value": 1022.0, 
          "label": 39.0
        }, 
        {
          "category": "B", 
          "position": 2, 
          "value": 1185.0, 
          "label": 33.0
        }, 
        {
          "category": "B", 
          "position": 3, 
          "value": 567.0, 
          "label": 60.0
        }, 
        {
          "category": "B", 
          "position": 4, 
          "value": 759.0, 
          "label": 84.0
        }
      ], 
      "name": "table"
    }
  ]
} 

I also tried to use signals in the mark block as shown below, but this doens't give me the desired result (all numbers are shown stacked on top of each other, unreadable).

  {
      "from": {
        "mark": "bars"
      }, 
      "type": "text", 
      "properties": {
        "enter": {
          "align": {"value": "center"},
          "fill": {"value": "#333"}
        },
        "update": {
          "x": { "signal": "tooltip.x2"},
          "dy": {"field":"height", "mult": 0.5},
          "y": {"signal":"tooltip.y"},
          "text": {"field": "datum.label"},
          "align": {"value":"center"},
          "baseline":{"value":"middle"},
          "fillOpacity": {
            "rule": [
              {
                "predicate": {"name": "tooltip", "id": {"value": null}},
                "value": 0
              },
              {"value": 1}
            ]
          }
        }
      }
    }

Can anyone help out how to get the desired result and to understand how the data is passed of a (sub)mark to that signal?

1

1 Answers

2
votes

I solved the issue by specifying three predicates, one that checks if datum.position equals the position given by the tooltip's signal datum. Another predicate for checking the category and a last predicate that checks both these conditions. When you hoover your mouse over a bar in the chart and the position and category datum of that bar are the same as in the tooltip's signal, the text is made opaque, otherwise it remains transparent.

{
  "scales": [
    {
      "padding": 0.2, 
      "range": "height", 
      "type": "ordinal", 
      "domain": {
        "field": "category", 
        "data": "table"
      }, 
      "name": "cat"
    }, 
    {
      "domain": {
        "field": "value", 
        "data": "table"
      }, 
      "name": "val", 
      "range": "width", 
      "type": "linear", 
      "round": "true", 
      "nice": "true"
    }, 
    {
      "range": "category20", 
      "type": "ordinal", 
      "domain": {
        "field": "position", 
        "data": "table"
      }, 
      "name": "color"
    }
  ], 
  "axes": [
    {
      "tickSize": 0, 
      "scale": "cat", 
      "type": "y", 
      "tickPadding": 8
    }, 
    {
      "scale": "val", 
      "type": "x"
    }
  ], 
  "signals": [
    {
      "name": "tooltip",
      "init": {},
      "streams": [
        {"type": "rect:mouseover", "expr": "datum"},
        {"type": "rect:mouseout", "expr": "{}"}
      ]
    }
  ],
  "predicates": [
    {
      "name": "isPosition", "type": "==", 
      "operands": [{"signal": "tooltip.position"}, {"arg": "position"}]
    },
    {
      "name": "isCategory", "type": "==", 
      "operands": [{"signal": "tooltip.category"}, {"arg": "category"}]
    },
    {
      "name": "iftooltip", "type": "and", 
      "operands": [{"predicate": "isPosition"}, {"predicate": "isCategory"}]
    }
  ],  
  "height": 800, 
  "width": 600, 
  "marks": [
    {
      "from": {
        "data": "table", 
        "transform": [
          {
            "type": "facet", 
            "groupby": [
              "category"
            ]
          }
        ]
      }, 
      "marks": [
        {
          "type": "rect", 
          "name": "bars", 
          "properties": {
            "enter": {
              "y": {
                "field": "position", 
                "scale": "pos"
              }, 
              "x": {
                "field": "value", 
                "scale": "val"
              }, 
              "x2": {
                "scale": "val", 
                "value": 0
              }, 
              "fill": {
                "field": "position", 
                "scale": "color"
              }, 
              "height": {
                "band": "true", 
                "scale": "pos"
              }
            }
          }
        }, 
        {
          "from": {
            "mark": "bars"
          }, 
          "type": "text", 
          "properties": {
            "enter": {
              "align": {"value": "center"},
              "fill": {"value": "#333"}
            },
            "update": {
              "x": { "field": "x2","offset":-10},
              "y": {"field":"y"},
              "dy": {"field": "height", "mult": 0.5},
              "text": {"signal": "tooltip.label"},
              "align": {"value":"center"},
              "baseline":{"value":"middle"},
              "fillOpacity": {
                "rule": [
                {
                  "predicate": {"name": "iftooltip", "position": {"field": "datum.position"},"category":{"field":"datum.category"}},
                  "value": 1
                },
                {"value": 0}
            ]}
            }
          }
        }
      ], 
      "type": "group", 
      "properties": {
        "enter": {
          "y": {
            "field": "key", 
            "scale": "cat"
          }, 
          "height": {
            "band": "true", 
            "scale": "cat"
          }
        }
      }, 
      "scales": [
        {
          "range": "height", 
          "type": "ordinal", 
          "name": "pos", 
          "domain": {
            "field": "position"
          }
        }
      ]
    }
  ], 
  "data": [
    {
      "values": [
        {
          "category": "A", 
          "position": 1, 
          "value": 1661.0, 
          "label": 40.0
        }, 
        {
          "category": "A", 
          "position": 2, 
          "value": 2928.0, 
          "label": 35.0
        }, 
        {
          "category": "A", 
          "position": 3, 
          "value": 9010.0, 
          "label": 69.0
        }, 
        {
          "category": "A", 
          "position": 4, 
          "value": 6459.0, 
          "label": 97.0
        }, 
        {
          "category": "B", 
          "position": 1, 
          "value": 1022.0, 
          "label": 39.0
        }, 
        {
          "category": "B", 
          "position": 2, 
          "value": 1185.0, 
          "label": 33.0
        }, 
        {
          "category": "B", 
          "position": 3, 
          "value": 567.0, 
          "label": 60.0
        }, 
        {
          "category": "B", 
          "position": 4, 
          "value": 759.0, 
          "label": 84.0
        }
      ], 
      "name": "table"
    }
  ]
}