图(图)算法

时间:2020-03-05 18:49:59  来源:igfitidea点击:

有没有人有一个不错的算法来计算轴的最小值和最大值?

当为一组给定的数据项创建图表时,我希望能够给出算法:

  • 集合中的最大(y)值
  • 集合中的最小(y)值
  • 轴上出现的刻度线数
  • 一个必须显示为刻度的可选值(例如,显示+ ve和-ve值时为零)

该算法应返回

  • 最大轴值
  • 最小的轴值(尽管可以从最大的轴值,间隔大小和刻度数推断出)
  • 间隔大小

刻度线应有规律的间隔,且大小应"合理"(例如1、3、5,甚至可能是2.5,但无其他符号)。

可选值的存在会使此值倾斜,但是如果没有该值,则最大的项目应出现在顶部两个刻度线之间,而最小值则位于底部两个刻度线之间。

这是一个与语言无关的问题,但是如果周围有C#/。NET库,那将会很糟糕;)

解决方案

回答

我一直在使用jQuery flot图形库。它是开源的,并且很好地完成了轴/刻度线的生成。我建议我们看一下它的代码,然后从中提出一些想法。

回答

我可以推荐以下内容:

  • 设置吸引人的主线最少数量。这将取决于我们提供的数据的性质以及正在执行的绘图的大小,但是7是一个很好的数字
  • 根据1、2、5、10等的级数选择指数和乘数,这样至少会给我们最少的主行数。 (即(最大-最小)/(比例x 10 ^指数)> = minimum_tick_marks)
  • 找到适合我们范围的指数和乘数的最小整数倍。这将是第一个主要的滴答声。其余的价格变动是由此得出的。

它用于允许任意缩放数据的应用程序,看起来效果很好。

回答

好的,这是我为我们的一种应用程序想到的。请注意,它不会处理我们提到的"可选值"方案,因为我们的可选值始终为0,但我们修改起来并不难。

数据会不断添加到序列中,因此我们只需检查每个数据点的添加情况即可保持y值的范围最新;这是非常便宜的并且易于跟踪。最小和最大值相等是特殊情况:间距0表示不应绘制标记。

此解决方案与上述安德鲁的建议并无不同,不同之处在于它以略为模糊的方式处理指数乘数的任意分数。

最后,此示例在C#中。希望能帮助到你。

private float GetYMarkerSpacing()
    {
        YValueRange range   = m_ScrollableCanvas.
                    TimelineCanvas.DataModel.CurrentYRange;
        if ( range.RealMinimum == range.RealMaximum )
        {
            return 0;
        }

        float   absolute    = Math.Max(
                    Math.Abs( range.RealMinimum ),
                    Math.Abs( range.RealMaximum ) ),
            spacing     = 0;
        for ( int power = 0; power < 39; ++power )
        {
            float   temp    = ( float ) Math.Pow( 10, power );
            if ( temp <= absolute )
            {
                spacing = temp;
            }
            else if ( temp / 2 <= absolute )
            {
                spacing = temp / 2;
                break;
            }
            else if ( temp / 2.5 <= absolute )
            {
                spacing = temp / 2.5F;
                break;
            }
            else if ( temp / 4 <= absolute )
            {
                spacing = temp / 4;
                break;
            }
            else if ( temp / 5 <= absolute )
            {
                spacing = temp / 5;
                break;
            }
            else
            {
                break;
            }
        }

        return spacing;
    }