Построение столбчатой диаграммы в Vega с разными цветами для отрицательных и положительных значений

#bar-chart #data-visualization #vega

#столбчатая диаграмма #данные-визуализация #vega

Вопрос:

Итак, мне нужно создать что-то подобное, используя библиотеку Vega:

Столбчатая диаграмма с разными цветами для положительных / отрицательных значений

Теперь я супер n00b, поэтому, пожалуйста, сжальтесь.

Первое решение: используйте какое-нибудь условное форматирование (например, в Excel): если значение столбца < 0, сделайте его красным. Если значение столбца > 0, сделайте его зеленым. Я мог бы найти некоторый условный синтаксис для Vega-Lite, что дало мне надежду, но как мне перевести синтаксис в обычный Vega, я понятия не имею.

Во-вторых, я подумал об использовании некоторой цветовой схемы для диапазонов, например, тех, у которых есть пороговое значение. Но я совершенно запутался в том, какой тип диапазона масштаба использовать, и заметил, что существует взаимосвязь между типом диапазона масштаба и цветовыми схемами, так что да. Запутался.

Затем мой коллега предложил это: https://vega.github.io/editor/#/examples/vega-lite/layer_bar_annotations

Итак, в примере мы можем видеть, что значение столбца выше порогового значения имеет условное форматирование. Итак, я попытался отфильтровать данные, чтобы получить 2 подмножества: values_lower_than_0 и values_higher_than_0 использовать их в качестве источников для меток. Но, похоже, я не знаю, как фильтровать. Мои данные выглядят следующим образом:

 [
  { "date": "2018-12-10", "difference": 20 }, 
  { "date": "2018-10-21", "difference": -10 }
  ...
]
  

Затем я применяю к ней преобразование:

 ...

{
      'name': 'values_lower_than_0',
      'source': 'temps',
      'transform': [{ 'type': 'filter', 'expr': 'datum.difference.Value < 0' }]
}
  

Но когда я использую values_lower_than_0 в метках, кажется, ничего не происходит.

Итак, у меня есть 2 вопроса:

  • Это лучший подход для построения такой диаграммы? (Tbh, мне это кажется довольно запутанным).
  • Если да, то как я должен получить два набора данных и использовать их для получения правильных цветов?

Ответ №1:

Лучшим подходом был бы тот, при котором преобразования к набору данных не применяются.

Берем пример из здесь

Идея состоит в том, чтобы установить y2 значение как середину Height . y затем на основе того, является ли значение отрицательным или положительным, будет скорректировано значение ниже среднего или выше среднего значения соответственно. Пожалуйста, обратитесь к rect конфигурации type marks ниже.

 {
  "$schema": "https://vega.github.io/schema/vega/v4.json",
  "width": 600,
  "height": 360,
  "autosize": "fit",
  "data": [
    {
      "name": "table",
      "url": "https://uat.gramener.com/vega/chart/data/pos-neg-items.json"
    }
  ],
  "scales": [
    {
      "name": "xscale",
      "type": "band",
      "domain": {
        "data": "table",
        "field": "category"
      },
      "range": "width",
      "padding": 0.2,
      "round": true
    },
    {
      "name": "yscale",
      "domain": {
        "data": "table",
        "field": "amount"
      },
      "nice": true,
      "range": "height"
    }
  ],
  "marks": [
    {
      "name": "bars",
      "type": "rect",
      "from": {
        "data": "table"
      },
      "encode": {
        "enter": {
          "x": {
            "scale": "xscale",
            "field": "category"
          },
          "width": {
            "scale": "xscale",
            "band": 1
          },
          "y": {
            "scale": "yscale",
            "field": "amount"
          },
          "y2": {
            "signal": "scale('yscale', 0)"
          },
          "fill": {
            "signal": "datum['amount'] > 0 ? '#5CB38B' : '#E6685C'"
          },
          "tooltip": {
            "signal": "datum"
          }
        }
      }
    },
    {
      "name": "item_score",
      "type": "text",
      "from": {
        "data": "table"
      },
      "encode": {
        "enter": {
          "x": {
            "scale": "xscale",
            "field": "category"
          },
          "y": {
            "scale": "yscale",
            "field": "amount"
          },
          "dy": {
            "signal": "datum['amount'] > 0 ? -4 : 14"
          },
          "dx": {
            "signal": "bandwidth('xscale')/2"
          },
          "align": {
            "value": "center"
          },
          "fill": {
            "value": "black"
          },
          "text": {
            "field": "amount"
          },
          "fontSize": {
            "value": 12
          }
        }
      }
    },
    {
      "name": "item_name",
      "type": "text",
      "from": {
        "data": "table"
      },
      "encode": {
        "enter": {
          "x": {
            "scale": "xscale",
            "field": "category"
          },
          "dx": {
            "value": 20
          },
          "dy": {
            "signal": "datum['amount'] > 0 ? height/2   14 : height/2 - 6"
          },
          "align": {
            "value": "center"
          },
          "fill": {
            "value": "#000000"
          },
          "text": {
            "field": "category"
          },
          "fontSize": {
            "value": 12
          }
        }
      }
    }
  ]
}  

Комментарии:

1. Мне это нравится, намного приятнее. Это более или менее то, что я искал, условная заливка.

Ответ №2:

Я так устал, что сегодня совершаю глупые ошибки! Если кто-то хочет использовать третий подход, описанный выше, тогда я был прав, я просто передавал неправильное название источника в метку.

Еще одно замечание: вам нужно вычислить только одно подмножество для отрицательных значений (например values_lower_than_0 ).

Как только вы это сделаете, у вас появится вызываемая метка bars для всех столбцов (как по умолчанию, с зеленой заливкой). Источником данных для этой метки будут данные по умолчанию. Поверх этой метки вы нанесете вторую метку, называемую negative_bars (например), источником которой будет values_lower_than_0 , и вы закрасите ее красным цветом.

Мой вопрос относительно наилучшего подхода все еще остается в силе.