|
12 | 12 | const N_MIN = 64; |
13 | 13 | const N_MAX = 8192; |
14 | 14 |
|
15 | | - // K 上限:N²(多项式增长,lnK/N = 2lnN/N 全程保持在次指数区域) |
| 15 | + // K 上限:N³(多项式增长,lnK/N = 3lnN/N 全程保持在次指数区域) |
16 | 16 | function kMax(N) { |
17 | | - return N * N; |
| 17 | + return N * N * N; |
18 | 18 | } |
19 | 19 | // 渐近区域阈值:lnK/N 小于 SUB_EXP 视为次指数区域(理论线可信), |
20 | 20 | // 大于 TRANSITION 视为超出定理覆盖范围 |
|
554 | 554 | // 右侧角度副轴的范围据此换算 |
555 | 555 | const yMax = 1.05 * T.firstOrderMean(N, kHi, state.twoSided); |
556 | 556 |
|
| 557 | + // ECharts log 轴在跨度 ~12 个数量级时只生成个位数刻度,且 |
| 558 | + // customValues / interval / splitNumber 对 log 轴均无效(5.5.0 实测); |
| 559 | + // 改用 value 轴 + 数据 x 手动取 log10(K),刻度间隔 interval:1(每个数量级一个) |
| 560 | + const lg = Math.log10; |
| 561 | + const logData = (data) => data.map((p) => [lg(p[0]), p[1]]); |
| 562 | + |
557 | 563 | // lnK/N > SUB_EXP 的区间铺浅灰背景:此区域理论线开始偏离 |
558 | 564 | const kThreshold = Math.exp(SUB_EXP * N); |
559 | 565 | const markAreaData = |
560 | 566 | kThreshold < kHi |
561 | | - ? [[{ xAxis: kThreshold }, { xAxis: kHi }]] |
| 567 | + ? [[{ xAxis: lg(kThreshold) }, { xAxis: lg(kHi) }]] |
562 | 568 | : []; |
563 | 569 |
|
564 | 570 | const mcOv = mcOverlay1(td.ks); |
| 571 | + // MC 叠加层数据同样是 [K, ρ],统一做 log10 变换 |
| 572 | + const mcSeries = mcOv.series.map((s) => |
| 573 | + Object.assign({}, s, { data: logData(s.data) }) |
| 574 | + ); |
565 | 575 |
|
566 | 576 | chart1.setOption( |
567 | 577 | { |
|
571 | 581 | tooltip: { |
572 | 582 | trigger: 'axis', |
573 | 583 | // 理论与模拟系列共享同一整数 K 网格(theoryData1.ks), |
574 | | - // axis 触发下同 K 全部显示;IQR 带是闭合多边形(每个 K 两个点),不进 tip |
| 584 | + // axis 触发下同 K 全部显示;IQR 带是闭合多边形(每个 K 两个点),不进 tip。 |
| 585 | + // 横轴是 log10(K),显示时还原为 K(round 吸收浮点尾数) |
575 | 586 | formatter: (params) => { |
576 | 587 | let html = |
577 | | - 'K = ' + Math.round(params[0].axisValue).toLocaleString('en-US'); |
| 588 | + 'K = ' + Math.round(Math.pow(10, Number(params[0].axisValue))).toLocaleString('en-US'); |
578 | 589 | for (const p of params) { |
579 | 590 | if (p.seriesName.indexOf('IQR') >= 0) continue; |
580 | 591 | const v = p.value[1]; |
|
589 | 600 | legend: { bottom: 0 }, |
590 | 601 | grid: { left: 60, right: 40, top: 30, bottom: 45 }, |
591 | 602 | xAxis: { |
592 | | - type: 'log', |
| 603 | + // 名义上是对数刻度:坐标值 = log10(K)(见上面 lg/logData 变换) |
| 604 | + type: 'value', |
593 | 605 | name: 'K(向量个数)', |
594 | 606 | // 轴名在刻度数值行之下、右对齐收于轴端内侧: |
595 | 607 | // nameGap 对 end 放置不生效,用 verticalAlign top + padding 下移; |
596 | 608 | // padding 右侧留白与右轴 90° 标签隔开 |
597 | 609 | nameTextStyle: { align: 'right', verticalAlign: 'top', padding: [24, 0, 0, 0] }, |
598 | | - min: 2, |
599 | | - max: kHi, |
600 | | - // K 是整数计数;log 轴末端刻度由 10^log10(N²) 反算,带浮点尾数,需取整 |
| 610 | + // min 取 log 空间整数(K=1):value 轴 interval 网格从 min 起对齐, |
| 611 | + // 这样 interval:1 的刻度恰好落在每个数量级上(数据从 K=2 起, |
| 612 | + // 左端空出 0.3 个数量级可忽略) |
| 613 | + min: 0, |
| 614 | + max: lg(kHi), |
| 615 | + // 每个数量级一个刻度;刻度值为整数 log10(K),标签还原为 K 的整数码 |
| 616 | + interval: 1, |
601 | 617 | axisLabel: { |
602 | | - formatter: (v) => Math.round(v).toLocaleString('en-US'), |
| 618 | + formatter: (v) => Math.round(Math.pow(10, v)).toLocaleString('en-US'), |
| 619 | + // 右端点(K 上限)标签贴轴缘会被截断,且位数随 N 变化,直接隐藏; |
| 620 | + // 上限可在控件输入框看到 |
| 621 | + showMaxLabel: false, |
603 | 622 | }, |
604 | 623 | }, |
605 | 624 | yAxis: [ |
|
626 | 645 | type: 'line', |
627 | 646 | showSymbol: false, |
628 | 647 | smooth: true, |
629 | | - data: td.firstOrder, |
| 648 | + data: logData(td.firstOrder), |
630 | 649 | markArea: { |
631 | 650 | silent: true, |
632 | 651 | itemStyle: { color: 'rgba(0,0,0,0.045)' }, |
|
645 | 664 | type: 'line', |
646 | 665 | showSymbol: false, |
647 | 666 | smooth: true, |
648 | | - data: td.betaMedian, |
| 667 | + data: logData(td.betaMedian), |
649 | 668 | markLine: { |
650 | 669 | silent: true, |
651 | 670 | symbol: 'none', |
652 | 671 | lineStyle: { type: 'dashed', color: '#999' }, |
653 | 672 | label: { formatter: 'K = ' + K, position: 'insideEndTop' }, |
654 | | - data: [{ xAxis: K }], |
| 673 | + data: [{ xAxis: lg(K) }], |
655 | 674 | }, |
656 | 675 | }, |
657 | 676 | { |
|
660 | 679 | showSymbol: false, |
661 | 680 | smooth: true, |
662 | 681 | lineStyle: { type: 'dashed' }, |
663 | | - data: td.gumbelMedian, |
| 682 | + data: logData(td.gumbelMedian), |
664 | 683 | }, |
665 | | - ].concat(mcOv.series), |
| 684 | + ].concat(mcSeries), |
666 | 685 | }, |
667 | 686 | { notMerge: true } |
668 | 687 | ); |
|
0 commit comments