Part 6 - 开发设备数据可视化

2023-10-06
5分钟阅读时长

【版本】

当前版本号v20231006

版本修改说明
v20231006初始化版本

【实验名称】 实验6.1 开发最近气温变化曲线图界面

【实验目的】

  • 掌握 Android 的可视化界面开发
  • 掌握 MPAndroidChart 框架

【实验环境】

  • 一台运行 64 位版本的 Windows(8、10 或 11)、Linux、macOS(10.14 Mojave 或更高版本)或 Chrome 操作系统的计算机。
  • 计算机可以访问互联网。
  • 内存:至少6G
  • 硬盘:至少空余20G
  • JDK 8或以上
  • Android Studio

【实验要求】

  • 完成以下智能温度采集的气温变化曲线图界面

【实验步骤】

  1. 在 settings.gradle下添加以下代码,加入MPAndroidChart包的仓库地址。
maven { url 'https://jitpack.io' }
  1. app/build.gradle内 dependencies 加入以下依赖包。
	
implementation 'org.litepal.guolindev:core:3.2.3'
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
  1. ThermometerActivity 参考代码,请自行完成代码。
package iot.app.smarthome.ui.device;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.Description;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

import iot.app.smarthome.R;

public class ThermometerActivity extends AppCompatActivity {

    private final static class TempValueFormatter extends ValueFormatter{
        @Override
        public String getFormattedValue(float v) {
            return (int)v+"\u2103";
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_thermometer);
        LineChart lineChart=findViewById(R.id.lineChart);

        List<Entry> list=new ArrayList<>();
        //其中两个数字对应的分别是 X轴 Y轴
        list.add(new Entry(7.0F,26F));
        list.add(new Entry(8.0F,29F));
        list.add(new Entry(9.0F,30F));
        list.add(new Entry(10.0F,31F));
        list.add(new Entry(11.0F,32F));

        //设置图表的数据
        LineDataSet lineDataSet=new LineDataSet(list,"最近气温变化");
        LineData lineData=new LineData(lineDataSet);
        lineData.setValueFormatter(new TempValueFormatter());
        lineChart.setData(lineData);
        //设置图表描述
        Description description=new Description();
        description.setText("最近气温变化");
        lineChart.setDescription(description);
        //获取 X 轴
        XAxis xAxis=lineChart.getXAxis();
        //设置 X 轴在底部
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxis.setLabelCount(list.size(), false);// 强制设置标签个数
        xAxis.setGranularity(1f);//设置X轴刻度间距

        //设置 X 轴的格式化显示内容
        xAxis.setValueFormatter(new ValueFormatter() {   //X轴自定义坐标
            @Override
            public String getFormattedValue(float v) {
                //TODO:请完善此处代码,返回时间格式 h:mm
            }
        });
        //获取左 Y 轴
        YAxis yLeftAxis=lineChart.getAxisLeft();
        //获取左 Y 轴格式化显示内容
        yLeftAxis.setValueFormatter(new TempValueFormatter());
        yLeftAxis.setAxisMinimum(23f);//设置最小值
        yLeftAxis.setGranularity(2f);//设置Y轴刻度间距
        yLeftAxis.setLabelCount(list.size(), false); // 强制设置标签个数
        //获取右边的Y轴
        YAxis yRightAxis=lineChart.getAxisRight();
        yRightAxis.setEnabled(true);
        yRightAxis.setValueFormatter(new TempValueFormatter());
        yRightAxis.setAxisMinimum(23f);//设置最小值
        yRightAxis.setGranularity(2f);//设置Y轴刻度间距
        yRightAxis.setLabelCount(list.size(), false); // 强制设置标签个数
    }
}

【实验名称】 实验6.2 升级最近气温变化曲线图界面(选做)

【实验目的】

  • 掌握 LitePal 框架的应用
  • 掌握 MPAndroidChart 框架

【实验环境】

  • 一台运行 64 位版本的 Windows(8、10 或 11)、Linux、macOS(10.14 Mojave 或更高版本)或 Chrome 操作系统的计算机。
  • 计算机可以访问互联网。
  • 内存:至少6G
  • 硬盘:至少空余20G
  • JDK 8或以上
  • Android Studio

【实验要求】

  • (1)本实验承接[实验6.1](#【实验名称】 实验6.1 开发最近气温变化曲线图界面)项目
  • (2)修改实验6.1 的ThermometerActivity,实现数据从 Sqlite 读取时间和温度数据。

【参考代码】

  • TempVo 是使用 Litepal 框架实现的保存时间和温度信息的类。
package iot.app.smarthome.model.device;

import org.litepal.annotation.Column;
import org.litepal.crud.LitePalSupport;

public class TempVo extends LitePalSupport {
    @Column(unique = true)
    private int dateHour;//默认格式yyyyMMddhh
    private float degree;

    public int getDateHour() {
        return dateHour;
    }

    public float genDateHourF() {
        return dateHour%100;
    }

    public void setDateHour(int dateHour) {
        this.dateHour = dateHour;
    }

    public float getDegree() {
        return degree;
    }

    public void setDegree(float degree) {
        this.degree = degree;
    }
}
  • litepal.xml 配置
<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <dbname value="SmartHome" />
    <version value="3" />
    <list>
        <mapping class="iot.app.smarthome.model.device.Device" />
        <mapping class="iot.app.smarthome.model.user.UserInfoVo"  />
        <mapping class="iot.app.smarthome.model.device.TempVo"  />
    </list>
</litepal>

【实验名称】 实验6.3 实现多种图组合界面(选做)

【实验目的】

  • 掌握 CombinedChart 和 CombinedData 的使用
  • 掌握 MPAndroidChart 框架

【实验环境】

  • 一台运行 64 位版本的 Windows(8、10 或 11)、Linux、macOS(10.14 Mojave 或更高版本)或 Chrome 操作系统的计算机。
  • 计算机可以访问互联网。
  • 内存:至少6G
  • 硬盘:至少空余20G
  • JDK 8或以上
  • Android Studio

【实验要求】

  • (1)实现TempHumStatisticActivity,实现柱状图和曲线图组合展示的界面。

【参考代码】

  • TempHumStatisticActivity,请完善其中的代码。
package iot.app.smarthome.ui.device;

import android.graphics.Color;
import android.os.Bundle;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.github.mikephil.charting.charts.CombinedChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.CombinedData;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.formatter.IndexAxisValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;

import java.util.ArrayList;
import java.util.List;

import iot.app.smarthome.R;

public class TempHumStatisticActivity extends AppCompatActivity {

    private CombinedChart dataChart;//图表
    private CombinedData data;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_energy_statistic);
        dataChart = (CombinedChart) findViewById(R.id.combinedChart);
        showDataOnChart();
        Legend legend = dataChart.getLegend();
        legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER);
        legend.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP);
    }

    /**
     * 展示数据
     */
    private void showDataOnChart() {
        //绘制图表数据
        data = new CombinedData();
        //TODO:设置折线图数据
        
        //TODO:设置柱状图数据
		
        //TODO:设置横坐标数据
		
        //TODO:设置右侧纵坐标数据
		
        //TODO:设置左侧纵坐标数据
		
        dataChart.setTouchEnabled(false);
        dataChart.getDescription().setEnabled(false);
        dataChart.setDrawGridBackground(false);
        dataChart.setDrawBarShadow(false);
        dataChart.setHighlightFullBarEnabled(true);
        dataChart.animateX(2000);
    }

    /**
     * 设置横坐标数据
     */
    private void setAxisXBottom() {
        List<String> valuesX = new ArrayList<>();
        String date[] = {"1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"};
        for (int i = 0;i < date.length;i++){
            valuesX.add(date[i]);
        }
        XAxis bottomAxis = dataChart.getXAxis();
        bottomAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        bottomAxis.setCenterAxisLabels(true);
        bottomAxis.setValueFormatter(new IndexAxisValueFormatter(valuesX));
        bottomAxis.setAxisMinimum(data.getXMin());
        bottomAxis.setAxisMaximum(data.getXMax() + 0.5f);
        bottomAxis.setLabelCount(date.length);
        bottomAxis.setAvoidFirstLastClipping(false);
    }

    /**
     * 设置右侧纵坐标数据
     */
    private void setAxisYRight() {
        YAxis right = dataChart.getAxisRight();
        right.setValueFormatter(new ValueFormatter() {
            @Override
            public String getFormattedValue(float value) {
                return value + "℃";
            }
        });
        right.setDrawGridLines(false);
    }

    /**
     * 设置左侧纵坐标数据
     */
    private void setAxisYLeft() {
        YAxis left = dataChart.getAxisLeft();
        left.setValueFormatter(new ValueFormatter() {
            @Override
            public String getFormattedValue(float value) {
                return value + "ml";
            }
        });
        left.setDrawGridLines(false);
    }

    /**
     * 设置折线图绘制数据
     * 温度
     * @return
     */
    public LineData getLineData() {
        LineData lineData = new LineData();
        List<Entry> customCounts = new ArrayList<>();
        float[] data = {2.0f, 2.2f, 3.3f, 4.5f, 6.3f, 10.2f, 20.3f, 23.4f, 23.0f, 16.5f, 12.0f, 6.2f};
        //人数
        for (int i = 0; i < data.length; i++) {
            customCounts.add(new Entry(i + 0.5f,data[i]));
        }
        LineDataSet lineDataSet = new LineDataSet(customCounts,"平均温度");
        lineDataSet.setAxisDependency(YAxis.AxisDependency.RIGHT);
        lineDataSet.setColor(Color.parseColor("#66A3AB"));
        lineDataSet.setCircleColor(Color.parseColor("#66A3AB"));
        lineDataSet.setCircleRadius(5);
        lineDataSet.setLineWidth(3);
        lineDataSet.setValueTextSize(12);
        lineDataSet.setValueTextColor(Color.parseColor("#66A3AB"));
        lineData.addDataSet(lineDataSet);
        return lineData;
    }
    /**
     * 设置柱状图绘制数据
     *
     * @return
     */
    public BarData getBarData() {
        BarData barData = new BarData();
        //蒸发量
        List<BarEntry> amounts = new ArrayList<>();
        float z[] = {2.0f, 4.9f, 7.0f, 23.2f, 25.6f, 76.7f, 135.6f, 162.2f, 32.6f, 20.0f, 6.4f, 3.3f};
        //降水量
        List<BarEntry> averages = new ArrayList<>();
        float j[] = {2.6f, 5.9f, 9.0f, 26.4f, 28.7f, 70.7f, 175.6f, 182.2f, 48.7f, 18.8f, 6.0f, 2.3f};
        //添加数据
        for (int i = 0; i < z.length; i++) {
            amounts.add(new BarEntry(i,z[i]));
            averages.add(new BarEntry(i,j[i]));
        }
        //设置总数的柱状图
        BarDataSet amountBar = new BarDataSet(amounts,"蒸发量");
        amountBar.setAxisDependency(YAxis.AxisDependency.LEFT);
        amountBar.setColor(Color.parseColor("#C23531"));
        //设置平均的柱状图
        BarDataSet averageBar = new BarDataSet(averages,"降水量");
        averageBar.setAxisDependency(YAxis.AxisDependency.LEFT);
        averageBar.setColor(Color.parseColor("#2F4554"));
        amountBar.setValueTextSize(10);
        averageBar.setValueTextSize(10);
        barData.addDataSet(amountBar);
        barData.addDataSet(averageBar);
        //设置柱状图显示的大小
        float groupSpace = 0.06f;
        float barSpace = 0.02f;
        float barWidth = 0.45f;
        barData.setBarWidth(barWidth);
        barData.groupBars(0, groupSpace, barSpace);
        return barData;
    }
}

扫码或长按识别访问