recharts#ReferenceLine JavaScript Examples

The following examples show how to use recharts#ReferenceLine. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: DashboardBarChart.js    From crypto-red.github.io with MIT License 5 votes vote down vote up
render() {

        const { classes, coins_markets } = this.state;

        const data_bar = coins_markets.map(function(data, key, array){

            return {
                name: data.name,
                changes: data.price_change_percentage_1y_in_currency
            };

        });

        return (
            <div className={classes.cardContainer}>
                <Fade in>
                    <Card className={classes.performanceCard}>
                        <CardHeader title={t( "components.dashboard_bar_chart.title")} />
                        <CardContent>
                            {
                                data_bar.length ?
                                    <Fade in>
                                        <div className={classes.barChart}>
                                            <ResponsiveContainer>
                                                <BarChart
                                                    width={400}
                                                    height={475}
                                                    data={data_bar}
                                                >
                                                    <CartesianGrid strokeDasharray="3 3" />
                                                    <XAxis dataKey="name" interval={0} angle={90} height={75} dy={10} textAnchor="start"/>
                                                    <YAxis tickFormatter={value => this._percent_formatter(value, true)} />
                                                    <Tooltip formatter={value => this._percent_formatter(value, true)} />
                                                    <ReferenceLine y={0} stroke="#000" />
                                                    <Bar dataKey="changes" fill="#131162" />
                                                </BarChart>
                                            </ResponsiveContainer>
                                        </div>
                                    </Fade>:
                                    <Fade in timeout={300}>
                                        <Skeleton height={475}/>
                                    </Fade>
                            }
                        </CardContent>
                    </Card>
                </Fade>
            </div>
        );
    }
Example #2
Source File: GraphDeathProjection.js    From covid-19 with MIT License 5 votes vote down vote up
GraphDeathProjectionRender = (props) => {
  let data = props.data;
  const max_date = props.max_date;
  const data_keys = props.data_keys;

  data = data.map(d => {
    d.name = moment(d.fulldate, "MM/DD/YYYY").format("M/D");
    return d;
  });
  data = data.sort((a, b) => moment(a.fulldate, "MM/DD/YYYY").toDate() - (moment(b.fulldate, "MM/DD/YYYY")).toDate());

  const [state, setState] = React.useState({
    showall: false,
  });

  const handleLogScaleToggle = event => {
    setState({ ...state, showall: !state.showall });
  };
  const cutoff = moment().subtract(30, 'days')
  const future = moment().add(30, 'days')
  data = data.filter(d => {
    let day = moment(d.fulldate, "MM/DD/YYYY");
    return day.isAfter(cutoff) && day.isBefore(future);
  });
  const formatYAxis = (tickItem) => {
    return myShortNumber(tickItem);
  }

  return <>
    <Grid container alignItems="center" spacing={1}>
      <Grid item onClick={handleLogScaleToggle}>
        <Typography>
          Daily
                </Typography>
      </Grid>
      <Grid item>
        <AntSwitch checked={state.showall} onClick={handleLogScaleToggle} />
      </Grid>
      <Grid item onClick={handleLogScaleToggle}>
        <Typography>
          Total
                </Typography>
      </Grid>
      <Grid item></Grid>
    </Grid>
    <ResponsiveContainer height={300} >
      <ComposedChart data={data} margin={{ top: 5, right: 30, left: 5, bottom: 5 }} >
        <XAxis dataKey="name" />
        <YAxis yAxisId={0} tickFormatter={formatYAxis} />
        <ReferenceLine x={moment(max_date, "MM/DD/YYYY").format("M/D")} label={{ value: props.max_label, fill: '#a3a3a3' }} stroke="#e3e3e3" strokeWidth={3} />
        <CartesianGrid stroke="#d5d5d5" strokeDasharray="5 5" />
        <Line type="monotone" dataKey={data_keys.key_mean} stroke="#000000" dot={{ r: 1 }} yAxisId={0} strokeWidth={2} />
        <Area type='monotone' dataKey={data_keys.key_lower} stackId="1" stroke='#8884d8' fill='#FFFFFF' />
        <Area type='monotone' dataKey={data_keys.key_delta} stackId="1" stroke='#82ca9d' fill='#82ca9d' />
        <Line type="monotone" dataKey="actualDeath_daily" stroke="#FF0000" dot={{ r: 1 }} strokeDasharray="2 2" yAxisId={0} strokeWidth={2} />
        <Line type="monotone" dataKey="actualDeath_moving_avg" stroke="#FF0000" dot={{ r: 1 }} yAxisId={0} strokeWidth={3} />
        {state.showall && <Line type="monotone" dataKey={data_keys.key_mean_cumulative} dot={{ r: 1 }} stroke="#000000" yAxisId={0} strokeWidth={1} />}
        {state.showall && <Line type="monotone" dataKey="actualDeath_total" dot={{ r: 1 }} stroke="#ff0000" yAxisId={0} strokeWidth={2} />}
        {state.showall && <Area type='monotone' dataKey={data_keys.key_lower_cumulative} stackId="2" stroke='#8884d8' fill='#FFFFFF' />}
        {state.showall && <Area type='monotone' dataKey={data_keys.key_delta_cumulative} stackId="2" stroke='#82ca9d' fill='#82ca9d' />}
        <Tooltip content={props.tooltip} />
        <Legend verticalAlign="top" payload={[
          { value: 'Actual Death', type: 'line', color: '#ff0000' },
          { value: 'Projection', type: 'line', color: '#000000' },
        ]} />
      </ComposedChart>
    </ResponsiveContainer>
    <Typography variant="body2">
      Source: The Institute for Health Metrics and Evaluation
                </Typography>
  </>
}
Example #3
Source File: MultiLinePlot.jsx    From covince with MIT License 4 votes vote down vote up
MainChart = React.memo((props) => {
  const {
    activeLineages,
    chart,
    dateRange,
    darkMode,
    precision,
    preset,
    stroke,
    tooltipEnabled,
    type,
    xAxisProps,
    yAxisConfig = {},
    zoomArea,
    ...chartProps
  } = props

  const { lineages, data, dates } = chart

  const yAxisDomain = useMemo(() => {
    if (yAxisConfig && yAxisConfig.domain) {
      return yAxisConfig.domain
    }
    if (preset === 'percentage' && type === 'area' && lineages.length === Object.keys(activeLineages).length) {
      return [0, 100]
    }
    if (dateRange && data.length) {
      if (type === 'area') {
        const [minIndex, maxIndex] = xAxisProps.domain
        const range = data.slice(minIndex, maxIndex + 1)
        let { sumY: max } = range[0]
        for (const { sumY } of range.slice(1)) {
          max = Math.max(sumY, max)
        }
        return [0, Math.ceil(max)]
      } else {
        const [minIndex, maxIndex] = xAxisProps.domain
        const range = data.slice(minIndex, maxIndex + 1)
        let { maxY: max } = range[0]
        for (const { maxY } of range.slice(1)) {
          max = Math.max(maxY, max)
        }
        return [0, Math.ceil(max)]
      }
    }
    if (preset === 'percentage' && type === 'area' && lineages.length) {
      return [0, 1]
    }
    return [0, 'auto']
  }, [preset, type, yAxisConfig, lineages, xAxisProps.domain, data])

  const yAxisTicks = useMemo(() => {
    if (preset === 'percentage') {
      if (lineages.length === 0) {
        return { ticks: false }
      }
      const fullScale = lineages.length === Object.keys(activeLineages).length
      if (fullScale) {
        return {
          tickFormatter: value => `${Math.min(parseFloat(value), 100)}%`,
          ticks: dateRange ? undefined : [0, 25, 50, 75, 100]
        }
      }
      return {
        tickFormatter: value => {
          if (value === 0) return '0%'
          if (value >= 100) return '100%'
          if (!Number.isInteger(value)) return `${value.toFixed(1)}%`
          return `${value}%`
        }
      }
    }
    return {
      tickFormatter: value => {
        const valueStr = value.toString()
        if (valueStr.length > 4) {
          const tripleFigureCount = Math.floor((valueStr.length - 1) / 3)
          const prefix = (value / Math.pow(1000, tripleFigureCount))
          const prefixStr = prefix.toString()
          return (
            (prefixStr.length < 4 ? prefixStr : prefix.toPrecision(3)) +
            (tripleFigureLabel[tripleFigureCount] || '')
          )
        }
        return value.toLocaleString()
      },
      ticks: dateRange ? undefined : yAxisConfig.ticks
    }
  }, [preset, lineages, activeLineages, yAxisConfig, dateRange])

  const grid =
    <CartesianGrid stroke={tailwindColors[stroke][darkMode ? 500 : 300]} />

  const [highlightedLineage, setHighlightedLineage] = useState(null)
  const tooltip = useMemo(() =>
    (tooltipEnabled && lineages.length > 0)
      ? <Tooltip
          content={ChartTooltip}
          cursor={{ stroke: tailwindColors[stroke][darkMode ? 300 : 400] }}
          dates={dates}
          percentage={preset === 'percentage'}
          precision={precision}
          sortByValue={type !== 'area'}
          highlightedItem={highlightedLineage}
        />
      : null
  , [tooltipEnabled, stroke, dates, preset, precision, highlightedLineage, type])

  const xAxis = useMemo(() =>
    <XAxis
      {...xAxisProps}
      fontSize='12'
      tick={data.length}
      tickFormatter={i => i in data ? format(new Date(data[i].date), 'd MMM') : ''}
      tickMargin='4'
      stroke='currentcolor'
    />
  , [data, xAxisProps])

  const yAxis =
    <YAxis
      type='number'
      allowDataOverflow={dateRange || yAxisConfig.allow_data_overflow || false}
      domain={yAxisDomain}
      width={48}
      stroke='currentcolor'
      tickMargin='4'
      tick={data.length}
      allowDecimals={false}
      {...yAxisTicks}
    />

  const areas = useMemo(() => {
    if (type === 'area') {
      return lineages.map(({ lineage, colour = fallbackColour }) => (
        <Area
          key={lineage}
          activeDot={{ stroke: tailwindColors[stroke][400] }}
          dataKey={lineage}
          dot={false}
          fill={colour}
          fillOpacity={highlightedLineage === lineage ? 0.8 : undefined}
          name={lineage}
          stackId='1'
          stroke={colour}
          type='monotone'
          animationDuration={animationDuration}
          isAnimationActive={true}
          onMouseEnter={({ name }) => { setHighlightedLineage(name) }}
          onMouseLeave={() => { setHighlightedLineage(null) }}
        />
      ))
    }
    return lineages
      .filter(_ => _.average !== 0)
      .map(({ lineage, colour = fallbackColour }) => {
        const key = `${lineage}_range`
        return (
          <Area
            key={key}
            activeDot={false}
            dataKey={key}
            fill={colour}
            name='_range'
            strokeWidth={0}
            type='monotone'
            animationDuration={animationDuration}
            isAnimationActive={true}
          />
        )
      })
  }, [lineages, stroke, type, highlightedLineage])

  const lines = useMemo(() => {
    if (type === 'area') return null
    return lineages.map(({ lineage, colour = fallbackColour }) =>
      <Line
        key={lineage}
        activeDot={{ stroke: tailwindColors[stroke][400] }}
        dataKey={lineage}
        dot={false}
        name={lineage}
        stroke={colour}
        type='monotone'
        animationDuration={animationDuration}
        isAnimationActive={true}
      />
    )
  }, [lineages, stroke, type])

  const yReference = useMemo(() => {
    if (yAxisConfig.reference_line === undefined) return null
    return (
      <ReferenceLine
        y={yAxisConfig.reference_line}
        stroke={tailwindColors[stroke][darkMode ? 400 : 600]}
        strokeDasharray={[8, 8]}
        label=''
        strokeWidth={2}
        style={{ mixBlendMode: darkMode ? 'screen' : 'multiply' }}
      />
    )
  }, [yAxisConfig.reference_line, stroke])

  return (
    <ComposedChart
      {...chartProps}
      data={[...data] /* new array required for animations */}
    >
      {grid}
      {areas}
      {xAxis}
      {yAxis}
      {tooltip}
      {yReference}
      {lines}
      {zoomArea.start !== undefined
        ? <ReferenceArea x1={zoomArea.start} x2={zoomArea.end} strokeOpacity={0.3} />
        : null}
    </ComposedChart>
  )
})
Example #4
Source File: MultiLinePlot.jsx    From covince with MIT License 4 votes vote down vote up
MultiLinePlot = props => {
  const {
    activeLineages,
    area_data,
    chartZoom,
    className,
    darkMode,
    date,
    groupStackedColours = true,
    height = 120,
    parameter,
    preset: deprecatedPreset,
    setDate,
    stroke = 'blueGray',
    tooltipEnabled,
    type,
    width,
    /* xAxis: xAxisConfig = {}, */
    yAxis: yAxisConfig,
    zoomEnabled
  } = props

  const preset = useMemo(() => {
    if (parameter && parameter.format === 'percentage') return 'percentage'

    // back compat
    if (deprecatedPreset) return deprecatedPreset
    if (parameter && parameter.id === 'p') return 'percentage'

    return null
  }, [parameter, deprecatedPreset])

  const precision = useMemo(() => {
    return parameter ? parameter.precision : undefined
  }, [parameter])

  const chart = useMemo(() => {
    const dataByDate = {}
    const lineageSum = {}

    for (const d of area_data) {
      if (d.parameter === parameter.id && d.lineage !== 'total') {
        const next = {
          ...dataByDate[d.date],
          date: d.date,
          [d.lineage]: d.mean,
          [`${d.lineage}_range`]: d.range
        }
        if (d.lineage in activeLineages && activeLineages[d.lineage].active) {
          next.maxY = Math.max(next.maxY || 0, d.range[1] || d.mean)
          next.sumY = (next.sumY || 0) + d.mean
        }
        dataByDate[d.date] = next
        const sum = lineageSum[d.lineage] || 0
        lineageSum[d.lineage] = (sum + d.mean)
      }
    }

    const data =
      orderBy(Object.values(dataByDate), 'date', 'asc')
        .map((d, index) => ({ ...d, index }))

    const dates = data.map(_ => _.date)

    const lineages = []
    for (const lineage of Object.keys(lineageSum)) {
      const { active, colour } = activeLineages[lineage]
      if (active) {
        lineages.push({ lineage, colour, average: lineageSum[lineage] / dates.length })
      }
    }

    const ordered = orderBy(lineages, 'average', 'asc')
    let sorted

    if (groupStackedColours) {
      sorted = []
      while (ordered.length > 0) {
        const [item] = ordered.splice(0, 1)
        if (sorted.includes(item)) continue
        sorted.push(item)
        for (let i = 0; i < ordered.length; i++) {
          const other = ordered[i]
          if (item.colour === other.colour) {
            sorted.push(other)
          }
        }
      }
    } else {
      sorted = ordered
    }

    return {
      lineages: sorted,
      data,
      dates
    }
  }, [area_data, activeLineages, groupStackedColours])

  const { data, dates } = chart

  const chartProps = useMemo(() => ({
    width,
    height,
    margin: { top: 12, left: 0, right: 24 }
  }), [width, height])

  const { dateRange, setChartZoom, clearChartZoom } = chartZoom

  const xAxisDomain = useMemo(() => {
    const minIndex = 0
    const maxIndex = data.length - 1
    if (dateRange && dates.length) {
      const [minDate, maxDate] = dateRange
      const min = minDate ? Math.max(dates.indexOf(minDate), minIndex) : minIndex
      let max = maxDate ? dates.indexOf(maxDate) : maxIndex
      if (max === -1) max = maxIndex
      return min < max ? [min, max] : [max, min]
    }
    return [minIndex, maxIndex]
  }, [dateRange, dates])

  const xAxisProps = useMemo(() => {
    const indices = Object.keys(dates)
    let ticks = indices
    if (dateRange) {
      const [minIndex, maxIndex] = xAxisDomain
      ticks = indices.slice(minIndex, maxIndex + 1)
    }
    return {
      allowDataOverflow: true,
      dataKey: 'index',
      domain: xAxisDomain,
      ticks,
      type: 'number'
    }
  }, [xAxisDomain, dates])

  const [zoomArea, setZoomArea] = React.useState({})
  const [isHovering, setIsHovering] = React.useState(false)

  const eventHandlers = useMemo(() => {
    const clickHandlers = {
      onClick: item => {
        if (date && item && !zoomArea.dragged) { // do not set date if not visible on chart
          setDate(data[item.activeLabel].date)
        }
        if (zoomEnabled) {
          setZoomArea({ dragged: zoomArea.dragged })
        }
      },
      onMouseDown: e => {
        if (e && zoomEnabled) {
          setZoomArea({ start: e.activeLabel, end: e.activeLabel, dragged: false })
        }
      },
      onMouseMove: e => {
        if (e) {
          setIsHovering(e.activeLabel !== undefined)
          if (zoomArea.start === undefined) return
          let end = e.activeLabel
          if (e.activeLabel === undefined) { // outside of axes
            end = xAxisDomain[zoomArea.end >= data.length / 2 ? 1 : 0]
          }
          setZoomArea({ start: zoomArea.start, end, dragged: true })
        }
      },
      onMouseLeave: e => {
        setIsHovering(false)
      },
      onMouseUp: (_, e) => {
        if (zoomArea.end !== zoomArea.start) {
          const xStart = data[zoomArea.start].date
          const xEnd = data[zoomArea.end].date
          const args = xStart < xEnd ? [xStart, xEnd] : [xEnd, xStart]
          setChartZoom(...args)
        }
        setZoomArea({ dragged: zoomArea.dragged })
      }
    }
    if (!tooltipEnabled) { // touch handlers need to be replaced when tooltip is missing
      return {
        ...clickHandlers,
        onTouchStart: clickHandlers.onMouseDown,
        onTouchMove: clickHandlers.onMouseMove,
        onTouchEnd: clickHandlers.onMouseUp
      }
    }
    return clickHandlers
  }, [zoomEnabled, data, zoomArea, isHovering])

  const cursor = useMemo(() => {
    if (zoomArea.start) return 'ew-resize'
    if (isHovering) return 'crosshair'
    return undefined
  }, [zoomArea, isHovering])

  return (
    <div
      className={classNames('relative select-none focus:outline-none', className)}
      onDoubleClick={clearChartZoom}
    >
      <MainChart
        {...{
          ...chartProps,
          ...eventHandlers,
          activeLineages,
          chart,
          dateRange,
          cursor,
          darkMode,
          precision,
          preset,
          stroke,
          tooltipEnabled,
          type,
          xAxisProps,
          yAxisConfig,
          zoomArea
        }}
      />
      <div className='absolute top-0 left-0 pointer-events-none'>
        <ComposedChart {...chartProps} data={data}>
          <XAxis
            {...xAxisProps}
            tick={false}
            stroke='none'
          />
          <YAxis
            width={48}
            tick={false}
            stroke='none'
          />
          <ReferenceLine
            x={dates.indexOf(date)}
            stroke={tailwindColors[stroke][darkMode ? 300 : 400]}
            label=''
            strokeWidth={2}
            style={{ mixBlendMode: darkMode ? 'screen' : 'multiply' }}
          />
        </ComposedChart>
      </div>
    </div>
  )
}
Example #5
Source File: AdvancedGraph.js    From covid-19 with MIT License 4 votes vote down vote up
Chart = (props) => {
  const ordered = (props.specs || []).sort((a, b) => {
    if (a.derived && !b.derived) {
      return -1;
    } else if (!a.derived && b.derived) {
      return 1;
    } else {
      return a.label < b.label ? -1 : 1;
    }
  });

  let YAxis0Color = "black";
  let YAxis1Color = undefined;
  for (const s of ordered) {
    if (s.rightAxis) {
      YAxis1Color = s.color;
    } else {
      YAxis0Color = s.color;
    }
  }

  function getvRefLines(lines) {
    let result = (lines || []).map((l, idx) => {
      return <ReferenceLine key={`vrefline${idx}`}
        x={l.date}
        stroke="#e3e3e3"
        strokeWidth={1}
      >
        <Label value={l.label} position={"insideTop"} fill="#b3b3b3" />
      </ReferenceLine>
    }
    );
    return result;
  }

  function getvRefAreas(lines) {
    let result = (lines || []).map((l, idx) => {
      const startdate = l.date;
      const today = moment().unix();
      let enddate = startdate + 14 * 24 * 60 * 60;
      while (enddate > today) {
        enddate -= 24 * 60 * 60;
      }
      return <ReferenceArea key={`vrefarea${idx}`}
        x1={startdate} x2={enddate}
        // stroke="red"
        // strokeOpacity={0.3}
        fillOpacity={0.15}
      />
    }
    );
    return result;
  }


  function gethRefLines(lines) {
    let result = (lines || []).map((l, idx) => {
      return <ReferenceLine key={`hrefline${idx}`}
        y={l.value}
        stroke="#e3e3e3"
        strokeWidth={1}
      >
        <Label value={l.label} position={"insideLeft"} ></Label>
      </ReferenceLine>
    }
    );
    return result;
  }

  let vRefLines = getvRefLines(props.vRefLines);
  let hRefLines = gethRefLines(props.hRefLines);

  return (
    <ResponsiveContainer height={300}>
      <LineChart data={props.data} margin={{ left: -4, right: 8 }}>
        {vRefLines}
        {hRefLines}
        {getvRefAreas(props.vRefLines)}
        <Tooltip
          formatter={valueFormatter}
          labelFormatter={props.timestampFormatter}
        />
        <XAxis
          dataKey="timestamp"
          tickFormatter={props.timestampFormatter}
        />
        <YAxis
          yAxisId={0}
          tick={{ fill: YAxis0Color }}
          scale={props.scale === 'Log' ? logScale : props.scale}
          width={50}
          tickFormatter={props.yAxisFormatter}
        />
        {YAxis1Color &&
          <YAxis
            yAxisId={1}
            tickFormatter={props.yAxisFormatter}
            width={35}
            tick={{ fill: YAxis1Color }}
            orientation="right"
          />
        }
        <CartesianGrid stroke="#d5d5d5" strokeDasharray="5 5" />

        {ordered.flatMap(spec => specToElements(spec))}
      </LineChart>
    </ResponsiveContainer>
  );
}