{"id":1424,"date":"2015-12-29T13:47:27","date_gmt":"2015-12-29T13:47:27","guid":{"rendered":"http:\/\/mindfusion.eu\/blog\/?p=1424"},"modified":"2021-01-20T17:11:31","modified_gmt":"2021-01-20T17:11:31","slug":"multiple-axis-line-chart-in-wpf","status":"publish","type":"post","link":"https:\/\/mindfusion.dev\/blog\/multiple-axis-line-chart-in-wpf\/","title":{"rendered":"Line Chart With Multiple Axes in WPF"},"content":{"rendered":"<p>A common scenario when building charts is the ability to render multiple series bound to multiple axes, each one with its own scale. To deal with this issue, MindFusion.Charting for WPF control has added support for multiple axes of all types &#8211; X, Y, Y2, X2 and in this post we&#8217;ll look how to add and customize them and how to create series bound to a given axis.<\/p>\n<p>The sample imitates a production chart, where three different scales measure three different values &#8211; work output, capital and energy consumption &#8211; all of which presumably participate in producing a single unit of a product. On the right side we have a single Y2 axis, which measures the amount of units produced. The X-axis displays the time scale. Let&#8217;s look at the chart elements, one by one.<\/p>\n<p><strong>I. The Y-Axes<\/strong><\/p>\n<p>The Y-axes, as all axes in the chart are an instance of the Axis class and are added to the appropriate collection property. The Axis class defines all types of useful properties needed to customize an axis. We define the three axes in XAML:<\/p>\n<pre id=\"line1\">&lt;<span class=\"start-tag\">chart:linechart.yaxes<\/span>&gt;\n<span id=\"line251\"><\/span>    &lt;<span class=\"start-tag\">chart:axescollection<\/span>&gt;\n<span id=\"line252\"><\/span>        &lt;<span class=\"start-tag\">chart:axis<\/span> <span class=\"attribute-name\">minvalue<\/span>=\"<a class=\"attribute-value\">0<\/a>\" <span class=\"attribute-name\">interval<\/span>=\"<a class=\"attribute-value\">5<\/a>\" <span class=\"attribute-name\">maxvalue<\/span>=\"<a class=\"attribute-value\">60<\/a>\" <span class=\"attribute-name\">labelformat<\/span>=\"<a class=\"attribute-value\">F0<\/a>\" <span class=\"attribute-name\">tick<\/span>=\"<a class=\"attribute-value\">3<\/a>\" <span class=\"attribute-name\">title<\/span>=\"<a class=\"attribute-value\">kWh\/day<\/a>\" <span class=\"attribute-name\">titlerotationangle<\/span>=\"<a class=\"attribute-value\">270<\/a>\" <span class=\"attribute-name\">labelstroke<\/span>=\"<a class=\"attribute-value\">Red<\/a>\" <span class=\"attribute-name\">titlestroke<\/span>=\"<a class=\"attribute-value\">Red<\/a>\"&gt;&lt;\/<span class=\"end-tag\">chart:axis<\/span>&gt;\n<span id=\"line253\"><\/span>        &lt;<span class=\"start-tag\">chart:axis<\/span> <span class=\"attribute-name\">minvalue<\/span>=\"<a class=\"attribute-value\">0<\/a>\" <span class=\"attribute-name\">interval<\/span>=\"<a class=\"attribute-value\">300<\/a>\" <span class=\"attribute-name\">maxvalue<\/span>=\"<a class=\"attribute-value\">2100<\/a>\" <span class=\"attribute-name\">title<\/span>=\"<a class=\"attribute-value\">Capital (USD)<\/a>\" <span class=\"attribute-name\">tick<\/span>=\"<a class=\"attribute-value\">3<\/a>\" <span class=\"attribute-name\">titlerotationangle<\/span>=\"<a class=\"attribute-value\">270<\/a>\" <span class=\"attribute-name\">labelstroke<\/span>=\"<a class=\"attribute-value\">Purple<\/a>\" <span class=\"attribute-name\">titlestroke<\/span>=\"<a class=\"attribute-value\">Purple<\/a>\"&gt;&lt;\/<span class=\"end-tag\">chart:axis<\/span>&gt;\n<span id=\"line254\"><\/span>        &lt;<span class=\"start-tag\">chart:axis<\/span> <span class=\"attribute-name\">minvalue<\/span>=\"<a class=\"attribute-value\">100<\/a>\" <span class=\"attribute-name\">interval<\/span>=\"<a class=\"attribute-value\">2.5<\/a>\" <span class=\"attribute-name\">maxvalue<\/span>=\"<a class=\"attribute-value\">130<\/a>\" <span class=\"attribute-name\">title<\/span>=\"<a class=\"attribute-value\">Work Productivity (%)<\/a>\" <span class=\"attribute-name\">customlabelposition<\/span>=\"<a class=\"attribute-value\">AutoScalePoints<\/a>\" <span class=\"attribute-name\">axiscrossingpoint<\/span>=\"<a class=\"attribute-value\">100.0<\/a>\" <span class=\"attribute-name\">labeltype<\/span>=\"<a class=\"attribute-value\">CustomText<\/a>\" <span class=\"attribute-name\">tick<\/span>=\"<a class=\"attribute-value\">3<\/a>\" <span class=\"attribute-name\">titlerotationangle<\/span>=\"<a class=\"attribute-value\">270<\/a>\" <span class=\"attribute-name\">labelstroke<\/span>=\"<a class=\"attribute-value\">Green<\/a>\" <span class=\"attribute-name\">titlestroke<\/span>=\"<a class=\"attribute-value\">Green<\/a>\"&gt;&lt;\/<span class=\"end-tag\">chart:axis<\/span>&gt;\n<span id=\"line255\"><\/span>    &lt;\/<span class=\"end-tag\">chart:axescollection<\/span>&gt;\n<span id=\"line256\"><\/span>&lt;\/<span class=\"end-tag\">chart:linechart.yaxes<\/span>&gt;<\/pre>\n<p>The property names easily describe what is set: the minimum and maximum values on each of the three axes, the title, the stroke for the labels and the title, the interval and the length of the axis ticks. Let&#8217;s note that the type of labels for the last Y-axis is &#8220;CustomText&#8221; &#8211; this means we will specify the labels explicitly rather than allow the control to generate them as with the other two axes &#8211; they don&#8217;t set a label type and the default value (the auto scale) is rendered.<\/p>\n<p>Here is how we define the labels:<\/p>\n<pre>double start = 100.0;\n\n    \/\/130 is the last number at the axis\n    while (start &lt;= 130)\n    {\n        string l = start.ToString(\"F1\") + \"%\";\n        chart.YAxes[2].Labels.Add(l);\n        start += 2.5;\n    }\n<\/pre>\n<p><strong>II. The Y2 Axis<\/strong><\/p>\n<p>The Y2-axis is just one and it is entirely declared in XAML:<\/p>\n<pre id=\"line1\">&lt;<span class=\"start-tag\">chart:linechart.y2axes<\/span>&gt;\n<span id=\"line274\"><\/span>    &lt;<span class=\"start-tag\">chart:axescollection<\/span>&gt;\n<span id=\"line275\"><\/span>        &lt;<span class=\"start-tag\">chart:axis<\/span> <span class=\"attribute-name\">minvalue<\/span>=\"<a class=\"attribute-value\">0<\/a>\" <span class=\"attribute-name\">interval<\/span>=\"<a class=\"attribute-value\">1000<\/a>\" <span class=\"attribute-name\">maxvalue<\/span>=\"<a class=\"attribute-value\">12000<\/a>\" <span class=\"attribute-name\">tick<\/span>=\"<a class=\"attribute-value\">3<\/a>\" <span class=\"attribute-name\">labelformat<\/span>=\"<a class=\"attribute-value\">F0<\/a>\" <span class=\"attribute-name\">titlerotationangle<\/span>=\"<a class=\"attribute-value\">270<\/a>\" <span class=\"attribute-name\">title<\/span>=\"<a class=\"attribute-value\">Units<\/a>\"&gt;&lt;\/<span class=\"end-tag\">chart:axis<\/span>&gt;\n<span id=\"line276\"><\/span>     &lt;\/<span class=\"end-tag\">chart:axescollection<\/span>&gt;\n<span id=\"line277\"><\/span>&lt;\/<span class=\"end-tag\">chart:linechart.y2axes<\/span>&gt;<\/pre>\n<p>The label format is set with the standard .NET numeric strings &#8211; in this case it is a floating number without trailing zeros. In this axis, as well in the other Y-axes you might have noticed that we use the TitleRotationAngle property. This property rotates the title label at an arbitrary angle between 0 and 360. In our case we want the label drawn vertically, to conserve space.<\/p>\n<p><strong>III. The Series<\/strong><\/p>\n<p>The series are created in code. They specify scatter type because we want each series to have markers at data points. The YAxis property specifies the Y-axis, which a given Series is bound to. Finally, we specify the tool tip type because we want to have a tool tip when the mouse hovers a data point.<\/p>\n<pre> LineSeries series0 = new LineSeries();\n series0.YAxis = chart.YAxes[0];\n series0.ScatterType = ScatterType.Square;\n series0.ScatterFills = new BrushCollection() { Brushes.Pink };\n series0.ScatterStrokes = new BrushCollection() { Brushes.Red };\n series0.Strokes = new BrushCollection() { Brushes.Red };\n series0.ToolTipType = ToolTipType.ChartData;\n<\/pre>\n<p>The data is random generated numbers. We use the Axis.XData and Axis.YData properties to set it.<\/p>\n<pre> for (int i = 0; i &lt; 30; i++)\n     {\n        series0.XData.Add(i * 6);\n        data1.Add(rand.NextDouble() * 60.0);     \n      }\n\n      data1.Sort();\n      series0.YData = new DoubleCollection(data1);\n      \/\/don't forget to add the series\n      chart.Series.Add(series0);\n<\/pre>\n<p>Last but not least &#8211; don&#8217;t forget to add the series to the Series collection property of the chart. With that our chart is ready &#8211; here is the result:<\/p>\n<div id=\"attachment_1427\" style=\"width: 788px\" class=\"wp-caption alignnone\"><a href=\"http:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2015\/12\/wpf_chart_production.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1427\" class=\"size-full wp-image-1427\" src=\"http:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2015\/12\/wpf_chart_production.png\" alt=\"Charting for WPF: Multiple Axes and Series\" width=\"778\" height=\"514\" srcset=\"https:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2015\/12\/wpf_chart_production.png 778w, https:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2015\/12\/wpf_chart_production-300x198.png 300w, https:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2015\/12\/wpf_chart_production-454x300.png 454w\" sizes=\"auto, (max-width: 778px) 100vw, 778px\" \/><\/a><p id=\"caption-attachment-1427\" class=\"wp-caption-text\">Charting for WPF: Multiple Axes and Series<\/p><\/div>\n<p>You can download the sample with the chart libraries from here:<\/p>\n<p align=\"center\"><a href=\"https:\/\/mindfusion.dev\/samples\/wpf\/charting\/ProductionChart.zip\">WPF Chart With Multiple Axes Sample Download<\/a><\/p>\n<p>If you have any questions regarding the chart component use the <a href=\"http:\/\/mindfusion.dev\/Forum\/YaBB.pl?board=wpfchart_disc\">forum,<\/a> <a href=\"mailto:support@mindfusion.dev?subject=MindFusion product inquiry&amp;body=Please, remember to add mindfusion.dev to your email whitelist. We usually reply to all contact inquiries within 3 to 4 hours. In case you have not received an answer in 24 hours, the email most likely has been filtered by an anti-spam software running at your mail server. Thank you for the understanding!\">email<\/a> or the <a href=\"http:\/\/www.mindfusion.dev\/HelpDesk\/index.php\">help desk<\/a> to contact MindFusion. More information about Charting for WPF, which includes a premium 3D charting library and a Real time charting library optimized to handle huge data sets <a href=\"http:\/\/mindfusion.dev\/wpfchart.html\">can be found here.<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A common scenario when building charts is the ability to render multiple series bound to multiple axes, each one with its own scale. To deal with this issue, MindFusion.Charting for WPF control has added support for multiple axes of all &hellip; <a href=\"https:\/\/mindfusion.dev\/blog\/multiple-axis-line-chart-in-wpf\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[61,74],"tags":[70,102,371,372,117,58],"class_list":["post-1424","post","type-post","status-publish","format-standard","hentry","category-charting-2","category-sample-code","tag-chart","tag-custom-labels","tag-multiple-axis","tag-multiple-series","tag-scatters","tag-wpf"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p3RlKs-mY","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts\/1424","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/comments?post=1424"}],"version-history":[{"count":7,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts\/1424\/revisions"}],"predecessor-version":[{"id":2575,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts\/1424\/revisions\/2575"}],"wp:attachment":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/media?parent=1424"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/categories?post=1424"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/tags?post=1424"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}