Создание нескольких строк с использованием вложенных данных json - PullRequest
1 голос
/ 29 апреля 2020

У меня есть вложенное json, например:

(47) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
0:
day: "2020-03-14"
total:
confirmed: 81
recovered: 9
deaths: 2
active: 70
__proto__: Object
statewise: Array(37)
0:
state: "Andaman and Nicobar Islands"
confirmed: 0
recovered: 0
deaths: 0
active: 0
__proto__: Object
1: {state: "Andhra Pradesh", confirmed: 1, recovered: 0, deaths: 0, active: 1}
.......

enter image description here

Структура выглядит так:

<array consiting daywise data>
    day
    total
     -confirmed
     -recovered
     -deaths
     -active
    statewise
       <array defining states having below items>
           - state
           - confirmed
           - recovered
           - deaths

Дело в том, что я хочу сделать линейный график, показывающий общую (подтвержденную) тенденцию случаев с датами для таких состояний, как это:

enter image description here

код :

  <script src="https://d3js.org/d3.v5.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.7/crossfilter.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dc/3.2.1/dc.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/reductio/1.0.0/reductio.js"></script>

 <script>

  const cases_chart = dc.lineChart("#line-chart");
  var log = console.log; 
  d3.json('https://api.rootnet.in/covid19-in/unofficial/covid19india.org/statewise/history').then(function(json_data) {
  var data = json_data.data.history;
  log("=====>", data);

    cf = crossfilter(data); // Main crossfilter objects
    var cases_bar_d = cf.dimension(function(d) { 
      console.log('---------------------->',new Date(d.day));
      return d.day});

    var cases_bar_g = cases_bar_d.group().reduceSum(function(d){ 
      log("statewise:", d.statewise);

      return d.statewise});
   });
</script>

На самом деле в состоянии 37 предметов, и я знаю, как решить это решение. Я должен создать составную диаграмму. Но создание 37 групп и последующая подача их в составную диаграмму будет длительным процессом. Есть ли другой способ решения этой проблемы? Я могу создавать группы индивидуально, возвращая d.statewise[0].confirmed,.....d.statewise[36].confirmed

Я хочу сделать так, чтобы cases_bar_g было так:

{key: <date>, <state_name1>: <confirmed1>, .....<state_name36>: <confirmed36> }

Тогда будет проще создать диаграмму.

Edit1:

Похоже, я нашел похожий вопрос с тем же вложенным шаблоном. Но с трудом удалось реализовать его в виде линейного графика.

Edit2:

Мне удалось сгладить массив, используя для случаев, подтвержденных состоянием.

    data.forEach(function(d,i){

      log("!!!!", i);

      for (var j=0; j<d.statewise.length;j++)
      {
          log("@@@:",map_state[d.statewise[j].state],d.statewise[j].state , d.statewise[j].confirmed);

         d[map_state[d.statewise[j].state]] = d.statewise[j].confirmed;
     }
   });

Теперь это выглядит так: enter image description here

Хотя теперь я могу получить доступ к элементу напрямую, чтобы построить его. Но я думаю, что это не очень хороший подход. Я должен был сделать это через измерение и концепцию группы.

1 Ответ

1 голос
/ 30 апреля 2020

Сглаживание часто является хорошей идеей при работе с перекрестным фильтром. Он должен работать нормально и, вероятно, не повлияет на производительность.

Но я согласен, что здесь, возможно, нет необходимости.

Вы должны иметь возможность использовать пользовательское сокращение, чтобы читать данные из массива statewise и обновлять несколько полей объекта-значения в каждой ячейке.

Вне моей головы, без возможности тестирования, может быть, что-то вроде

var cases_bar_g = cases_bar_d.group().reduce(
  // add
  (p, v) =>
    (v.statewise.forEach(({state, confirmed}) => p[state] = (p[state] || 0) + confirmed), p),
  // remove
  (p,v) =>
    (v.statewise.forEach(({state, confirmed}) => p[state] -= confirmed), p),
  // init
  () => ({})
);

Теперь, когда я смотрю на это, на самом деле это не намного проще, чем выравнивание, но я согласен, что как-то лучше.

Мы говорим crossfilter:

  • каждый бин должен инициализироваться пустым объектом
  • каждый раз, когда вы добавляете строку в бин, с go до statewise и создайте или добавьте запись для этого state в объекте значения bin, начиная с 0 и увеличивая на confirmed
  • каждый раз при удалении строки, уменьшайте значение state на confirmed

Построение композита с использованием al oop

Если вы продолжите идти по этому пути вместо использования диаграммы серии, все еще довольно легко создать дочерние диаграммы для композита.

Вам просто нужен массив имен состояний, который вы можете извлечь из первой строки:

const states = data[0].statewise.map(d => d.state);

Все дочерние диаграммы будут использовать одинаковое измерение и группу; мы просто будем использовать другой метод доступа для извлечения данных.

Мы сопоставим имена состояний с массивом дочерних диаграмм и составим их:

composite.compose(states.map(
  state => dc.lineChart(composite)
    .dimension(cases_bar_d)
    .group(cases_bar_g)
    .valueAccessor(kv => kv.value[state])
    // need .x() and .xUnits and such here
));
...