简体   繁体   English

如何使用 SVG 标记制作图表,其大小仅在一个方面增加,或为 Vega/Vega-Lite 中的每个数据点显示自定义 SVG 标记?

[英]How to make a chart with SVG marker whose size increases in only one aspect or show a custom SVG marker for each data point in Vega/Vega-Lite?

I want to make a chart that has "spikes" as markers.我想制作一个以“尖峰”为标记的图表。 And to denote the "severity" or the "quantitative" nature of the data, I want to scale the "spikes" longer but NOT wider.为了表示数据的“严重性”或“定量”性质,我想将“尖峰”缩放得更长但不更宽。 Currently, when I use the size encoding it increases the area of the "spike", which is undesirable.目前,当我使用size编码时,它会增加“尖峰”的面积,这是不可取的。 I used "aspect": false too but the results did not change -我也使用了"aspect": false但结果没有改变 -

Vega-Lite Spec Vega-Lite 规格

{
  "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
  "description": "A simple bar chart with embedded data.",
  "data": {
    "values": [
      {"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},
      {"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},
      {"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}
    ]
  },
  "mark": {"type": "point", "shape":"M -1 0 L0 -10 L1 0", "fill": "red", "opacity": 0.5, "stroke": "black", "strokeOpacity": 1 },
  "encoding": {
    "x": {"field": "a", "type": "ordinal"},
    "y": {"field": "b", "type": "quantitative"},
    "size": {"field": "b", "type": "quantitative"}
  }
}

在此处输入图像描述

Then I thought that maybe I can specify shape as an encoding and provide custom SVG that only changes in height, as PATH value to the data itself and pass that in the shape encoding.然后我想也许我可以将shape指定为编码并提供仅高度变化的自定义 SVG,作为数据本身的 PATH 值并将其传递给形状编码。 But of course that didn't work.但这当然没有用。 Vega-Lite assigned its own shapes - Vega-Lite 分配了自己的形状 -

{
  "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
  "description": "A simple bar chart with embedded data.",
  "data": {
    "values": [
      {"a": "A", "b": 28, "c":"M -1 0 L0 -10 L1 0"}, {"a": "B", "b": 55, "c":"M -1 0 L0 -5 L1 0"}, {"a": "C", "b": 43, "c":"M -1 0 L0 -20 L1 0"},
      {"a": "D", "b": 91, "c":"M -1 0 L0 -1 L1 0"}
    ]
  },
  "mark": {"type": "point", "fill": "red", "opacity": 0.5, "stroke": "black", "strokeOpacity": 1 },
  "encoding": {
    "x": {"field": "a", "type": "ordinal"},
    "y": {"field": "b", "type": "quantitative"},
    "shape": {"field": "c", "type": "quantitative"}
  }
}

在此处输入图像描述

I also played around with url encoding in point mark as well as image mark, but they did not yield anything.我还在point标记和image标记中使用了url编码,但它们没有产生任何结果。

I saw Path Mark in Vega, which may be useful but I do not see it in Vega-Lite.我在 Vega 中看到了Path Mark ,这可能很有用,但我在 Vega-Lite 中看不到它。 If it can somehow be used then that is fine too.如果它可以以某种方式使用,那也很好。

Any idea how do I make this happen?知道如何实现这一点吗?

Main idea is to have the width of the marker same, but scale the height.主要思想是使标记的宽度相同,但缩放高度。 I don't mind doing it via encoding channels or arguments/parameters or specifying an SVG PATH for each data point, either way is fine.我不介意通过编码通道或参数/参数或为每个数据点指定 SVG PATH 来实现,无论哪种方式都可以。

EDIT 1编辑 1

After fiddling with vega, I got around to the following -在摆弄 vega 之后,我得到了以下内容 -

{
  "$schema": "https://vega.github.io/schema/vega/v5.json",
  "description": "A simple bar chart with embedded data.",
  "background": "white",
  "padding": 5,
  "height": 700,
  "style": "cell",
  "data": [
    {
      "name": "source_0",
      "values": [
        {"a": "A", "b": 1.5, "c": 0},
        {"a": "B", "b": 0.5, "c": 0},
        {"a": "C", "b": 10, "c": 0},
        {"a": "D", "b": 1, "c": 0}
      ]
    },
    {
      "name": "data_0",
      "source": "source_0",
      "transform": [
        {
          "type": "filter",
          "expr": "isValid(datum[\"b\"]) && isFinite(+datum[\"b\"])"
        }
      ]
    }
  ],
  "signals": [
    {"name": "x_step", "value": 20},
    {
      "name": "width",
      "update": "bandspace(domain('x').length, 1, 0.5) * x_step"
    }
  ],
  "marks": [
    {
      "name": "marks",
      "type": "symbol",
      "style": ["path"],
      "from": {"data": "data_0"},
      "encode": {
        "update": {
          "opacity": {"value": 0.7},
          "fill": {"value": "red"},
          "stroke": {"value": "red"},
          "strokeOpacity": {"value": 1},
          "strokeWidth": {"value": 0.25},
          "shape": {"value": "M -1 0 L0 -10 L1 0 Z"},
          "ariaRoleDescription": {"value": "point"},
          "description": {
            "signal": "\"a\" + \": \" + (isValid(datum[\"a\"]) ? datum[\"a\"] : \"\"+datum[\"a\"]) + \"; \" + \"b\" + \": \" + (format(datum[\"b\"], \"\"))"
          },
          "x": {"scale": "x", "field": "a"},
          "y": {"scale": "y", "field": "c"},
          "scaleY": {"field": "b", "type": "quantitative"}
        }
      }
    }
  ],
  "scales": [
    {
      "name": "x",
      "type": "point",
      "domain": {"data": "data_0", "field": "a", "sort": true},
      "range": {"step": {"signal": "x_step"}},
      "padding": 0.5
    },
    {
      "name": "y",
      "type": "linear",
      "domain": {"data": "data_0", "field": "b"},
      "range": [{"signal": "height"}, 0],
      "nice": true,
      "zero": true
    },
    {
      "name": "size",
      "type": "linear",
      "domain": {"data": "data_0", "field": "b"},
      "range": [0, 361],
      "zero": true
    }
  ],
  "axes": [
    {
      "scale": "y",
      "orient": "left",
      "gridScale": "x",
      "grid": true,
      "tickCount": {"signal": "ceil(height/40)"},
      "domain": false,
      "labels": false,
      "aria": false,
      "maxExtent": 0,
      "minExtent": 0,
      "ticks": false,
      "zindex": 0
    },
    {
      "scale": "x",
      "orient": "bottom",
      "grid": false,
      "title": "a",
      "labelAlign": "right",
      "labelAngle": 270,
      "labelBaseline": "middle",
      "labelOverlap": true,
      "zindex": 0
    },
    {
      "scale": "y",
      "orient": "left",
      "grid": false,
      "title": "b",
      "labelOverlap": true,
      "tickCount": {"signal": "ceil(height/40)"},
      "zindex": 0
    }
  ]
}

Which gives me -这给了我 -
在此处输入图像描述

I tried to convert this to Vega-Lite but it doesn't seem to work -我试图将其转换为 Vega-Lite,但它似乎不起作用 -

{
  "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
  "description": "A simple bar chart with embedded data.",
  "data": {
    "values": [
      {"a": "A", "b": 2}, {"a": "B", "b": 5}, {"a": "C", "b": 4},
      {"a": "D", "b": 9}
    ]
  },
  "mark": {"type": "point", "shape":"M -1 0 L0 -10 L1 0", "fill": "red", "opacity": 0.5, "stroke": "black", "strokeOpacity": 1 },
  "encoding": {
    "x": {"field": "a", "type": "ordinal", "axis": {"labelAngle": 0}},
    "y": {"field": "b", "type": "quantitative"},
    "scaleY": {"field": "b", "type": "quantitative"}
  }
}

Error错误

Property scaleY is not allowed.

Your second approach, of providing the SVG path in the shape encoding, will work if you set the scale to null ( open in editor ):如果您将scale设置为null在编辑器中打开),则第二种方法(在shape编码中提供 SVG 路径)将起作用:

{
  "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
  "description": "A simple bar chart with embedded data.",
  "data": {
    "values": [
      {"a": "A", "b": 28, "c":"M -1 0 L0 -10 L1 0"},
      {"a": "B", "b": 55, "c":"M -1 0 L0 -5 L1 0"},
      {"a": "C", "b": 43, "c":"M -1 0 L0 -20 L1 0"},
      {"a": "D", "b": 91, "c":"M -1 0 L0 -1 L1 0"}
    ]
  },
  "mark": {"type": "point", "fill": "red", "opacity": 0.5, "stroke": "black", "strokeOpacity": 1 },
  "encoding": {
    "x": {"field": "a", "type": "ordinal"},
    "y": {"field": "b", "type": "quantitative"},
    "shape": {"field": "c", "type": "quantitative", "scale": null}
  }
}

在此处输入图像描述

Vega-Lite does not provide the equivalent of Vega's ScaleY encoding, so if you want that approach you will have to work in Vega directly. Vega-Lite 不提供与 Vega 的ScaleY编码等效的功能,因此如果您想要这种方法,则必须直接在 Vega 中工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM