데이터

시리즈는 차트에 출력할 데이터값의 집합이다. 예를 들어 성적표를 그린다면 각 학생의 점수 데이터 집합이 하나의 시리즈가 된다. 데이터 집합은 SeriesPoints 컬렉션으로 관리한다.

 

DataPointCollection Points

 

DataPointCollectionDataPoint의 컬렉션이며 DataPoint는 시리즈를 구성하는 데이터 하나이다. 즉 차트를 구성하는 가장 원자적인 단위가 바로 DataPoint이다. 하나의 데이터는 다음 두 값으로 구성된다.

 

XValue : 가로 X축에 표시할 값이며 타입은 double이다. 성적표라면 학생의 출석 번호가 X값으로 사용된다. X값이 반드시 있어야 하는 것은 아니며 생략시 컬렉션에 추가한 순서대로 그려 연속적인(non scatter) 차트가 된다. X값을 지정하면 이 값에 따라 비 연속적인 흩어진(scatter) 차트가 된다.

YValues : 세로 Y축에 표시할 값이다. 성적표라면 각 학생의 점수값이다. 보통은 하나의 값만 있지만 여러 개의 값을 조합하여 보여 주는 차트는 Y값이 여러 개일 수도 있다. 예를 들어 주식 시황을 그리는 차트는 시가, 종가, 고가, 저가 등 4개의 값을 한꺼번에 그린다. 그래서 이 속성의 타입은 double []이다.

 

차트의 형태가 워낙 다양하다 보니 X값은 없을 수도 있고 Y값이 여러 개일 수도 있다. DataPointCollectionDataPoint를 추가하는 메서드를 제공한다. 디자이너에서도 데이터를 직접 추가할 수 있지만 대량 추가는 아무래도 코드를 사용해야 한다. 차트의 구조를 살펴 볼 수 있는 가장 원론적인 메서드이므로 자세히 살펴 보자. Y값만 추가할 때는 다음 두 메서드를 사용한다.

 

int AddY (double yValue);

int AddY (params object[] yValue);

 

첫 번째 메서드는 하나의 y값을 컬렉션의 마지막에 추가하고 그 첨자를 리턴한다. 성적을 순서대로 나열한다면 첫 학생의 성적부터 순서대로 죽 추가하면 된다.

 

private void Form1_Load(object sender, EventArgs e)

{

       chart1.Legends[0].Enabled = false;

       chart1.Series[0].Points.AddY(55);

       chart1.Series[0].Points.AddY(77);

       chart1.Series[0].Points.AddY(66);

}

 

당분간 범례는 필요없으므로 제거한 상태로 실행해 보자. 안그래도 지면이 좁은데 범례까지 있으면 차트를 크게 볼 수 없어 범례를 숨기기로 한다.

Y값만 주면 자동으로 1, 2, 3번 학생의 성적이 된다. object[]을 받는 AddY 메서드는 여러 개의 Y값을 받을 수도 있고 여러 타입의 값을 받을 수도 있다. 그렇다고 해서 아무 타입이나 다 받는 것은 아니며 정수, 실수 타입과 String, DateTime 정도만 가능하다. 점수값이 문자열 형태로 조사되었다면 그냥 문자열을 Add 해도 된다.

 

chart1.Series[0].Points.AddY("55");

chart1.Series[0].Points.AddY("77");

chart1.Series[0].Points.AddY("66");

 

이렇게 해도 결과는 같다. 문자열 안에 저장된 정수, 실수를 double 타입으로 바꿔서 사용한다. 일반적이지 않지만 DateTime 타입도 대소 구분이 가능하므로 Y값으로 쓸 수 있다.

 

chart1.Series[0].Points.AddY(DateTime.Now);

chart1.Series[0].Points.AddY(DateTime.Now.AddDays(1));

chart1.Series[0].Points.AddY(DateTime.Now.AddDays(2));

Y축에 날짜가 나타난다. 다음은 여러 개의 Y값을 가지는 차트를 그려 보자. 주식 차트에 주로 사용하는 캔들스틱이 대표적이다. 차트 타입을 먼저 바꿔야 하며 커스텀 프로피터를 사용하여 상승은 빨간색, 하락은 파란색으로 지정했다. X축 그리드는 없애는 것이 보기 좋다.

 

chart1.Series[0].ChartType = SeriesChartType.Candlestick;

chart1.Series[0].CustomProperties = "PriceDownColor=Blue, PriceUpColor=Red";

chart1.ChartAreas[0].AxisX.MajorGrid.Enabled = false;

chart1.Series[0].Points.AddY(900, 1600, 1000, 1500);

chart1.Series[0].Points.AddY(1000, 1700, 1200, 1600);

chart1.Series[0].Points.AddY(1200, 500, 1000, 600);

이런 차트를 그리려면 X축 하나에 대해 여러 개의 Y값이 필요하다. AddY 메서드는 X축값을 모두 생략한다. 다음 두 메서드는 X축을 지정하여 좀 더 다양한 형태의 차트를 그린다.

 

public int AddXY (double xValue, double yValue);

public int AddXY (object xValue, params object[] yValue);

 

하나의 y값을 받는 버전과 여러 개의 y값을 받는 버전이 있다. 1, 2,3 번 학생의 성적표를 그리고 싶다면 X값에 출석 번호를 적어 준다.

 

chart1.Series[0].Points.AddXY(1, 55);

chart1.Series[0].Points.AddXY(2, 77);

chart1.Series[0].Points.AddXY(3, 66);

 

이렇게 하면 X를 생략하고 세 개의 Y값을 순서대로 제공하는 것과 마찬가지이며 굳이 X값을 줄 필요가 없다. 그러나 X가 비연속적이거나 다른 타입일 때는 X값을 지정해야 한다. 예를 들어 3번 학생이 전학을 가서 없다고 하면 1, 2, 4번을 X값으로 지정한다.

 

 

chart1.Series[0].Points.AddXY(1, 55);

chart1.Series[0].Points.AddXY(2, 77);

chart1.Series[0].Points.AddXY(4, 66);

3번 자리는 빈 것으로 나타난다. 또 출석 번호가 아닌 각 학생의 이름으로 성적을 출력할 때도 X값을 지정한다.

 

chart1.Series[0].Points.AddXY("철수", 55);

chart1.Series[0].Points.AddXY("영희", 77);

chart1.Series[0].Points.AddXY("동수", 66);

학생 이름은 XValue에 저장되는 것이 아니라 DataPoint 객체의 AxisLabel 속성에 저장된다. XValue는 항상 숫자이다. X축에 시간을 표시할 때는 DateTime 타입을 사용한다. 다음 차트는 15분간의 값 변화를 표현한다.

 

Random R = new Random(100);

DateTime end = DateTime.Now.AddMinutes(15);

for (DateTime dt = DateTime.Now;dt < end;dt = dt.AddMinutes(1))

{

       chart1.Series[0].Points.AddXY(dt, R.Next(10, 100));

}

편의상 값은 난수로 생성했다. X축에는 시간이 표시되는데 날짜, 시간도 double 타입으로 변환되어 저장된다. 마지막 Add 메서드는 한 개 이상의 y값을 추가하고 DataPoint 객체를 리턴한다.

 

DataPoint Add (params double[] y);

 

다른 Add 메서드가 삽입한 위치를 리턴하는데 비해 이 메서드는 DataPoint 객체를 리턴한다는 점이 특이하다. 추가 후 리턴된 DataPoint 객체로 여러 가지 속성을 편집할 수 있다.

다음 메서드는 컬렉션의 데이터를 관리한다. 추가하는 기능이 있으면 당연히 삽입, 삭제, 검색, 초기화 등의 메서드도 필요하다. 컬렉션이 갖추어야 할 모든 기능이 다 구비되어 있다.

 

public void InsertY (int index, params object[] yValue);

public void RemoveAt (int index);

public void Clear ();

 

메서드 이름만 봐도 기능을 쉽게 유추할 수 있다. 편의상 여기서는 대표 원형만 보이는데 InsertY가 있으면 응당 InsertXYInsert도 있기 마련이다. 객체 지향 라이브러리는 필요할 거 같은 메서드는 거의 다 제공하므로 항상 레퍼런스를 참조하자. 다음 코드는 3개의 데이터를 추가한 후 1번 위치에 88을 삽입하고 2번 위치의 77 데이터를 제거한다.

 

chart1.Series[0].Points.AddY(55);

chart1.Series[0].Points.AddY(77);

chart1.Series[0].Points.AddY(66);

chart1.Series[0].Points.InsertY(1, 88);

chart1.Series[0].Points.RemoveAt(2);

하나를 넣고 하나를 뺐으니 결국 세 개 남는다. 데이터를 완전히 새로 입력하고 싶으면 Clear로 전부 제거한 후 다시 추가한다. 다음 메서드는 컬렉션에서 데이터를 찾는다.

 

DataPoint FindByValue (double valueToFind);

DataPoint FindByValue (double valueToFind, string useValue);

DataPoint FindByValue (double valueToFind, string useValue, int startIndex);

IEnumerable<DataPoint> FindAllByValue (double valueToFind);

DataPoint FindMinByValue ();

DataPoint FindMaxByValue ();

 

FindByValue는 최대 3개의 인수를 가진다. valueToFind는 찾을 값이다. useValue는 이 값이 X인지 Y1인지를 지정하며 생략시 Y값을 찾는다. startindex는 검색을 시작할 위치이되 생략시 처음부터 찾는다. 검색된 위치 다음부터 검색하면 순서대로 값을 찾을 수 있다.

모든 값을 한꺼번에 다 찾을 수도 있고 최소, 최대값을 찾을 수도 있다. 찾는 값이 있으면 해당 DataPoint 객체를 리턴하며 없으면 null을 리턴한다. 꼭 값이 있다고 보장할 수 없으므로 null 점검은 반드시 해야 한다. 다음 코드는 77점짜리 점수를 찾아 22점으로 수정한다.

 

chart1.Series[0].Points.AddY(55);

chart1.Series[0].Points.AddY(77);

chart1.Series[0].Points.AddY(66);

DataPoint dp = chart1.Series[0].Points.FindByValue(77);

if (dp != null)

{

    dp.YValues = new double[] { 22 };

}

Series의 속성이 Points 컬렉션은 데이터를 추가, 삭제, 삽입, 검색 등 모든 관리 기능을 다 지원한다. 원하는 모든 것을 다 할 수 있어 자유도가 높고 유연하다.