C# 图形最大值的四舍五入

C# 图形最大值的四舍五入,c#,math,C#,Math,我正在绘制一些统计数据,可以是百分比、货币值或普通数字 我需要将graph控件轴的最大值设置为一个漂亮的整数,刚好比数据集中的最大值高一点。(图形控件的默认值不是我想要的) 有两点需要注意: 我为轴最大值设置的值应至少比数据集的最大值高5%(越低越好) 我在0 Y轴上方有4条水平线;因此,理想情况下,Y轴最大值应该很好地除以4 示例数据可能是: 200%, 100%, 100%, 100%, 75%, 50%, 9% 在这种情况下,220%可接受为最大值 $3500161, $1825223,

我正在绘制一些统计数据,可以是百分比、货币值或普通数字

我需要将graph控件轴的最大值设置为一个漂亮的整数,刚好比数据集中的最大值高一点。(图形控件的默认值不是我想要的)

有两点需要注意:

  • 我为轴最大值设置的值应至少比数据集的最大值高5%(越低越好)

  • 我在0 Y轴上方有4条水平线;因此,理想情况下,Y轴最大值应该很好地除以4

  • 示例数据可能是:

    200%, 100%, 100%, 100%, 75%, 50%, 9%
    
    在这种情况下,220%可接受为最大值

    $3500161, $1825223, $1671232, $110112
    
    在这种情况下,3680000美元就可以了。我想是370万美元吧


    有人能提出一个很好的公式吗?我可能需要调整设置,例如5%的边距可能更改为10%,或者我可能需要将4条水平线更改为5。

    对于您的第一次查询使用:

    DataView data = new DataView(dt);
    string strTarget = dt.Compute("MAX(target)", string.Empty).ToString();// target is your column name.
    int tTarget = int.Parse(strTarget.Equals("") ? "0" : strTarget); // Just in case if your string is empty.
    myChart.ChartAreas[0].AxisY.Maximum = myChart.ChartAreas[0].AxisY2.Maximum = Math.Ceiling(tTarget * 1.1); // This will give a 10% plus to max value.
    

    对于第二点,我想您可以使用短/长轴交错和偏移属性来解决这一问题。

    首先,您需要确定(图形顶部)/(最大数据点)的范围。将其下限设为1.05;合理的上限可能是1.1或1.15。范围越宽,图表顶部可能出现的空白越多,但数字可能越“美好”。或者,您可以先选择一个“良好”标准,然后选择最小的足够好的数字,其中上述比率至少为1.05

    您还可以通过放宽该下限来提高间隔的“精确性”,例如将其降低到1.02甚至1.0

    编辑:回应评论


    要找到一个好的最大值,你需要做的是取最大值加上边距,除以区间数,向上取整到最接近的“nice”值,然后乘以区间数。“nice”的合理定义可能是“floor(log_10(max value))-2的倍数”“nice”的更宽松定义将(平均)减少顶部的额外边距。

    以下是我用于创建图形轴的代码

    /// <summary>
    /// Axis scales a min/max value appropriately for the purpose of graphs
    /// <remarks>Code taken and modified from http://peltiertech.com/WordPress/calculate-nice-axis-scales-in-excel-vba/</remarks>
    /// </summary>
    public struct Axis 
    {
        public readonly float min_value;
        public readonly float max_value;
        public readonly float major_step;
        public readonly float minor_step;
        public readonly int major_count;
        public readonly int minor_count;
    
        /// <summary>
        /// Initialize Axis from range of values. 
        /// </summary>
        /// <param name="x_min">Low end of range to be included</param>
        /// <param name="x_max">High end of range to be included</param>
        public Axis(float x_min, float x_max)
        {
            //Check if the max and min are the same
            if(x_min==x_max)
            {
                x_max*=1.01f;
                x_min/=1.01f;
            }
            //Check if dMax is bigger than dMin - swap them if not
            if(x_max<x_min)
            {
                float temp = x_min;
                x_min = x_max;
                x_max = temp;
            }
    
            //Make dMax a little bigger and dMin a little smaller (by 1% of their difference)
            float delta=(x_max-x_min)/2;
            float  x_mid=(x_max+x_min)/2;
    
            x_max=x_mid+1.01f*delta;
            x_min=x_mid-1.01f*delta;
    
            //What if they are both 0?
            if(x_max==0&&x_min==0)
            {
                x_max=1;
            }
    
            //This bit rounds the maximum and minimum values to reasonable values
            //to chart.  If not done, the axis numbers will look very silly
            //Find the range of values covered
            double pwr=Math.Log(x_max-x_min)/Math.Log(10);
            double scl=Math.Pow(10, pwr-Math.Floor(pwr));
            //Find the scaling factor
            if(scl>0&&scl<=2.5)
            {
                major_step=0.2f;
                minor_step=0.05f;
            }
            else if(scl>2.5&&scl<5)
            {
                major_step=0.5f;
                minor_step=0.1f;
            }
            else if(scl>5&&scl<7.5)
            {
                major_step=1f;
                minor_step=0.2f;
            }
            else
            {
                major_step=2f;
                minor_step=0.5f;
            }
            this.major_step=(float)(Math.Pow(10, Math.Floor(pwr))*major_step);
            this.minor_step=(float)(Math.Pow(10, Math.Floor(pwr))*minor_step);
            this.major_count=(int)Math.Ceiling((x_max-x_min)/major_step);
            this.minor_count=(int)Math.Ceiling((x_max-x_min)/minor_step);
            int i_1=(int)Math.Floor(x_min/major_step);
            int i_2=(int)Math.Ceiling(x_max/major_step);
            this.min_value=i_1*major_step;
            this.max_value=i_2*major_step;
        }
        public float[] MajorRange
        {
            get
            {
                float[] res=new float[major_count+1];
                for(int i=0; i<res.Length; i++)
                {
                    res[i]=min_value+major_step*i;
                }
                return res;
            }
        }
        public float[] MinorRange
        {
            get
            {
                float[] res=new float[minor_count+1];
                for(int i=0; i<res.Length; i++)
                {
                    res[i]=min_value+minor_step*i;
                }
                return res;
            }
        }
    }
    
    //
    ///Axis适当缩放最小/最大值以用于图形
    ///从中获取和修改的代码http://peltiertech.com/WordPress/calculate-nice-axis-scales-in-excel-vba/
    /// 
    公共结构轴
    {
    公共只读浮点最小值;
    公共只读浮点最大值;
    公共只读浮动主要步骤;
    公共只读浮动小步;
    公共只读int主计数;
    公共只读整数次计数;
    /// 
    ///从值的范围初始化轴。
    /// 
    ///要包括的范围的低端
    ///包括高端产品
    公共轴(最小浮动x_,最大浮动x_)
    {
    //检查最大值和最小值是否相同
    如果(x_min==x_max)
    {
    x_max*=1.01f;
    x_min/=1.01f;
    }
    //检查dMax是否大于dMin-如果不大于,则交换它们
    
    如果(x#u max0&&scl2.5&&scl5&&scl)这是为什么标记为SQL?您可以在用于生成graph.SQL标记的C#代码中执行此操作。SQL标记已移除,图表控件将自动将Y轴的最小/最大间距设置为正好四分之一(如果指定4)。因此需要找到一个“精确”除以4的数字-这部分我必须自己做(如果我不喜欢他们自动生成的选择)。我之所以说5%,是因为这应该为条形标签留出足够的空间,使其位于条形上方。否则控件会将其放置在条形上。因此它需要在5-10%的范围内。事实上,我刚刚尝试了5%的精确值,这还不够(只是!).仍然不确定如何获得比这个数字更高的整数…是的,我想这大概就是我需要的,虽然我还没有完全理解数学!我必须修改它以使差距更小。但是谢谢!