# all files / candela/components/SurvivalPlot/ index.js

63.75% Statements 51/80
80.49% Branches 33/41
50% Functions 9/18
18.75% Lines 6/32
15 statements, 3 functions, 18 branches Ignored

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    1041×
    1×
    1×

    1×

    1×

     import VisComponent from '../../VisComponent';
    import VegaChart from '../../VisComponent/mixin/VegaChart';
    import spec from './spec.json';

    export default class SurvivalPlot extends VegaChart(VisComponent, spec) {
      static get options () {
        return [
          {
            name: 'data',
            type: 'table',
            format: 'objectlist'
          },
          {
            name: 'time',
            type: 'string',
            format: 'text',
            domain: {
              mode: 'field',
              from: 'data',
              fieldTypes: ['number', 'integer']
            }
          },
          {
            name: 'censor',
            type: 'string',
            format: 'text',
            domain: {
              mode: 'field',
              from: 'data',
              fieldTypes: ['integer', 'boolean']
            }
          },
          {
            name: 'group',
            type: 'string',
            format: 'text',
            optional: true,
            domain: {
              mode: 'field',
              from: 'data',
              fieldTypes: ['string', 'date', 'number', 'integer', 'boolean']
            }
          }
        ];
      }

      constructor (el, options) {
        super(el, options);

        // Sort the events by time.
        options.data.sort((x, y) => x[options.time] - y[options.time]);

        // If there is no 'group' parameter, fake one up.
        if (!options.group) {
          options.group = 'group';
          options.data.forEach(d => d.group = 0);
        }

        // Collect the grouping values, and count how many belong to each group.
        let groups = {};
        options.data.forEach(d => {
          const key = d[options.group];
          if (!groups[key]) {
            groups[key] = {
              survivors: 1
            };
          }

          groups[key].survivors++;
        });

        // Append a dummy value to the start of the dataset, one per group.
        const dummies = Object.keys(groups).map(g => {
          let x = {
            time: 0
          };

          x[options.group] = g;

          return x;
        });
        options.data = [...dummies, ...options.data];

        // Compute the number of survivors at each event. A patient is assumed to
        // have not survived, unless the reason for the event is "right censoring"
        // (aka, censor == 1).
        options.data.forEach(d => {
          if (d[options.censor] !== 0) {
            groups[d[options.group]].survivors--;
          }
          d.survivors = groups[d[options.group]].survivors;
        });

        this.chart.then(chart => {
          let data = chart.data('table');
          data.remove(() => true);
          data.insert(options.data);

          chart.update();
        });
      }
    }