Scottplot库

前言

笔者的.NET环境已经是6.0版本以上了,而在C#的窗体程序中,如果不是.NET frameword,就已经抛弃了chart图表控件,导致在win form里面没有原生的画图控件。这时候Scottplot就很好地解决了需求,但是也存在一些不足,没有像chart组件那么强大,有部分功能需要自己手写。笔者将介绍三个主要自己手写的功能

对数轴

对数轴可以用来

  • 数据压缩:对数轴可以将跨度很大的数据压缩到一个可管理的范围内,使得我们可以在图表上更容易地看到和理解数据。

  • 比例关系:在对数轴上,乘法和除法操作可以被转化为加法和减法操作。这使得比例关系更加直观。

  • 显示指数增长:对于指数增长的数据,使用对数轴可以将其转化为线性增长,从而更容易地看出趋势。

我将用一个例子解释:

​ 这是没有取对数的图
在这里插入图片描述

​ 取完对数的图

在这里插入图片描述

话不多说,接下来是重点部分,讲解如何实现对数轴(实现的是X轴的对数化)

  • 1.先是对X轴的处理,这里会用到一个刻度,相当于就是你想要展示的X轴的段,
 //首先是plt绘图的申明
 var plt = formsPlot1.Plot;
 List<double> xs = new List<double>();
 List<double> ys = new List<double>();

 // 给X轴和Y轴添加标签
 plt.XLabel("固定标准孔喉半径值");
 plt.YLabel("汞增量插值");
 plt.Clear();

 // 定义您想要在X轴上显示的刻度
 double[] xTicks = { 0.001, 0.01, 0.1, 1, 10, 100 };

 // 将这些刻度转换为对数尺度
 double[] logTicks = xTicks.Select(x => Math.Log10(x)).ToArray();

 // 定义对应的刻度标签
 string[] tickLabels = xTicks.Select(x => x.ToString("G")).ToArray();

 // 设置X轴的刻度和刻度标签
 plt.XAxis.ManualTickPositions(logTicks, tickLabels);

     
  • 2.数据取对数操作
 //进行画直线操作
 string name ="标签名字";
 plt.PlotScatter(xs.Select(x => Math.Log10(x)).ToArray(), ys.ToArray(), label: name);
 Func<double, string> tickLabeler = (x) => Math.Pow(10, x).ToString("G");

//设置了x轴刻度标签的格式
 plt.XAxis.TickLabelFormat(tickLabeler);

 //手动设置轴限制
 plt.SetAxisLimits(Math.Log10(0.001), Math.Log10(100), ys.Min(), ys.Max());

         
 //其余绘制操作
 plt.AxisAuto();
 plt.Legend(location: Alignment.UpperLeft);
 plt.Title("样本数据总览图");

 // 刷新图表
 this.formsPlot1.Render();

你们也可以看Github上的作者示例,Improve support for logarithmic axes by swharden · Pull Request #1393 · ScottPlot/ScottPlot (github.com)

多轴显示

有时候,你会在一个图上画两种类型的图,例如直方图和折线图,这时候就需要两个Y轴来表示。

​ 结果展示

在这里插入图片描述

  • 轴的新建很简单
// 创建一个新的Y轴
var yAxis2 = plt.AddAxis(Renderable.Edge.Left);

// 使用新的Y轴绘制散点图
plt.PlotScatter(xs, ys, yAxisIndex: yAxis2.AxisIndex);

但是难的是如何删除,尤其是你是批量生成两个轴的时候,plt.clear()无法清除轴,如果使用 plt.RemoveAxis(),那必须有这个轴的引用,要不然无法删除,我的一个方法,就是保存了这个变量,每一次先清除

var plt = formsPlot1.Plot;
plt.Clear();
if (this.axis != null)
{
    plt.RemoveAxis(this.axis); // 移除额外的Y轴
}

// 创建第二个Y轴
ScottPlot.Renderable.Axis yAxis2 = plt.AddAxis(ScottPlot.Renderable.Edge.Right);
this.axis = yAxis2;

直方图的绘制

是用类似的柱形图模拟

List<double> doubles = "数据";
double minValue = "自己输入值";
double maxValue = "自己输入值";
double step ="自己输入值";

var plt = formsPlot1.Plot;
plt.Clear();
// 创建一个具有固定大小箱子的直方图
var hist = ScottPlot.Statistics.Histogram.WithFixedBinSize(minValue, maxValue, binSize: step);
hist.AddRange(doubles);

// 获取每个箱子的概率密度
double[] probabilities = hist.GetProbability();
// 将直方图添加到ScottPlot对象中
var bar = plt.AddBar(values: probabilities, positions: hist.Bins);

// 调整每个柱子的宽度
bar.BarWidth = step;

// 自定义图表样式
plt.Title(this.GraphTitle);
string Xstring = this.SelectValueXaxis;
plt.XLabel(Xstring);
plt.YLabel("概率");

plt.AxisAuto();
plt.Legend(location: Alignment.UpperRight);

// 刷新图表
this.formsPlot1.Render();

在这里插入图片描述

如果要实现不均等区间的直方图,的自己切分。

以自己的数据为例子,我的区间是[-2,-1,-0.75,-0.5,-0.25,0,1,1.25等等]

//画图部分了
//进行画图的部分,进行筛选出来的结果
List<double> xs = this.XArray.Select(i => (double)i / 100).ToList(); ;
List<double> ys = this.YArray[specialIndex - 1].Select(i => (double)i / 100).ToList();




var plt = formsPlot1.Plot;
plt.Clear();
if (this.axis != null)
{
    plt.RemoveAxis(this.axis); // 移除额外的Y轴
}

// 创建第二个Y轴
ScottPlot.Renderable.Axis yAxis2 = plt.AddAxis(ScottPlot.Renderable.Edge.Right);
this.axis = yAxis2;

// 给y轴添加说明
plt.YLabel("累计百分比");


// 创建一个具有固定大小箱子的直方图
var hist = ScottPlot.Statistics.Histogram.WithFixedBinSize(min: -2, max: 9, binSize: 0.25);
hist.AddRange(xs);

// 将直方图的计数值作为条形图添加到绘图中

//下面的ys是一个区间的数组
double[] ys_area = new double[27];
for (int i = 0; i < ys_area.Length - 1; i++)
{
    ys_area[i] = ys[i + 1] - ys[i];
}
ys_area[ys_area.Length - 1] = 0;
//变成相同个数的new
double[] ys_new = new double[hist.Bins.Length];
for (int i = 1; i < xs.Count(); i++)
{
    double start = xs[i - 1] - xs[0];
    int startValue = (int)(start / 0.25);

    double end = xs[i] - xs[0];
    int endValue = (int)(end / 0.25);

    for (int j = startValue; j < endValue; j++)
    {
        ys_new[j] = ys_area[i - 1];
    }

}

var bar = plt.AddBar(values: ys_new, positions: hist.Bins);
bar.BarWidth = 0.25;
// 将条形图关联到第二个Y轴
bar.YAxisIndex = yAxis2.AxisIndex;

plt.PlotScatter(xs.ToArray(), ys.ToArray(), label: "累计曲线");


plt.XLabel("φ的值");

plt.AxisAuto();
plt.Legend(location: Alignment.UpperRight);
plt.Title("第一个数据的绘图展示");

// 刷新图表
this.formsPlot1.Render();

Logo

鸿蒙生态一站式服务平台。

更多推荐