C#

045_ECG,PPG(Gragh Control)

iwannabebackendexpert 2022. 6. 9. 04:09

 

Chart를 조작할수있게 만들어보자

 

ECG는 정해진 시간에 심장의 전기적 활동을 해석하는 것이다. (심전도)

PPG는 맥파형은 피부표면 혈관의 미세혈관안의 혈류량의 변화상을 통해 혈관에 대한 임상 정보를 제공한다.

	double[] ecg = new double[100000];
        double[] ppg = new double[100000];
        private int ecgCount;
        private int ppgCount;
        Timer t = new Timer();

ecg / ppg 의 배열의 크기를 10만개 지정; 사실 데이터의 개수가 10만개 까지는 아님.

Timer를 통해 AutoScroll 조작예정

	    InitializeComponent();
            this.Text = "ECG/PPG";
            this.WindowState = FormWindowState.Maximized; //창 최대화

            EcgRead();
            PpgRead();
            ChartSetting();

            t.Interval = 10;  // 0.01초
            t.Tick += T_Tick;

생성자 함수 밑에 폼의 이름 지정. 그리고 창 최대화를 위해 세팅.

EcgRead() 함수,PpgRead()함수,ChartSetting()함수를 만들어두고 ALT+ENTER로 함수를 만들어준다.

timer의 interval은 0.01초로 지정.

 

private void PpgRead()
        {
            string fileName = "../../Data/ppg.txt";
            string[] lines = File.ReadAllLines(fileName);

            double min = double.MaxValue;
            double max = double.MinValue;

            int i = 0;
            foreach (var line in lines)
            {
                ppg[i] = double.Parse(line);
                if (min > ppg[i])
                    min = ppg[i];
                if (max < ppg[i])
                    max = ppg[i];
                i++;
            }
            ppgCount = i;
            string s = string.Format("PPG: count = {0}, min = {1}, max = {2}",
                ppgCount, min, max);
            MessageBox.Show(s);
        }
        
 private void EcgRead()
{
    string fileName = "../../Data/ecg.txt";
    string[] lines = File.ReadAllLines(fileName);

    double min = double.MaxValue;
    double max = double.MinValue;

    int i = 0;
    foreach (var line in lines)
    {
        ecg[i] = double.Parse(line) + 3; //+3 해서 그래프를 따로 보기위함
        if (min > ecg[i])
            min = ecg[i];
        if (max < ecg[i])
            max = ecg[i];
        i++;
    }
    ecgCount = i;
    string s = string.Format("ECG: count = {0}, min = {1}, max = {2}",
        ecgCount, min, max);
    MessageBox.Show(s);
}

데이터 셋을 프로젝트의 같은 파일안에 Data라는 파일을 만들어주고 txt파일을 넣어준다.

using IO; 필수.

그 파일의 값을 lines배열에 몽땅 넣어준다.

값을 찾기위해 min에는 maxvalue를, max에는 minvalue를 넣어 값을 탐색하게 한다.

값 하나하나를 탐색해 최대값과 최소값을 찾아낸다. 그리고 MessageBox를 통해 값을 출력

 

Ecg /Ppg 함수 둘다 동일.

private void ChartSetting()
        {
            c.ChartAreas[0].CursorX.IsUserEnabled = true; // 커서 사용가능
            c.ChartAreas[0].CursorX.IsUserSelectionEnabled = true; // zoom
            c.ChartAreas[0].BackColor = Color.Black;

            c.ChartAreas[0].AxisX.Minimum = 0;
            c.ChartAreas[0].AxisX.Maximum = ecgCount;
            c.ChartAreas[0].AxisX.Interval = 50; //50개의 데이터마다 새로운 눈금을 그림
            c.ChartAreas[0].AxisX.MajorGrid.LineColor = Color.Gray;
            c.ChartAreas[0].AxisX.MajorGrid.LineDashStyle = ChartDashStyle.Dash;

            c.ChartAreas[0].AxisY.Minimum = -2;
            c.ChartAreas[0].AxisY.Maximum = 6;
            c.ChartAreas[0].AxisY.Interval = 0.5;
            c.ChartAreas[0].AxisY.MajorGrid.LineColor = Color.Gray;
            c.ChartAreas[0].AxisY.MajorGrid.LineDashStyle = ChartDashStyle.Dash;

            c.Series.Clear();  // 시리즈를 다 지운다
            c.Series.Add("ECG");
            c.Series.Add("PPG");

            c.Series[0].ChartType = SeriesChartType.Line;
            c.Series[0].Color = Color.LightGreen;
            c.Series[0].BorderWidth = 2;
            c.Series[0].LegendText = "ECG";

            c.Series[1].ChartType = SeriesChartType.Line;
            c.Series[1].Color = Color.Orange;
            c.Series[1].BorderWidth = 2;
            c.Series[1].LegendText = "PPG";

            // 데이터를 시리즈에 넣는 작업
            foreach (var v in ecg)
            {
                c.Series["ECG"].Points.Add(v);
            }

            foreach (var v in ppg)
            {
                c.Series["PPG"].Points.Add(v);

            }
        }
	private int cursorX = 0;  // 차트에 표시되는 첫번째 데이터
        private bool scrolling = false;  // true이면 스크롤, false이면 정지
        private int dataCount = 50;  // 한 화면에 표시되는 데이터
        private int speed = 2;  // 데이터 표시 속도

주석참고하여 이해하도록하자.

 private void T_Tick(object sender, EventArgs e)
        {
            if (cursorX + dataCount <= ecgCount)
                c.ChartAreas[0].AxisX.ScaleView.Zoom(
                cursorX, cursorX + dataCount);
            else
                t.Stop();
            cursorX += speed;
        }

틱 함수. cursorX 의 값과 dataCount의 값이 ecgCount(최대값) 보다 작으면 줌 가능하게 지정

넘어가면 줌불가 및 멈춤.

 

  private void viewAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            t.Stop();
            c.ChartAreas[0].AxisX.ScaleView.Zoom(0, ecgCount);
            scrolling = false;

        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void autoScrollToolStripMenuItem_Click(object sender, EventArgs e)
        {
            t.Start();
            scrolling = true;
        }

ViewAll (전체보기) Zoom을 x값 0에서 최대값 까지 볼수있게 함.

bool scrollFlag = true;
        //차트를 클릭했을 때 처리 메소드
        private void c_Click(object sender, EventArgs e)
        {
            if (scrollFlag == true)
            {
                t.Stop();
                scrollFlag = false;
            }
            else
            {
                t.Start();
                scrollFlag = true;
            }
        }

차트를 클릭했을 때 차트를 멈추고, 진행하기를 실행하는 메소드입니다.

 private void c_SelectionRangeChanged(object sender, CursorEventArgs e)
        {
            int min = (int)(c.ChartAreas[0].AxisX.ScaleView.ViewMinimum); //선택한 값의 가장 왼쪽이 미니멈
            int max = (int)(c.ChartAreas[0].AxisX.ScaleView.ViewMaximum); 
            cursorX = min; 
            dataCount = max - min; //개수
        }

dataCount 를 지정해 한화면에 몇개의 dataCount를 볼지 정하는 메소드.

private void dataCountToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dataCount *= 2;
        }

        private void dataCountToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            dataCount /= 2;
        }

        private void speedToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            speed *= 2;
        }

        private void speedDownToolStripMenuItem_Click(object sender, EventArgs e)
        {
            speed /= 2;
        }

속도 및 dataCount을 곱하기 or  나누기로 정하는 메소드.

//클릭하는 곳의 데이터 값을 표시
        private void c_MouseClick(object sender, MouseEventArgs e)
        {
            HitTestResult htr = c.HitTest(e.X, e.Y);
            if (htr.ChartElementType == ChartElementType.DataPoint)
            {
                t.Stop();
                string s = string.Format(
                    "Count : {0}, ECG : {1}, PPG : {2}", htr.PointIndex,
                    c.Series["ECG"].Points[htr.PointIndex].YValues[0],
                    c.Series["PPG"].Points[htr.PointIndex].YValues[0]);
                MessageBox.Show(s);
            }
        }

가장 상단의 동영상 처럼 그래프를 클릭하면 값이 메세지 박스를 통해 출력된다.

HitTestResult형으로 HitPoint의 값을 찍어냄.(Point Index 이용)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace _045_EcgPpg
{
    public partial class Form1 : Form
    {
        double[] ecg = new double[100000];
        double[] ppg = new double[100000];
        private int ecgCount;
        private int ppgCount;
        Timer t = new Timer();
        public Form1()
        {
            InitializeComponent();
            this.Text = "ECG/PPG";
            this.WindowState = FormWindowState.Maximized; //창 최대화

            EcgRead();
            PpgRead();
            ChartSetting();

            t.Interval = 10;  // 0.01초
            t.Tick += T_Tick;
        }

        private void PpgRead()
        {
            string fileName = "../../Data/ppg.txt";
            string[] lines = File.ReadAllLines(fileName);

            double min = double.MaxValue;
            double max = double.MinValue;

            int i = 0;
            foreach (var line in lines)
            {
                ppg[i] = double.Parse(line);
                if (min > ppg[i])
                    min = ppg[i];
                if (max < ppg[i])
                    max = ppg[i];
                i++;
            }
            ppgCount = i;
            string s = string.Format("PPG: count = {0}, min = {1}, max = {2}",
                ppgCount, min, max);
            MessageBox.Show(s);
        }

        private void EcgRead()
        {
            string fileName = "../../Data/ecg.txt";
            string[] lines = File.ReadAllLines(fileName);

            double min = double.MaxValue;
            double max = double.MinValue;

            int i = 0;
            foreach (var line in lines)
            {
                ecg[i] = double.Parse(line) + 3; //+3 해서 그래프를 따로 보기위함
                if (min > ecg[i])
                    min = ecg[i];
                if (max < ecg[i])
                    max = ecg[i];
                i++;
            }
            ecgCount = i;
            string s = string.Format("ECG: count = {0}, min = {1}, max = {2}",
                ecgCount, min, max);
            MessageBox.Show(s);
        }

        private void ChartSetting()
        {
            c.ChartAreas[0].CursorX.IsUserEnabled = true; // 커서 사용가능
            c.ChartAreas[0].CursorX.IsUserSelectionEnabled = true; // zoom
            c.ChartAreas[0].BackColor = Color.Black;

            c.ChartAreas[0].AxisX.Minimum = 0;
            c.ChartAreas[0].AxisX.Maximum = ecgCount;
            c.ChartAreas[0].AxisX.Interval = 50; //50개의 데이터마다 새로운 눈금을 그림
            c.ChartAreas[0].AxisX.MajorGrid.LineColor = Color.Gray;
            c.ChartAreas[0].AxisX.MajorGrid.LineDashStyle = ChartDashStyle.Dash;

            c.ChartAreas[0].AxisY.Minimum = -2;
            c.ChartAreas[0].AxisY.Maximum = 6;
            c.ChartAreas[0].AxisY.Interval = 0.5;
            c.ChartAreas[0].AxisY.MajorGrid.LineColor = Color.Gray;
            c.ChartAreas[0].AxisY.MajorGrid.LineDashStyle = ChartDashStyle.Dash;

            c.Series.Clear();  // 시리즈를 다 지운다
            c.Series.Add("ECG");
            c.Series.Add("PPG");

            c.Series[0].ChartType = SeriesChartType.Line;
            c.Series[0].Color = Color.LightGreen;
            c.Series[0].BorderWidth = 2;
            c.Series[0].LegendText = "ECG";

            c.Series[1].ChartType = SeriesChartType.Line;
            c.Series[1].Color = Color.Orange;
            c.Series[1].BorderWidth = 2;
            c.Series[1].LegendText = "PPG";

            // 데이터를 시리즈에 넣는 작업
            foreach (var v in ecg)
            {
                c.Series["ECG"].Points.Add(v);
            }

            foreach (var v in ppg)
            {
                c.Series["PPG"].Points.Add(v);

            }
        }

        private int cursorX = 0;  // 차트에 표시되는 첫번째 데이터
        private bool scrolling = false;  // true이면 스크롤, false이면 정지
        private int dataCount = 50;  // 한 화면에 표시되는 데이터
        private int speed = 2;  // 데이터 표시 속도


        private void T_Tick(object sender, EventArgs e)
        {
            if (cursorX + dataCount <= ecgCount)
                c.ChartAreas[0].AxisX.ScaleView.Zoom(
                cursorX, cursorX + dataCount);
            else
                t.Stop();
            cursorX += speed;
        }




        private void viewAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            t.Stop();
            c.ChartAreas[0].AxisX.ScaleView.Zoom(0, ecgCount);
            scrolling = false;

        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void autoScrollToolStripMenuItem_Click(object sender, EventArgs e)
        {
            t.Start();
            scrolling = true;
        }


        bool scrollFlag = true;
        //차트를 클릭했을 때 처리 메소드
        private void c_Click(object sender, EventArgs e)
        {
            if (scrollFlag == true)
            {
                t.Stop();
                scrollFlag = false;
            }
            else
            {
                t.Start();
                scrollFlag = true;
            }
        }

        private void c_SelectionRangeChanged(object sender, CursorEventArgs e)
        {
            int min = (int)(c.ChartAreas[0].AxisX.ScaleView.ViewMinimum); //선택한 값의 가장 왼쪽이 미니멈
            int max = (int)(c.ChartAreas[0].AxisX.ScaleView.ViewMaximum); 
            cursorX = min; 
            dataCount = max - min; //개수
        }

        private void dataCountToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dataCount *= 2;
        }

        private void dataCountToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            dataCount /= 2;
        }

        private void speedToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            speed *= 2;
        }

        private void speedDownToolStripMenuItem_Click(object sender, EventArgs e)
        {
            speed /= 2;
        }


        //클릭하는 곳의 데이터 값을 표시
        private void c_MouseClick(object sender, MouseEventArgs e)
        {
            HitTestResult htr = c.HitTest(e.X, e.Y);
            if (htr.ChartElementType == ChartElementType.DataPoint)
            {
                t.Stop();
                string s = string.Format(
                    "Count : {0}, ECG : {1}, PPG : {2}", htr.PointIndex,
                    c.Series["ECG"].Points[htr.PointIndex].YValues[0],
                    c.Series["PPG"].Points[htr.PointIndex].YValues[0]);
                MessageBox.Show(s);
            }
        }
    }
}

전체 소스코드

'C#' 카테고리의 다른 글

047_Form_Clock_C#  (0) 2022.06.09
046_Matching Game(그림 맞추기 게임)_C#  (0) 2022.06.09
044_Graph  (0) 2022.06.09
043_TwoChart  (0) 2022.06.09
042_Chart  (0) 2022.06.09