You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Amcharts 5 柱状图排序后部分柱状条消失问题求助

问题:Amcharts 5排序Y轴后部分柱状条消失
  • 用Amcharts 5做XY柱状图,Y轴是名称分类轴,X轴是0-1区间的比率值
  • 页面加载时图表显示正常,但通过下拉菜单按Exp_rank排序后,Y轴能正常排序,可部分柱状条(比如示例里的Mike)会消失
  • 数据量少于7个时问题就没了,数据越多问题越严重

数据项格式示例:

{'name': 'John Doe', 'Rate': .2, 'Exp_rank': 0}

原因分析

你当前的排序逻辑直接操作series.dataItems和yAxis.dataItems的索引,有两个核心问题:

  1. 索引不匹配:手动设置dataItem.set("index", n_idx)时,Exp_rank的值可能超出Y轴数据项的实际索引范围,或者和Amcharts内部维护的索引机制冲突,导致部分数据项没法正确关联到柱状条
  2. 数据同步错误:单独排序series.dataItems却没同步更新Y轴的数据源,Amcharts 5的XY系列依赖轴和系列数据的双向绑定,手动改索引会直接破坏这种绑定关系,导致柱状条丢失

修复方案

正确的做法是重新排序原始数据源,再更新Y轴和系列的数据,保证轴和系列的数据同步,避免绑定关系断裂:

  1. 排序时根据指定字段对原始数据做排序
  2. 调用yAxis.data.setAll()更新Y轴数据
  3. 调用series.data.setAll()更新系列数据
  4. 要保留动画的话,用轴的animateDataItems方法实现平滑过渡

完整修复代码

<!-- Resources -->
<script src='https://cdn.amcharts.com/lib/5/index.js'></script>
<script src='https://cdn.amcharts.com/lib/5/xy.js'></script>
<script src='https://cdn.amcharts.com/lib/5/themes/Animated.js'></script>
<script src='https://cdn.amcharts.com/lib/5/stock.js'></script>

<div id="chartdiv" style="width: 100%; height: 600px;"></div>
<div id="chartcontrols"></div>

<script>
var barchart;
sortdict = {'id1': 'Exp_rank'};

var root = am5.Root.new("chartdiv");
root.setThemes([
  am5themes_Animated.new(root)
]);

var chart = root.container.children.push(
        am5.Container.new(root, {
            layout: root.gridLayout,
            width: am5.percent(70),
            height: am5.percent(100),
        })
    )
chartstuff = create_bar('Rate','Test Chart');

// 保存原始数据,用于排序
let originalData = [ { name: 'John',
    Rate: 0.005,
    Exp_rank: 0 },
  { name: 'Steve',
    Rate: 0.005,
    Exp_rank: 1 },
  { name: 'Josh',
    Rate: 0.005,
    Exp_rank: 6 },
  { name: 'Greg',
    Rate: 0.005,
    Exp_rank: 7 },
  { name: 'Brandon',
    Rate: 0.0556,
    Exp_rank: 2 },
  { name: 'Dirk',
    Rate: 0.0833,
    Exp_rank: 3 },
  { name: 'Sean',
    Rate: 0.0857,
    Exp_rank: 4 },
  { name: 'Mike',
    Rate: 0.0909,
    Exp_rank: 5 } ]

// parameters: html_title, category, values
function create_bar(seriesName,title){
    
    var barchart = chart.children.push(
    am5xy.XYChart.new(
        root, {width: am5.percent(50),
            height: am5.percent(85),
            paddingLeft: 100,
            marginTop: 100,
        })
    )

    barchart.children.unshift(am5.Label.new(root, {
        html: title,
        dy: -50,
        fontWeight: 'bold',
        fontSize: 17
        }
    ))

    var xAxis = barchart.xAxes.push(
    am5xy.ValueAxis.new(root, {
        renderer: am5xy.AxisRendererX.new(root, {
            opacity: 1,
            numberFormat: "#.00'%'"
        })
    })
    );

    var yAxis = barchart.yAxes.push(
        am5xy.CategoryAxis.new(root, {
            renderer: am5xy.AxisRendererY.new(root, {
                minGridDistance: 12
            }),
            categoryField: 'name',
        })
        );
 
    const yAxisRenderer = yAxis.get('renderer');
    const xAxisRenderer = xAxis.get('renderer');
    yAxisRenderer.grid.template.setAll({ disabled: true, visible: false });
    xAxisRenderer.grid.template.setAll({ disabled: true, visible: false });

    yAxis.data.setAll(originalData);
    
    var series = barchart.series.push(am5xy.ColumnSeries.new(root, {
                name: seriesName,
                xAxis: xAxis,
                yAxis: yAxis,
                valueXField: 'Rate',
                categoryYField: 'name',
                fill: am5.color('#e1e1e1'),
                numberFormat : "#.00'%'",
                width: am5.percent(100),
                duration: 1000
            })
        );
            
    series.columns.template.set("interactive", true);
    series.columns.template.set("tooltipText",'Rate: {valueX}');

    xAxis.get('renderer').labels.template.set("fontSize", 12);
    yAxis.get('renderer').labels.template.set("fontSize", 10);

    series.data.setAll(originalData);
    series.appear();

    let mysorter = am5stock.DropdownListControl.new(root, {
    stockChart: barchart,
     name: "Sorting options",
    items: [{
            id: "id1",
            label: "Experience"
            }]
    })

    var toolbar = am5stock.StockToolbar.new(root, {
    container: document.getElementById("chartcontrols"),
    stockChart: barchart,
    controls: [
        mysorter
    ]
    });
    
    mysorter.events.on("selected",function(ev){
        sortCategoryAxis(series, ev.item.id, yAxis);
    })

    return [series, barchart];
}

function sortCategoryAxis(series,sortType, yAxis) {
    // 获取排序字段
    const sortField = sortdict[sortType];
    // 对原始数据排序
    const sortedData = [...originalData].sort((a, b) => {
        return a[sortField] - b[sortField];
    });
    
    // 更新Y轴和系列数据,自动同步排序
    yAxis.data.setAll(sortedData);
    series.data.setAll(sortedData);
    
    // 可选:添加轴数据项的动画过渡
    yAxis.animateDataItems({
        duration: 1000,
        easing: am5.ease.out(am5.ease.cubic)
    });
}
</script>

关键修改点

  • 把原始数据抽成全局变量originalData,方便排序时复用
  • 排序函数不再手动改数据项索引,直接对原始数据排序后更新轴和系列的数据源
  • 用yAxis.animateDataItems实现平滑排序动画,替代手动设置deltaPosition的复杂逻辑
  • 删掉了没必要的series.dataItems.sort操作,避免破坏内部数据结构

内容的提问来源于stack exchange,提问作者boody

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 09:37:03