따라 하기

소개

Chart는 닷넷으로 구현된 차트 컨트롤이며 흔히 MSChart라고 부른다. 정보를 축약해 보여 주어야 하는 사무용 프로그램에서 주로 많이 사용한다. 경쟁 제품으로는 InfragisticsUltraChartDevExpressDevExtream 차트 컨트롤이 있으며 디자인이 훨씬 예쁘지만 유료 제품이다.

Chart는 디자인이 소박한 편이지만 닷넷에 기본 포함되어 있는 컨트롤이어서 별도의 비용이 들지 않고 추가 설치도 필요 없어 간편하다. 비주얼 스튜디오만 설치하면 바로 쓸 수 있다. 이 강좌는 비주얼 스튜디오 2019 커뮤니티 버전을 사용한다.

다행인지 불행인지 컨트롤 자체는 10여전째 업그레이드가 없어 비주얼 스튜디오의 거의 모든 버전에서 사용할 수 있다. 그래픽 환경의 WinForm 프로젝트에 바로 활용할 수 있고 ASP.NET에서도 쓸 수 있어 웹도 지원한다. 여기서는 편의상 WinForm에서 주로 실습하되 ASP.NET에서 사용하는 방법도 별반 다르지 않다.

너무 오래된 컨트롤이다 보니 문서가 좀 부족한데 다음 주소에 간단한 자습서가 있다. 비주얼 스튜디오 2010의 문서이며 구글링을 통해서는 찾기 힘든 링크여서 주소를 일일이 치고 들어가는 수밖에 없다.

 

https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/dd489238(v=vs.100)

 

상단 메시지에 더 이상 관리하지는 않는 문서라고 되어 있다. 최신 버전에 자습서는 없지만 레퍼런스는 존재한다. Chart 컨트롤 이름으로 검색하면 어렵지 않게 찾을 수 있다.

 

https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.datavisualization.charting.chart?view=netframework-4.8

 

객체 지향 라이브러리는 레퍼런스가 필수이므로 즐겨 찾기해 두고 필요할 때마다 참고해야 한다. 친절하게 잘 만들어진 차트 샘플도 있다.

여러 가지 차트 샘플과 간략한 소스, 설명이 잘 정리되어 있다. 이렇게 잘 만든 샘플이 있지만 MS의 공식 사이트에서는 더 이상 찾을 수 없으며 개인 블로그를 뒤져야 겨우 저장된 사본을 찾을 수 있다. MS가 문서 하나는 끝내주게 잘 만들고 정리하는 편인데 Chart에 대한 지원은 좀 박한 편이다.

그래서 눈코뜰새없이 바쁜 시간을 쪼개 밤잠을 줄여 가며 이 강좌를 집필했다. 레퍼런스는 잘 정리되어 있으므로 모든 주제를 일일이 나열하기보다는 구조와 방법 위주로 컨트롤 활용법을 소개하기로 한다. 항상 프로젝트를 우선 수행해야 하는 개발자 신분이다 보니 문장을 잘 가드듬거나 그림을 예쁘게 그릴 시간이 충분치 않음을 양해 바란다.

디자이너로 실습하기

비주얼 스튜디오를 실행해 놓고 순서대로 따라하며 Chart 컨트롤을 사용해 보자. 따라하다 보면 전체적인 구조와 기능을 대부분 파악할 수 있다. 비주얼 스튜디오 2019를 실행한다. 파일/새로 만들기/프로젝트 항목을 선택하고 Windows Forms(.Net Framework) 템플릿을 선택한다.

프로젝트 이름은 chartTest로 지정한다. 이 프로젝트 하나로 모든 실습을 다 진행할 것이다. 여러분도 강좌만 보지 말고 반드시 코드를 같이 작성해 보자. 프로젝트가 생성되고 빈폼이 열린다. 도구 상자의 데이터 카테고리에서 Chart를 선택하여 폼에 배치하고 폼에 차도록 적당히 크기를 늘린다.

 

차트임을 표시하기 위해 폼에 샘플 차트가 표시되지만 아직 데이터가 없어 이대로 실행하면 아무 것도 나타나지 않는다. 속성창을 통해 데이터를 제공하고 여러 속성을 지정해야 한다. 속성을 찾기 쉽도록 알파벳순으로 정렬해 놓자.

차트 표면인 ChartArea1이 생성되어 있고 데이터의 집합인 Series1도 생성되어 있다. 그러나 아직 데이터는 없다. 속성창의 Series 옆의 ... 버튼을 클릭하여 시리즈 컬렉션 편집기를 연다. 시리즈 편집기에는 Series1이 이미 생성되어 있다. Points속성이 데이터 컬렉션이며 속성명 옆의 ... 버튼을 누르면 데이터 편집기가 열린다.

Series 컬렉션 안에 Points 컬렉션이 포함되어 있는 구조여서 속성 편집창이 중첩해서 열린다. 최초 DataPoint 컬렉션은 비어 있다. 추가 버튼을 누르면 DataPoint 객체 하나가 생성된다. 이 객체의 YValues55를 입력한다.

 

하나의 값이 생성되었다. 계속 추가 버튼을 누르고 66, 77, 70, 88을 입력한다. 총 다섯 개의 데이터가 시리즈에 추가되었다. 확인 버튼을 눌러 컬렉션 편집기를 닫는다. 이 상태에서 폼 디자인창을 보면 이미 다섯 개의 데이터가 막대 그래프로 표시된다. 실행하면 이 그래프가 그대로 나타난다.

Points 배열에 값을 더 많이 넣으면 더 많은 막대가 나타난다. 차트의 모양은 시리즈의 ChartType 속성으로 지정하는데 디폴트 타입은 막대 그래프인 Column이다. 속성 편집기에서 다른 타입으로 바꿔 보자.

다음은 BarLine 차트 타입으로 바꾼 모습이다. Chart 컨트롤은 35가지나 되는 차트 타입을 지원한다. 데이터의 구조에 따라 가능한 차트 타입이 제한된다. 연속적인 데이터는 Bar, Column, Line, StepLine, Spline, Point 정도의 타입을 주로 사용한다.

 

시리즈를 하나 더 추가해 보자. 동시에 두 개의 차트를 같이 보여줄 수 있다. 시리즈 컬렉션 편집기를 열어 Series2를 추가하고 Points 컬렉션에 33, 44, 22, 40, 50 다섯 개의 값을 입력해 넣는다.

 

Series1Line 차트 타입으로 두고 Series2Column 타입으로 두면 두 가지 타입의 차트가 같이 표시된다. 둘 다 Column으로 하면 막대가 나란히 표시된다. 같이 표시할 수 있는 타입이 있고 그렇지 않은 타입이 있다. 예를 들어 ColumnBar는 방향이 달라 같은 표면에 표시할 수 없다.

 

다음은 Area를 하나 더 추가해 보자. Area는 시리즈를 그리는 영역이며 기본적으로 하나 주어지지만 필요한만큼 만들 수 있다. ChartAreas 속성의 ... 을 클릭하면 에리어 편집기가 열리며 ChartArea1이 미리 생성되어 있다. 추가 버튼을 눌러 ChartArea2를 하나 더 만든다.

에리어를 추가하면 차트 높이가 절반으로 줄어든다. 아직 보이지는 않지만 아래쪽에 에리어가 하나 더 생긴 것이다.

새로 생긴 에리어에는 시리즈가 배치되어 있지 않아 현재는 비어 있다. 시리즈 편집기를 열고 Series2의 속성창에서 ChartAreaChartArea2로 지정하고 ChartTypeBar로 변경해 보자.

출력 표면을 분리하면 각 에리어에 다른 타입의 차트를 각각 배치할 수 있다. 위쪽 에리어에는 Column 시리즈를 표시하고 아래쪽 에리어에는 Bar 시리즈를 표시했다.

이런 식으로 에리어와 시리즈를 조합하여 다양한 형태의 차트를 그린다. 여러 정보를 한꺼번에 표시할 수도 있고 타입이 다른 정보는 에리어를 분리하여 보여줄 수도 있다.

범례는 도표의 각 시리즈를 설명하는 표식이다. 오른쪽 위에 파란색이 Series1이고 노란색이 Series2라고 되어 있어 전혀 설명적이지 않다. 시리즈를 그냥 추가만 했을 뿐이라 디폴트 이름이 붙어 있다. 시리즈 편집기를 열어 Series1LegendText"성적표", Sereis2LegendText"매출"로 변경해 보자.

범례도 필요한만큼 생성할 수 있으며 어떤 범례에 어떤 표식으로 시리즈를 설명한 것인지 지정한다. 디폴트로 하나의 범례가 미리 생성되어 있다. 차트를 선택하고 속성창에서 Legends...을 눌러 컬렉션 편집기를 열고 Legend1의 속성을 다음과 같이 편집한다.

 

Docking : Left 차트의 왼쪽에 배치한다.

BackColor : Yellow

Title : "시리즈 설명"

 

범례가 왼쪽으로 이동하며 배경색이 바뀌고 위쪽에 제목이 표시된다.

이 외에 Enabled로 범례 표시 여부, LegendStyle로 범례의 나열 방향, 각종 색상과 모양을 조정할 수 있다. 두 개 이상의 범례를 만들어 각 시리즈를 그룹으로 나누어 설명할 수도 있다.

다음은 차트에 타이틀을 붙여 보자. 차트를 선택해 놓고 Titles 속성의 ... 버튼을 눌러 컬렉션 편집기를 연다. 디폴트로 비어 있는데 타이틀도 여러 개 지정할 수 있다. 하나 추가한 후 Text"차트 타이틀"로 지정하고 폰트는 궁서 20 pt로 지정한다.

차트 위쪽에 타이틀이 표시된다. 타이틀을 계속 추가하여 여러 줄로 표시할 수도 있고 각 변에 타이틀을 붙일 수도 있다.

애노테이션(Annotation)은 도표의 각 부분에 붙이는 보충적인 설명이다. 여러 개를 붙일 수 있어 이 역시 컬렉션이다. 차트의 Annotations 속성에서 ... 버튼을 눌러 컬렉션 편집기를 연다. 최초 비어 있는데 아래쪽의 추가 버튼 콤보 박스를 열면 애노테이션 목록이 나타난다.

EllipseAnnotation을 선택하면 왼쪽 위에 타원형이 하나 나타난다. Text 속성은 "여기 주목"으로 변경하고 BackColor를 눈에 띄는 Lime색으로 지정한다. 이 애노테이션을 어디다 놓을 것인가는 AnchorDataPoint 속성으로 지정하는데 Series1DataPoint1로 지정한다.

이렇게 하면 시리즈11번 막대 위에 애노테이션이 나타난다. 너무 바짝 붙어 있는데 AnchorOffsetY 속성을 2로 지정하여 적당히 띄운다.

여기까지 디자인창에서 차트의 속성을 바꿔 가며 여러 가지 실습을 해 보았다. 이 실습을 통해 차트로 어떤 작업이 가능한지 알 수 있으며 대충의 구조도 눈치챌 수 있다. 한두 번 더 실습을 반복해 보자.

코드로 만들기

디자인 타임에 속성만 조정해도 차트를 원하는 형식으로 만들 수 있다. 비주얼 스튜디오의 지원이 훌륭해 속성을 이것 저것 바꿔 보며 재미있게 공부할 수 있다. 그러나 마우스를 통한 편집은 재현이 어렵고 단계가 복잡해 한계가 있다.

차트에 출력할 데이터를 런타임에 제대로 구할 수 있기 때문에 결국은 코드로 프로그래밍해야 한다. 앞에서 디자인 타임에 만든 차트 컨트롤을 삭제하여 원래대로 리셋한다.

빈 폼에 차트 컨트롤을 새로 하나 배치한다. 폼 크기는 500 * 350으로 작게 설정하고 차트의 Dock 속성을 Fill로 지정하여 폼을 가득 채운다. 캡처를 작게 잡아도 차트를 크게 보이도록 하기 위해서인데 실습할 때는 아무렇게나 해도 상관 없다.

이 상태로 실행하면 차트는 그냥 하얀 영역으로 표시될 뿐이다. 차트에 데이터를 제공하고 속성을 편집하는 코드가 필요하다. 폼의 빈 영역을 더블클릭하여 Form1_Load 이벤트 핸들러를 작성하고 여기에 다음 코드를 작성한다.

 

private void Form1_Load(object sender, EventArgs e)

{

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

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

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

       chart1.Series[0].Points.Add(70);

       chart1.Series[0].Points.Add(80);

}

 

시리즈 하나는 기본적으로 생성되어 있으므로 0번 시리즈에 데이터만 제공하면 된다. Points 컬렉션의 Add 메서드로 값을 넣어 주면 이 값이 차트에 나타난다. 실행해 보자.

두번째 이후의 시리즈는 직접 생성해야 한다. Series 컬렉션의 Add 메서드로 추가하되 이후의 참조를 위해 이름을 주는 것이 좋다. 데이터는 Points.Add로 계속 추가할 수 있지만 DataBind 메서드를 사용하면 배열을 한꺼번에 등록할 수 있다. 다음 코드를 더 작성해 보자.

 

chart1.Series.Add("Series2");

chart1.Series[1].Points.DataBindY(new int[] { 33, 44, 22, 40, 50 });

 

속성창에서는 일일이 값을 입력해야 하지만 코드를 사용하면 배열이나 컬렉션을 통째로 등록할 수 있어 편리하다. 두 개의 차트가 나란히 나타난다.

다음은 에리어를 하나 더 추가하고 Sereis2를 아래쪽으로 옮긴 후 Bar 타입으로 바꾸어 보자. 다음 코드 세 줄이면 된다.

 

chart1.ChartAreas.Add("ChartArea2");

chart1.Series["Series2"].ChartArea = "ChartArea2";

chart1.Series["Series2"].ChartType = SeriesChartType.Bar;

 

ChartAreas 컬렉션의 Add 메서드로 ChartArea2 에리어를 추가했다. 여기까지만 하면 아래쪽에 빈 에리어만 생성된다. Series2를 아래쪽 에리어로 이동시켜 보자. 시리즈의 ChartArea 속성에 원하는 에리어의 이름을 대입한다.

이런 용도로 쓰기 위해 모든 객체에 이름을 붙여 두는 것이 좋다. 시리즈도 Series 컬렉션에서 0, 1번 순서값으로 참조할 수 있지만 이름을 붙여 두면 이름으로 검색할 수 있다. 위 두 번째 줄은 다음 코드와 같다.

 

chart1.Series[1].ChartArea = "ChartArea2";

 

Sereis[1]이 두 번째 컬렉션을 의미한다. 그러나 시리즈가 많아지면 순서값은 헷갈리고 중간에 첨삭되면 바뀔 수도 있어 일관성이 떨어진다. 그래서 이름을 붙여 두고 Series["Series2"] 형식으로 이름을 통해 찾는 것이 더 좋다.

세번째 줄은 시리즈의 차트 타입을 Bar로 변경한다. SeriesChartType을 찾을 수 없다는 에러가 발생하면 다음 using문을 소스 선두에 작성한다.

 

using System.Windows.Forms.DataVisualization.Charting;

 

차트와 관련된 웬만한 타입이 다 Charting 네임스페이스에 선언되어 있어 이 using문만 추가하면 차트 관련 타입을 자유롭게 쓸 수 있다. 여기까지의 실행 결과는 다음과 같다.

다음은 범례를 조정해 보자. 시리즈에 범례 텍스트를 지정하고 Legends 컬렉션의 0번 범례의 속성을 조정하면 된다.

 

chart1.Series["Series1"].LegendText = "성적표";

chart1.Series["Series2"].LegendText = "매출";

chart1.Legends[0].Docking = Docking.Left;

chart1.Legends[0].BackColor = Color.Yellow;

chart1.Legends[0].Title = "시리즈 설명";

 

디자인창에서 속성을 찾아 변경하는 동작을 코드로 그대로 옮긴 것 뿐이다. 왼쪽에 노란색 범례가 나타난다.

다음은 타이틀을 붙여 보자. 타이틀은 Titles 컬렉션에 생성한다. 새 타이틀 객체 추가하고 텍스트와 폰트만 지정하면 된다.

 

chart1.Titles.Add("Title1");

chart1.Titles["Title1"].Text = "차트 타이틀";

chart1.Titles["Title1"].Font = new Font("궁서", 20);

 

위쪽에 차트 제목이 출력된다.

보다시피 차트의 모든 세부 요소는 컬렉션으로 되어 있고 원하는 것을 추가한 후 속성만 편집하면 된다. C#의 기본 문법만 안다면 아주 쉬운 코드이다. 그러나 구조가 복잡해지고 중첩이 심해지면 약간씩 헷갈리는 면도 있다.

마지막으로 애노테이션을 추가해 보자. 애노테이션은 Annotations 컬렉션에 저장하되 파생 타입이 있다는 면에서 조금 복잡하다. 원하는 타입의 애노테이션 객체를 생성하여 속성을 편집한 후 컬렉션에 추가한다.

 

EllipseAnnotation ell = new EllipseAnnotation();

ell.Text = "여기주목";

ell.BackColor = Color.Lime;

ell.AnchorOffsetY = 2;

ell.AnchorDataPoint = chart1.Series["Series1"].Points[0];

chart1.Annotations.Add(ell);

 

타원 애노테이션인 EllipseAnnotation 객체를 생성하고 이 객체의 Text, BackColor. AnchorOffsetY 속성을 지정한다. 애노테이션을 붙일 위치인 AnchorDataPoint 속성은 시리즈내의 포인트값을 지정한다는 면에서 조금 까다롭다. Series1Points 컬렉션에서 0번 포인터를 찾아 대입하면 된다. 이렇게 만든 타원 애노테이션 객체를 Annotations 컬렉션에 추가한다.

이상으로 디자인 타임에 만들었던 예제와 똑같은 예제를 코드로 만들어 보았다. 과정이 긴 거 같지만 코드줄 수는 얼마 되지 않는다.

 

private void Form1_Load(object sender, EventArgs e)

{

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

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

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

       chart1.Series[0].Points.Add(70);

       chart1.Series[0].Points.Add(80);

 

       chart1.Series.Add("Series2");

       chart1.Series[1].Points.DataBindY(new int[] { 33, 44, 22, 40, 50 });

 

       chart1.ChartAreas.Add("ChartArea2");

       chart1.Series["Series2"].ChartArea = "ChartArea2";

       chart1.Series["Series2"].ChartType = SeriesChartType.Bar;

 

       chart1.Series["Series1"].LegendText = "성적표";

       chart1.Series["Series2"].LegendText = "매출";

       chart1.Legends[0].Docking = Docking.Left;

       chart1.Legends[0].BackColor = Color.Yellow;

       chart1.Legends[0].Title = "시리즈 설명";

 

       chart1.Titles.Add("Title1");

       chart1.Titles["Title1"].Text = "차트 타이틀";

       chart1.Titles["Title1"].Font = new Font("궁서", 20);

 

       EllipseAnnotation ell = new EllipseAnnotation();

       ell.Text = "여기주목";

       ell.BackColor = Color.Lime;

       ell.AnchorOffsetY = 2;

       ell.AnchorDataPoint = chart1.Series["Series1"].Points[0];

       chart1.Annotations.Add(ell);

}

 

이런 차트가 필요하다면 이 코드를 그대로 가져가 편집하면 된다. 코드는 복사 및 반복이 쉽다는 면에서 역시 우월하고 실용적이다.