xyz83242
xyz83242

Reputation: 814

Is there an function in react-vis to scale each line series into it's % range having the domain min set to 0 and max to 100

I am having 9 different line series being drawn on the react-vis graph. Values of those line series vary. The smallest range is between 0-4, the largest one is between 0 - 12000 (image 1). When I draw all those line series most of them sit down at the bottom of the graph not being readable enough.

react-vis graph showing the current range 0 - 2000

I have tried using the yDomain={[0, 100]}. However, what I see happening now is that the graph max value ends up being 100 and all the other line series with higher values than 100 are not visible (they are being drawn above what we can see).

react-vis graph showing the range set by yDomain to 0-100 and missing other line series as a result

Here is an example of the code if this helps:

            <FlexibleWidthXYPlot
              onMouseLeave={() => this.setState({crosshairValues: []})}
              height={250}
              color="blue"
              size="12"
              xType="time"
              yDomain={[0, 100]}
              >
              <VerticalGridLines />
              <HorizontalGridLines />
              <XAxis 
                tickFormat={function tickFormat(d){
                  const date = new Date(d)
                  return date.toISOString().substr(11, 8)
                }}
                tickLabelAngle={45}
                margin={{bottom: 100}}
                padding={{left: 100}}
              />
              <YAxis />
              <LineSeries
                onNearestX={(value, {index}) =>
                  this.setState({crosshairValues: gasDataFiltered.map(d => d[index])}
                )}
                data={gasDataFiltered[0]}
                color="#27AE60" 
                opacity={battVoltShow === true ? 1 : 0.15}
              />
              <LineSeries
                data={gasDataFiltered[1]}
                color="#2A80B9" 
                opacity={fuelInjShow === true ? 1 : 0.15}
              />
              <LineSeries
                data={gasDataFiltered[2]}
                color="#8E44AD" 
                opacity={gasInjShow === true ? 1 : 0.15}
              />
              <LineSeries
                data={gasDataFiltered[3]}
                color="#560E0D" 
                opacity={gasLvlShow === true ? 1 : 0.15}
              />
              <LineSeries
                data={gasDataFiltered[4]}
                color="#F39C13" 
                opacity={gasPressShow === true ? 1 : 0.15}
              />
              <LineSeries
                data={gasDataFiltered[5]}
                color="#E91F62" 
                opacity={gasTempShow === true ? 1 : 0.15}
              />
              <LineSeries
                data={gasDataFiltered[6]}
                color="#20E3D1" 
                opacity={mapShow === true ? 1 : 0.15}
              />
              <LineSeries
                data={gasDataFiltered[7]}
                color="#246A80"
                opacity={reducerTempShow === true ? 1 : 0.15} 
              />
              <LineSeries
                data={gasDataFiltered[8]}
                color="#FF81C3" 
                opacity={rpmShow === true ? 1 : 0.15}
              />
              <Crosshair values={crosshairValues}>
                <div className='oscilloscope-tooltip'>
                  <ul>
                    <li><span className='oscilloscope-color oscilloscope-color--green'></span>{t('oscilloscope.battVolt')}: {crosshairValues[0] !== undefined && crosshairValues[0].y}</li>
                    <li><span className='oscilloscope-color oscilloscope-color--blue'></span>{t('oscilloscope.fuelInj')}: {crosshairValues[1] !== undefined && crosshairValues[1].y}</li>
                    <li><span className='oscilloscope-color oscilloscope-color--purple'></span>{t('oscilloscope.gasInj')}: {crosshairValues[2] !== undefined && crosshairValues[2].y}</li>
                    <li><span className='oscilloscope-color oscilloscope-color--dark'></span>{t('oscilloscope.gasLvl')}: {crosshairValues[3] !== undefined && crosshairValues[3].y}</li>
                    <li><span className='oscilloscope-color oscilloscope-color--orange'></span>{t('oscilloscope.gasPress')}: {crosshairValues[4] !== undefined && crosshairValues[4].y}</li>
                    <li><span className='oscilloscope-color oscilloscope-color--red'></span>{t('oscilloscope.gasTemp')}: {crosshairValues[5] !== undefined && crosshairValues[5].y}</li>
                    <li><span className='oscilloscope-color oscilloscope-color--light'></span>{t('oscilloscope.map')}: {crosshairValues[6] !== undefined && crosshairValues[6].y}</li>
                    <li><span className='oscilloscope-color oscilloscope-color--navy'></span>{t('oscilloscope.reducerTemp')}: {crosshairValues[7] !== undefined && crosshairValues[7].y}</li>
                    <li><span className='oscilloscope-color oscilloscope-color--pink'></span>{t('oscilloscope.rpm')}: {crosshairValues[8] !== undefined && crosshairValues[8].y}</li>
                  </ul>
                </div>
              </Crosshair>
            </FlexibleWidthXYPlot>

What I would like to have is each line series being scaled perceptually to the 0-100% range without amending the actual values. I need those values still to be shown as I am using the crosshair to show them.

Upvotes: 1

Views: 832

Answers (1)

Pavlo Zabaikin
Pavlo Zabaikin

Reputation: 26

Here is an example how I scaled two graphs ( one values in millions, second in % ) to show on one plot at the same time.

export const getBound = (arr, key, max = true) => {
  if (!Array.isArray(arr)) {
    return false
  }
  // `${key}0` is a check for graphs that has y0 and x0 values, for example Bar Charts
  const key0 = `${key}0`
  let result = max ? 0 : Number(arr[0][key])
  arr.forEach(item => {
    if (max) {
      if (Number(item[key]) > result || (item[key0] && Number(item[key0]) > result)) {
        result = item[key0] ? (Number(item[key]) > Number(item[key0])
          ? Number(item[key]) : Number(item[key0])) : Number(item[key])
      }
    } else {
      if (Number(item[key]) < result || (item[key0] && Number(item[key0]) < result)) {
        result = item[key0] ? (Number(item[key]) < Number(item[key0])
          ? Number(item[key]) : Number(item[key0])) : Number(item[key])
      }
    }
  })
  return result
}


export const getScaleValues = (arr1, arr2, roundTicksTo = 5) => {
  const arr1AbsMax = Math.abs(getBound(arr1, 'y')) > Math.abs(getBound(arr1, 'y', false))
    ? Math.abs(getBound(arr1, 'y')) : Math.abs(getBound(arr1, 'y', false))

  const arr2AbsMax = Math.abs(getBound(arr2, 'y')) > Math.abs(getBound(arr2, 'y', false))
    ? Math.abs(getBound(arr2, 'y')) : Math.abs(getBound(arr2, 'y', false))

  const coef = arr1AbsMax / arr2AbsMax

  const scaled = arr2.map(item => {
    return Object.assign({}, item, {
      y: item.y * coef,
    })
  })

  const ticksFormat = (v) => formatPercentageTicks(v, coef, roundTicksTo)

  return {
    coef: coef,
    scaled: scaled,
    ticksFormat: ticksFormat,
  }
}

export const formatPercentageTicks = (value, coef, roundTo = 1) => {
  return `${round(value / (coef), roundTo)} %`
}

export const round = (num, roundTo) => {
  return num % roundTo < (Math.ceil(roundTo / 2))
    ? (num % roundTo === 0 ? num : Math.floor(num / roundTo) * roundTo) : Math.ceil(num / roundTo) * roundTo
}

If you have 9 Lines you could take 1 as default, and scale 8 others as % from default. Also, default YAxis will show numbers, and you could add additional Yaxis for % on the right side:

<YAxis orientation={'right'} tickFormat={v => scaledObj.ticksFormat(v)} />

Upvotes: 0

Related Questions