Nivo 条形图调用标签函数数百次

Posted

技术标签:

【中文标题】Nivo 条形图调用标签函数数百次【英文标题】:Nivo bar chart calling label function hundreds of times 【发布时间】:2020-06-26 10:27:06 【问题描述】:

我正在使用 Nivo 栏来表示用户的预算进度。我通过将类别余额除以类别目标来标准化数据。示例数据。

[
    "category": "Gas",
    "budget": 0.24,
    "over_budget": 0.0
,

    "category": "Groceries",
    "budget": 1.0,
    "over_budget": 0.26
]

我不希望将这些值用作图表上的标签。我打算用实际余额值作为标签。我有一个端点,它将返回一个类别的余额,并尝试了以下使用该值:

<ResponsiveBar
...
label=d => this.getDollarAmount(d.value)
...
>

功能POC为:

getDollarAmount(value) 
    console.log("hitting getDollarAmount")
    return 1
  ;

日志消息被记录了 500 多次。我的期望是,对于图表中的每个条形,该函数只会被点击一次。

我仍在学习反应,所以这可能是显而易见的。提前致谢!

编辑 - 这是整个 BarChart 组件:

import axios from 'axios';

import React,  Component  from "react";

import  ResponsiveBar  from '@nivo/bar'

// Nivo theming
const theme = 
  axis: 
    ticks: 
      line: 
        stroke: "#e9ecee",
        strokeWidth: 40
      ,
      text: 
        // fill: "#919eab",
        fill: "black",
        fontFamily: "BlinkMacSystemFont",
        fontSize: 16
      
    
  ,
  grid: 
    line: 
      stroke: "#e9ecee",
      strokeWidth: 5
    
  ,
  legends: 
    text: 
      fontFamily: "BlinkMacSystemFont"
    
  
;

let budgetStatusAPI = 'http://127.0.0.1:8000/api/budget_status/?auth_user=1&month=2020-02-01';

class BarChart extends Component 

  constructor(props) 
    super(props);

    this.state = 
      data: [],
    

    this.getDollarAmount = this.getDollarAmount.bind(this);
  


  componentDidMount() 
    console.log("component did mount")

    axios.get(budgetStatusAPI).then(response => 
      this.setState(
        data: response.data
      , function () 
        console.log(this.state.data);
      )
    );
  

  componentDidUpdate() 
    console.log("component did update")
  

  getDollarAmount(value) 
    console.log("hitting getDollarAmount")
    console.log(value)
    return 1
  ;


  render() 

    const hard_data = [
        
          "category": "Groceries",
          "budget_status": 1.0,
          "over_budget": .26,
        ,
        
          "category": "Gas",
          "budget_status": .24,
          "over_budget": 0.0,
        ]

    return(

      <ResponsiveBar
        maxValue=1.5
        markers=[
            
                axis: 'x',
                value: 1,
                lineStyle:  stroke: 'rgba(0, 0, 0, .35)', strokeWidth: 2 ,
                legend: 'Goal',
                legendOrientation: 'horizontal',
                legendPosition: 'top'
            ,
        ]
        enableGridX=false
        gridXValues=[1]
        enableGridY=false
        data=this.state.data
        // data=hard_data
        keys=['budget_status', 'over_budget']
        indexBy="category"
        margin= top: 25, right: 130, bottom: 50, left: 125 
        padding=0.3
        layout="horizontal"
        colors= scheme: 'set2' 
        theme=theme
        defs=[
            
                id: 'dots',
                type: 'patternDots',
                background: 'inherit',
                color: '#38bcb2',
                size: 4,
                padding: 1,
                stagger: true
            ,
            
                id: 'lines',
                type: 'patternLines',
                background: 'inherit',
                color: '#eed312',
                rotation: -45,
                lineWidth: 6,
                spacing: 10
            
        ]
        borderColor= from: 'color', modifiers: [ [ 'darker', 1.6 ] ] 
        axisBottom=null
        label=d => this.getDollarAmount(d.value)
        isInteractive=false
        animate=true
        motionStiffness=90
        motionDamping=15
    />
    )
  



export default BarChart;

转载于此:https://codesandbox.io/s/nivo-bar-label-issue-k4qek

【问题讨论】:

您的组件(或其他应用程序状态管理)代码中有一些东西会触发多个渲染。请提供完整的组件代码。 我已经添加了整个组件。我注意到,当我对数据使用硬编码值时,不会发生此问题。如果我使用从状态中抓取的数据,它就会发生。 我在这里转载了这个:codesandbox.io/s/nivo-bar-label-issue-k4qek 仍然不确定它为什么会发生。 请在下面查看我的答案。 【参考方案1】:

之所以会发生多次调用,是因为条形图正在为每个动画刻度/帧渲染调用 label 函数。如果我们设置一个计数器,我们将看到将animate 属性设置为true,它将从450+ 渲染到550+ 次,但是如果我们将属性animate 设置为false,我们将它会渲染6 次,这正是&gt; 0.0 的价格值。

如果您想避免所有这些渲染,则必须使用 animate=false 属性禁用动画,如下所示:

getDollarAmount(value) 
  // Remove every console.log inside this function

  return `$$value`


render() 
  return (
    <ResponsiveBar
      animate=false
      label=d => this.getDollarAmount(d.value)
      ...
  );

您可以检查它是否运行到您克隆的CodeSandbox。我已将animate 设置为false 并且counter 内的getDollarAmount 日志正在调用6 次。尝试将animate 更改为true,您将看到500+- 渲染。

另外,您不必为每个label 调用创建一个函数,您只需传递getDollarAmount 函数并让它处理整个d 参数,如下所示:

getDollarAmount(d) 
  // Remove every console.log inside this function

  return `$$d.value`


render() 
  return (
    <ResponsiveBar
      animate=false
      label=this.getDollarAmount
      ...
  );

【讨论】:

我怎么知道它还没有调用该函数数百次? @brewcrazy 你是对的,这不是罪魁祸首,动画才是。检查我更新的答案。

以上是关于Nivo 条形图调用标签函数数百次的主要内容,如果未能解决你的问题,请参考以下文章

Python使用seaborn可视化分组条形图并且在分组条形图的条形上添加数值标签(seaborn grouped bar plot add labels)

Matplotlib 条形图:对角刻度标签

使用 ggplot 在分组条形图上定位标签

剑道条形图 - 顶部的系列标签?

python使用matplotlib绘制水平条形图并在条形图上添加实际数值标签实战

如何在ggplot2中并排条形图上居中标签