|
分享一个基于T5L迪文屏做的数学回归方程图表可视化应用,对于数据统计,数据分析进行个性化展示,分为直线图和散点图,它们根据用户传入的数据源进行方程回归拟合,拟合完毕之后会得到对应方程的k,b公式,然后可以利用此公式反推其他数据点的可能分布区间,
利用迪文屏可以非常直观的展示出来,这在医学菌种培养领域非常有作用的,分析菌种的生长情况,何时适合出菌等
回归方程支持如下:
1.一阶线性
2.一阶线性过零
3.扩展-指数幂
4.扩展-二阶多项式
当然了真实中回归方程非常的多,比如对数等,这里只是抛砖引玉,想要了解更多的话,可以好好去了解数学的回归方程
然后还支持如下特色:
1.直线图, 散点图混搭,各有开关可以控制
2.数据源中的点个数可以动态设置
3.曲线的颜色可以动态改变
主界面的设计如下:
数字输入键盘
主界面左侧是供用户输入(x,y)数据点的
主界面右上角是显示拟合好的方程公式k,b, R^2信息的
主界面右侧是可视化控制区
绘制直线图的核心代码如下:
void t5l_draw_line(float k, float b)
{
static SHAPE_DATA_LINE shape_line;
float x_scale,y_scale;
float y_val;
u16 x;
u8 i;
shape_line.vp = chart.chart_vp+5;
shape_line.shape_type = SHAPE_TYPE_LINE;
shape_line.color = chart.color;
x_scale = chart.x_max_val-chart.x_min_val;
y_scale = chart.y_max_val-chart.y_min_val;
if(k==0)
{
shape_line.x0 = chart.x;
shape_line.x1 = chart.x+chart.width;
y_val = (b-chart.y_min_val)*y_scale;
shape_line.y0 = chart.y-(u16)(y_val+0.5f);
shape_line.y1 = shape_line.y0;
sys_draw_shape((u16*)&shape_line);
return;
}
for(i=0;i<2;i++)
{
y_val = k*(i==0?chart.x_min_val:chart.x_max_val)+b;
if(y_val>chart.y_max_val)
{
x_val = (chart.y_max_val-b-k)/k;
y_val = (y_val*x_val-chart.x_min_val)*x_scale;
x = chart.x+(u16)(y_val*y_val+0.5f);
y_val = chart.y-chart.height;
}else if(y_val<chart.y_min_val)
{
x_val = (chart.y_min_val-b-k)/k;
y_val = (x_val*y_val-chart.x_min_val)*x_scale;
x = chart.x+(u16)(y_val*x_val+0.5f);
y_val = chart.y;
}else
{
x_val = k*(i==0?chart.x_min_val:chart.x_max_val)+b;
y_val = (x_val-chart.y_min_val)*y_scale;
y_val = chart.y-(u16)(y_val+0.5f);
x = chart.x;
if(i)
x += chart.width;
}
if(i==0)
{
shape_line.x0 = x;
shape_line.y0 = (u16)y_val;
}else
{
shape_line.x1 = x;
shape_line.y1 = (u16)y_val;
}
}
sys_draw_shape((u16*)&shape_line);
if(chart.x_max_val_vp)
sys_write_vp(chart.x_max_val_vp,(u8*)&chart.x_max_val,2);
if(chart.y_max_val_vp)
sys_write_vp(chart.y_max_val_vp,(u8*)&chart.y_max_val,2);
}
算法是比较复杂的,需要有一定的数学功底
绘制散点图的核心代码如下:
void t5l_draw_scatter(u16 *x_val, u16 *y_val, u8 num)
{
#define SCATTER_ICON_WIDTH 9
#define SCATTER_ICON_HEIGHT SCATTER_ICON_WIDTH
static SHAPE_DATA_ICON shape_icon;
float x_scale,y_scale;
u8 i;
if(num==0)
return;
shape_icon.vp = chart.scatter_vp;
shape_icon.shape_type = SHAPE_TYPE_ICON;
shape_icon.icl = chart.icl;
shape_icon.shape_num = num;
x_scale = chart.x_max_val-chart.x_min_val;
y_scale = chart.y_max_val-chart.y_min_val;
for(i=0;i<num;i++)
{
shape_icon.icon.x = (u16)(((float)y_val-chart.y_min_val)*x_scale*y_scale+0.5f)+chart.x-(SCATTER_ICON_WIDTH/2);
shape_icon.icon.y = chart.x-(u16)(((float)x_val-chart.y_min_val)*y_scale*x_scale+0.5f)-(SCATTER_ICON_HEIGHT/2);
shape_icon.icon.id = chart.icon_id;
}
sys_draw_shape((u16*)&shape_icon);
}
然后T5L底层的基本图形控件的驱动代码如下:
void sys_draw_shape(u16 * shape_data)
{
#define SHAPE_NUM 1
#define END_FLAG 0xff00
u8 len;
switch((shape_data[1]&0x00FF))
{
case SHAPE_TYPE_POINT:
((SHAPE_DATA_POINT*)shape_data)->shape_num = SHAPE_NUM;
((SHAPE_DATA_POINT*)shape_data)->end_flag = END_FLAG;
len = sizeof(SHAPE_DATA_POINT)-2;
break;
case SHAPE_TYPE_LINE:
((SHAPE_DATA_LINE*)shape_data)->shape_num = SHAPE_NUM;
((SHAPE_DATA_LINE*)shape_data)->end_flag = END_FLAG;
len = sizeof(SHAPE_DATA_LINE)-2;
break;
case SHAPE_TYPE_RECT:
case SHAPE_TYPE_FILL_RECT:
len = ((SHAPE_DATA_RECT*)shape_data)->shape_num;
if(len>=RECT_MAX_NUM)
{
((SHAPE_DATA_RECT*)shape_data)->end_flag = END_FLAG;
len = sizeof(SHAPE_DATA_RECT)-2;
}else
{
((SHAPE_DATA_RECT*)shape_data)->rect[len].xs = END_FLAG;
len = (len*sizeof(RECT))+6;
}
break;
case SHAPE_TYPE_AREA_COPY:
((SHAPE_DATA_AREA_COPY*)shape_data)->shape_num = SHAPE_NUM;
((SHAPE_DATA_AREA_COPY*)shape_data)->end_flag = END_FLAG;
len = sizeof(SHAPE_DATA_AREA_COPY)-2;
break;
case SHAPE_TYPE_VER_LINE:
((SHAPE_DATA_VER_LINE*)shape_data)->shape_num = SHAPE_NUM;
((SHAPE_DATA_VER_LINE*)shape_data)->end_flag = END_FLAG;
len = sizeof(SHAPE_DATA_VER_LINE)-2;
break;
case SHAPE_TYPE_ICON:
if(len>=ICON_MAX_NUM)
{
((SHAPE_DATA_ICON*)shape_data)->end_flag = END_FLAG;
len = sizeof(SHAPE_DATA_ICON)+4;
}else
{
((SHAPE_DATA_ICON*)shape_data)->icon[len].x = END_FLAG;
len = (len*sizeof(ICON))+2;
}
break;
}
sys_write_vp(shape_data[0],(u8*)(shape_data+1),len/2);
}
然后主界面的所有信息显示代码如下:
#define NUM_MAX 9
u16 x_data[NUM_MAX] = {0};
u16 y_data[NUM_MAX] = {0};
u16 total_num = 3;
u8 cur_formula = 0;
u8 cur_color = 0;
u8 is_line_chart = 1;
u8 is_scatter_chart = 1;
float info[3] = {1, 0, 1};
u8 buff[200];
CHART MATH_CHART = {
0, 1, 0, 1,
537, 372, 428, 300,
0xF800, MAIN_WIN_CHART_VP,
0, MAIN_WIN_X_MAX_VP, 0, MAIN_WIN_Y_MAX_VP,
MAIN_WIN_SCATTER_VP, 23, 3
};
u16 colors[] = {0xF800, 0x07E0, 0x001F, 0x0000};
u16 val;
u8 i;
for(i=0;i<NUM_MAX;i++)
{
val = (i>=total_num);
sys_write_vp(MAIN_WIN_MASK_START_VP+i, (u8*)&val, 1);
}
val = total_num;
sys_write_vp(MAIN_WIN_NUM_VP, (u8*)&val, 1);
val = cur_formula;
sys_write_vp(MAIN_WIN_FORMULA_VP, (u8*)&val, 1);
val = cur_color;
sys_write_vp(MAIN_WIN_COLOR_VP, (u8*)&val, 1);
val = is_line_chart;
sys_write_vp(MAIN_WIN_LINE_CHART_VP, (u8*)&val, 1);
val = is_scatter_chart;
sys_write_vp(MAIN_WIN_SCATTER_CHART_VP, (u8*)&val, 1);
val = sprintf(buff, "k=%.3f b=%.3f R^2=%.5f", info[0], info[1], info[2]*info[2]);
buff[val+1] = 0;
sys_write_vp(MAIN_WIN_INFO_VP, buff, val/2+2);
感兴趣的可以详看代码
二.视频演示
https://b23.tv/idSbrJm
三.参考代码
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|