创建一个 vega-lite 图表,显示自去年/月以来的变化

问题描述 投票:0回答:1

只是想分享一种显示收入、费用、利润值并显示与上一年相比的差异的方法。费用颜色应该颠倒过来,因为越少越好。回答如下。

visualization vega-lite
1个回答
0
投票

我们开始吧:

enter image description here

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "description": "Using window transform to impute missing values in a line chart by averaging the previous and next values.",
  "title": [
    "Revenue, Expenses, Profit: 2024",
    "Variance based on previous year/month",
    ""
  ],
  "data": {
    "values": [
      {"period": "2024-01", "type": "Revenue", "CY": 1000, "PY": 900},
      {"period": "2024-02", "type": "Revenue", "CY": 1100, "PY": 800},
      {"period": "2024-03", "type": "Revenue", "CY": 1300, "PY": 1350},
      {"period": "2024-04", "type": "Revenue", "CY": 900, "PY": 1110},
      {"period": "2024-05", "type": "Revenue", "CY": 950, "PY": 750},
      {"period": "2024-06", "type": "Revenue", "CY": 1030, "PY": 1000},
      {"period": "2024-07", "type": "Revenue", "CY": 1080, "PY": 950},
      {"period": "2024-08", "type": "Revenue", "CY": 900, "PY": 910},
      {"period": "2024-09", "type": "Revenue", "CY": 960, "PY": 800},
      {"period": "2024-10", "type": "Revenue", "CY": 1200, "PY": 1000},
      {"period": "2024-11", "type": "Revenue", "CY": 1280, "PY": 1350},
      {"period": "2024-12", "type": "Revenue", "CY": 1400, "PY": 1350},
      {"period": "2024-01", "type": "Expenses", "CY": 600, "PY": 500},
      {"period": "2024-02", "type": "Expenses", "CY": 550, "PY": 500},
      {"period": "2024-03", "type": "Expenses", "CY": 600, "PY": 500},
      {"period": "2024-04", "type": "Expenses", "CY": 500, "PY": 500},
      {"period": "2024-05", "type": "Expenses", "CY": 450, "PY": 550},
      {"period": "2024-06", "type": "Expenses", "CY": 630, "PY": 750},
      {"period": "2024-07", "type": "Expenses", "CY": 380, "PY": 650},
      {"period": "2024-08", "type": "Expenses", "CY": 200, "PY": 350},
      {"period": "2024-09", "type": "Expenses", "CY": 660, "PY": 450},
      {"period": "2024-10", "type": "Expenses", "CY": 700, "PY": 500},
      {"period": "2024-11", "type": "Expenses", "CY": 480, "PY": 700},
      {"period": "2024-12", "type": "Expenses", "CY": 300, "PY": 400},
      {"period": "2024-01", "type": "Profit", "CY": 100, "PY": 200},
      {"period": "2024-02", "type": "Profit", "CY": 200, "PY": 150},
      {"period": "2024-03", "type": "Profit", "CY": 300, "PY": 350},
      {"period": "2024-04", "type": "Profit", "CY": 100, "PY": 50},
      {"period": "2024-05", "type": "Profit", "CY": 250, "PY": 300},
      {"period": "2024-06", "type": "Profit", "CY": 330, "PY": 500},
      {"period": "2024-07", "type": "Profit", "CY": 180, "PY": 100},
      {"period": "2024-08", "type": "Profit", "CY": 200, "PY": 300},
      {"period": "2024-09", "type": "Profit", "CY": 360, "PY": 450},
      {"period": "2024-10", "type": "Profit", "CY": 100, "PY": 200},
      {"period": "2024-11", "type": "Profit", "CY": 280, "PY": 100},
      {"period": "2024-12", "type": "Profit", "CY": 300, "PY": 300}
    ]
  },
  "usermeta": {"embedOptions": {"renderer": "svg"}},
  "transform": [
    {
      "calculate": "datum.CY - datum.PY < 0 && (datum.type === 'Revenue' || datum.type === 'Profit') ? 'neg' : datum.CY - datum.PY > 0 && (datum.type === 'Expenses') ? 'neg' :'pos'",
      "as": "diff"
    },
    {
      "calculate": "(datum.type === 'Expenses' ?  (datum.CY == datum.PY ? '🠊' : datum.CY - datum.PY > 0 ? '🠉' : '🠋') : (datum.CY == datum.PY ? '🠊' : datum.CY - datum.PY < 0 ? '🠋' : '🠉'))+ format((datum.CY - datum.PY < 0 ? (datum.CY - datum.PY)*-1 : (datum.CY - datum.PY)), '.0f')",
      "as": "icon"
    },
    {
      "calculate": "datum.CY > datum.PY ? datum.PY : datum.CY",
      "as": "smallVal"
    },
    {"calculate": "datum.CY <= datum.PY ? datum.PY : datum.CY", "as": "bigVal"},
    {
      "joinaggregate": [{"op": "min", "field": "smallVal", "as": "minValTemp"}],
      "groupby": ["type"]
    },
    {"calculate": "round(datum.minValTemp * 0.8,0)", "as": "minVal"},
    {
      "joinaggregate": [{"op": "max", "field": "bigVal", "as": "maxValTemp"}],
      "groupby": ["type"]
    },
    {"calculate": "round(datum.maxValTemp * 1.2,0)", "as": "maxVal"}
  ],
  "vconcat": [
    {
      "width": 500,
      "height": 200,
      "transform": [{"filter": "datum.type == 'Revenue'"}],
      "encoding": {
        "x": {
          "timeUnit": "yearmonth",
          "field": "period",
          "type": "ordinal",
          "axis": {"format": "%b", "title": null}
        },
        "y": {
          "axis": {"grid": false, "title": "Revenue"},
          "scale": {
            "domain": [
              {"expr": "data('data_0')[0].minVal"},
              {"expr": "data('data_0')[0].maxVal"}
            ]
          }
        }
      },
      "layer": [
        {
          "transform": [
            {
              "window": [{"op": "lag", "field": "CY", "as": "CY2"}],
              "frame": [-1, 0]
            }
          ],
          "mark": {
            "type": "rule",
            "color": "black",
            "xOffset": -21,
            "strokeWidth": 1,
            "strokeCap": "square",
            "strokeDash": [4, 3]
          },
          "encoding": {
            "opacity": {"value": 1},
            "y": {"field": "CY", "type": "quantitative"},
            "y2": {"field": "CY2"}
          }
        },
        {
          "mark": {"type": "bar", "point": true, "color": "black", "width": 30},
          "encoding": {
            "y": {"field": "PY", "type": "quantitative"},
            "y2": {"field": "CY"},
            "color": {
              "condition": {"test": "datum.diff === 'neg'", "value": "red"},
              "value": "green"
            },
            "opacity": {"value": 0.5}
          }
        },
        {
          "mark": {
            "type": "tick",
            "point": true,
            "color": "black",
            "thickness": 1,
            "width": 42
          },
          "encoding": {
            "opacity": {"value": 1},
            "y": {"field": "CY", "type": "quantitative"}
          }
        },
        {
          "mark": {
            "type": "tick",
            "point": true,
            "color": "black",
            "thickness": 1,
            "width": 30
          },
          "encoding": {"y": {"field": "PY", "type": "quantitative"}}
        },
        {
          "mark": {"type": "text", "point": true, "color": "black"},
          "encoding": {
            "y": {"field": "maxVal", "type": "quantitative"},
            "text": {"field": "CY", "type": "quantitative"}
          }
        },
        {
          "mark": {
            "type": "text",
            "point": true,
            "yOffset": 12,
            "fontSize": 10
          },
          "encoding": {
            "y": {"field": "maxVal", "type": "quantitative"},
            "text": {"field": "icon"},
            "color": {
              "condition": {"test": "datum.diff === 'neg'", "value": "red"},
              "value": "green"
            }
          }
        }
      ]
    },
    {
      "width": 500,
      "height": 200,
      "transform": [{"filter": "datum.type == 'Expenses'"}],
      "encoding": {
        "x": {
          "timeUnit": "yearmonth",
          "field": "period",
          "type": "ordinal",
          "axis": {"format": "%b", "title": null}
        },
        "y": {
          "axis": {"grid": false, "title": "Expenses"},
          "scale": {
            "domain": [
              {"expr": "data('data_0')[13].minVal"},
              {"expr": "data('data_0')[13].maxVal"}
            ]
          }
        }
      },
      "layer": [
        {
          "transform": [
            {
              "window": [{"op": "lag", "field": "CY", "as": "CY2"}],
              "frame": [-1, 0]
            }
          ],
          "mark": {
            "type": "rule",
            "color": "black",
            "xOffset": -21,
            "strokeWidth": 1,
            "strokeCap": "square",
            "strokeDash": [4, 3]
          },
          "encoding": {
            "opacity": {"value": 1},
            "y": {"field": "CY", "type": "quantitative"},
            "y2": {"field": "CY2"}
          }
        },
        {
          "mark": {"type": "bar", "point": true, "color": "black", "width": 30},
          "encoding": {
            "y": {"field": "PY", "type": "quantitative"},
            "y2": {"field": "CY"},
            "color": {
              "condition": {"test": "datum.diff === 'neg'", "value": "red"},
              "value": "green"
            },
            "opacity": {"value": 0.5}
          }
        },
        {
          "mark": {
            "type": "tick",
            "point": true,
            "color": "black",
            "thickness": 1,
            "width": 42
          },
          "encoding": {
            "opacity": {"value": 1},
            "y": {"field": "CY", "type": "quantitative"}
          }
        },
        {
          "mark": {
            "type": "tick",
            "point": true,
            "color": "black",
            "thickness": 1,
            "width": 30
          },
          "encoding": {"y": {"field": "PY", "type": "quantitative"}}
        },
        {
          "mark": {"type": "text", "point": true, "color": "black"},
          "encoding": {
            "y": {"field": "maxVal", "type": "quantitative"},
            "text": {"field": "CY", "type": "quantitative"}
          }
        },
        {
          "mark": {
            "type": "text",
            "point": true,
            "yOffset": 12,
            "fontSize": 10
          },
          "encoding": {
            "y": {"field": "maxVal", "type": "quantitative"},
            "text": {"field": "icon"},
            "color": {
              "condition": {"test": "datum.diff === 'neg'", "value": "red"},
              "value": "green"
            }
          }
        }
      ]
    },
    {
      "width": 500,
      "height": 200,
      "transform": [{"filter": "datum.type == 'Profit'"}],
      "encoding": {
        "x": {
          "timeUnit": "yearmonth",
          "field": "period",
          "type": "ordinal",
          "axis": {"format": "%b", "title": null}
        },
        "y": {
          "axis": {"grid": false, "title": "Profit"},
          "scale": {
            "domain": [
              {"expr": "data('data_0')[25].minVal"},
              {"expr": "data('data_0')[25].maxVal"}
            ]
          }
        }
      },
      "layer": [
        {
          "transform": [
            {
              "window": [{"op": "lag", "field": "CY", "as": "CY2"}],
              "frame": [-1, 0]
            }
          ],
          "mark": {
            "type": "rule",
            "color": "black",
            "xOffset": -21,
            "strokeWidth": 1,
            "strokeCap": "square",
            "strokeDash": [4, 3]
          },
          "encoding": {
            "opacity": {"value": 1},
            "y": {"field": "CY", "type": "quantitative"},
            "y2": {"field": "CY2"}
          }
        },
        {
          "mark": {"type": "bar", "point": true, "color": "black", "width": 30},
          "encoding": {
            "y": {"field": "PY", "type": "quantitative"},
            "y2": {"field": "CY"},
            "color": {
              "condition": {"test": "datum.diff === 'neg'", "value": "red"},
              "value": "green"
            },
            "opacity": {"value": 0.5}
          }
        },
        {
          "mark": {
            "type": "tick",
            "point": true,
            "color": "black",
            "thickness": 1,
            "width": 42
          },
          "encoding": {
            "opacity": {"value": 1},
            "y": {"field": "CY", "type": "quantitative"}
          }
        },
        {
          "mark": {
            "type": "tick",
            "point": true,
            "color": "black",
            "thickness": 1,
            "width": 30
          },
          "encoding": {"y": {"field": "PY", "type": "quantitative"}}
        },
        {
          "mark": {"type": "text", "point": true, "color": "black"},
          "encoding": {
            "y": {"field": "maxVal", "type": "quantitative"},
            "text": {"field": "CY", "type": "quantitative"}
          }
        },
        {
          "mark": {
            "type": "text",
            "point": true,
            "yOffset": 12,
            "fontSize": 10
          },
          "encoding": {
            "y": {"field": "maxVal", "type": "quantitative"},
            "text": {"field": "icon"},
            "color": {
              "condition": {"test": "datum.diff === 'neg'", "value": "red"},
              "value": "green"
            }
          }
        }
      ]
    }
  ],
  "config": {"view": {"stroke": "transparent"}}
}
© www.soinside.com 2019 - 2024. All rights reserved.