Search code examples
c#chartsconsole-applicationasp.net-charts

How to set chart title above y-axis?


I have been experimenting with charts and so far I got this experimental code:

    static void Main(string[] args)
    {
        Random rnd = new Random();

        Chart thisChart = new Chart();

        thisChart.Height = 400;
        thisChart.Width = 500;
        thisChart.BackColor = SystemColors.Window;
        thisChart.Palette = ChartColorPalette.EarthTones;
        thisChart.Titles.Add("Test");
        thisChart.Visible = true;

        ChartArea ca = new ChartArea();
        ca.Name = "Default";
        ca.BackColor = Color.White;
        ca.BorderColor = Color.FromArgb(26, 59, 105);
        ca.BorderWidth = 0;
        ca.BorderDashStyle = ChartDashStyle.Solid;
        ca.AxisX = new Axis();
        ca.AxisY = new Axis();
        thisChart.ChartAreas.Add(ca);

        Series series = thisChart.Series.Add("Default");
        series.ChartType = SeriesChartType.Spline;
        series.ChartArea = "Default";
        series.Points.AddXY("1", 20);
        series.Points.AddXY("2", 25);
        series.Points.AddXY("3", 30);
        series.Points.AddXY("4", 35);
        series.Points.AddXY("5", 40);
        series.Points.AddXY("6", 45);

        //SetPosition for multiple Y-axis labels
        thisChart.ChartAreas["Default"].Position = new ElementPosition(25, 10, 68, 85);
        thisChart.ChartAreas["Default"].InnerPlotPosition = new ElementPosition(10, 0, 90, 80);

        // Create extra Y axis for second and third series
        Series series2 = thisChart.Series.Add("Series2");
        series2.ChartType = SeriesChartType.Spline;
        series2.ChartArea = "Default";
        series2.Points.AddXY("1", 50);
        series2.Points.AddXY("2", 55);
        series2.Points.AddXY("3", 60);
        series2.Points.AddXY("4", 70);
        series2.Points.AddXY("5", 75);
        series2.Points.AddXY("6", 80);
        //series2.Legend = "Default";

        thisChart.Series["Series2"].ChartArea = "Default";
        CreateYAxis(thisChart, thisChart.ChartAreas["Default"], thisChart.Series["Series2"], 13, 8);

        // Create extra X axis for second and third series
        Series series3 = thisChart.Series.Add("Series3");
        series3.ChartType = SeriesChartType.Spline;
        series3.ChartArea = "Default";
        series3.Points.AddXY("1,5", 75);
        series3.Points.AddXY("2,5", 175);
        series3.Points.AddXY("3,5", 300);
        series3.Points.AddXY("4,5", 75);
        series3.Points.AddXY("5,5", 150);
        series3.Points.AddXY("6,6", 125);

        thisChart.Series["Series3"].ChartArea = "Default";
        CreateXAxis(thisChart, thisChart.ChartAreas["Default"], thisChart.Series["Series3"], -10, 8);

        //thisChart.DataBind();
        thisChart.SaveImage(@"C:\Temp\TestChart.png", ChartImageFormat.Png);

    }

    private static void CreateYAxis(Chart chart, ChartArea area, Series series, float axisOffset, float labelsSize)
    {
        // Create new chart area for original series
        ChartArea areaSeries = chart.ChartAreas.Add("ChartArea_" + series.Name);
        areaSeries.BackColor = Color.Transparent;
        areaSeries.BorderColor = Color.Transparent;
        areaSeries.Position.FromRectangleF(area.Position.ToRectangleF());
        areaSeries.InnerPlotPosition.FromRectangleF(area.InnerPlotPosition.ToRectangleF());
        areaSeries.AxisX.MajorGrid.Enabled = false;
        areaSeries.AxisX.MajorTickMark.Enabled = false;
        areaSeries.AxisX.LabelStyle.Enabled = false;
        areaSeries.AxisY.MajorGrid.Enabled = false;
        areaSeries.AxisY.MajorTickMark.Enabled = false;
        areaSeries.AxisY.LabelStyle.Enabled = false;
        areaSeries.AxisY.IsStartedFromZero = area.AxisY.IsStartedFromZero;
        areaSeries.AxisY.TitleAlignment = StringAlignment.Far;
        areaSeries.AxisY.TextOrientation = TextOrientation.Horizontal;
        areaSeries.AxisY.Title = "Y-axis Title1";
        areaSeries.AxisY.TitleForeColor = Color.Blue;
        areaSeries.AxisY.TitleFont = new Font("Tahoma", 7, FontStyle.Bold);
        areaSeries.AxisY.Maximum = 300;


        series.ChartArea = areaSeries.Name;

        // Create new chart area for axis
        ChartArea areaAxis = chart.ChartAreas.Add("AxisY_" + series.ChartArea);
        areaAxis.BackColor = Color.Transparent;
        areaAxis.BorderColor = Color.Transparent;
        areaAxis.Position.FromRectangleF(chart.ChartAreas[series.ChartArea].Position.ToRectangleF());
        areaAxis.InnerPlotPosition.FromRectangleF(chart.ChartAreas[series.ChartArea].InnerPlotPosition.ToRectangleF());
        areaAxis.AxisY.TitleAlignment = StringAlignment.Center;
        areaAxis.AxisY.Title = "Y-axis Title";
        areaAxis.AxisY.TitleForeColor = Color.Blue;
        areaAxis.AxisY.TitleFont = new Font("Tahoma", 7, FontStyle.Bold);
        areaAxis.AxisY.TitleAlignment = StringAlignment.Far;
        areaAxis.AxisY.TextOrientation = TextOrientation.Horizontal;
        areaAxis.AxisY.Maximum = 200;


        // Create a copy of specified series
        Series seriesCopy = chart.Series.Add(series.Name + "_Copy");
        seriesCopy.ChartType = series.ChartType;
        foreach (DataPoint point in series.Points)
        {
            seriesCopy.Points.AddXY(point.XValue, point.YValues[0]);
        }

        // Hide copied series
        seriesCopy.IsVisibleInLegend = false;
        seriesCopy.Color = Color.Transparent;
        seriesCopy.BorderColor = Color.Transparent;
        seriesCopy.ChartArea = areaAxis.Name;

        // Disable drid lines & tickmarks
        areaAxis.AxisX.LineWidth = 0;
        areaAxis.AxisX.MajorGrid.Enabled = false;
        areaAxis.AxisX.MajorTickMark.Enabled = false;
        areaAxis.AxisX.LabelStyle.Enabled = false;
        areaAxis.AxisY.MajorGrid.Enabled = false;
        areaAxis.AxisY.IsStartedFromZero = area.AxisY.IsStartedFromZero;
        areaAxis.AxisY.LabelStyle.Font = area.AxisY.LabelStyle.Font;

        // Adjust area position
        areaAxis.Position.X -= axisOffset;
        areaAxis.InnerPlotPosition.X += labelsSize;

    }

    private static void CreateXAxis(Chart chart, ChartArea area, Series series, float axisOffset, float labelsSize)
    {
        // Create new chart area for original series
        ChartArea areaSeries = chart.ChartAreas.Add("ChartArea_" + series.Name);
        areaSeries.BackColor = Color.Transparent;
        areaSeries.BorderColor = Color.Transparent;
        areaSeries.Position.FromRectangleF(area.Position.ToRectangleF());
        areaSeries.InnerPlotPosition.FromRectangleF(area.InnerPlotPosition.ToRectangleF());

        areaSeries.AxisY.MajorGrid.Enabled = false;
        areaSeries.AxisY.MajorTickMark.Enabled = false;
        areaSeries.AxisY.LabelStyle.Enabled = false;

        areaSeries.AxisX.MajorGrid.Enabled = false;
        areaSeries.AxisX.MajorTickMark.Enabled = false;
        areaSeries.AxisX.LabelStyle.Enabled = false;
        areaSeries.AxisX.IsStartedFromZero = area.AxisX.IsStartedFromZero;

        series.ChartArea = areaSeries.Name;

        // Create new chart area for axis
        ChartArea areaAxis = chart.ChartAreas.Add("AxisX_" + series.ChartArea);
        areaAxis.BackColor = Color.Transparent;
        areaAxis.BorderColor = Color.Transparent;
        areaAxis.Position.FromRectangleF(chart.ChartAreas[series.ChartArea].Position.ToRectangleF());
        areaAxis.InnerPlotPosition.FromRectangleF(chart.ChartAreas[series.ChartArea].InnerPlotPosition.ToRectangleF());



        // Create a copy of specified series
        Series seriesCopy = chart.Series.Add(series.Name + "_Copy");
        seriesCopy.ChartType = series.ChartType;
        foreach (DataPoint point in series.Points)
        {
            seriesCopy.Points.AddXY(point.XValue, point.YValues[0]);
        }

        // Hide copied series
        seriesCopy.IsVisibleInLegend = false;
        seriesCopy.Color = Color.Transparent;
        seriesCopy.BorderColor = Color.Transparent;
        seriesCopy.ChartArea = areaAxis.Name;

        // Disable drid lines & tickmarks
        areaAxis.AxisY.LineWidth = 0;
        areaAxis.AxisY.MajorGrid.Enabled = false;
        areaAxis.AxisY.MajorTickMark.Enabled = false;
        areaAxis.AxisY.LabelStyle.Enabled = false;

        areaAxis.AxisX.MajorGrid.Enabled = false;
        //areaAxis.AxisX.IntervalOffset = Convert.ToDouble("0,5");
        areaAxis.AxisX.IsStartedFromZero = area.AxisX.IsStartedFromZero;
        areaAxis.AxisX.LabelStyle.Font = area.AxisX.LabelStyle.Font;

        areaAxis.AxisX.CustomLabels.Add(0, 1, "0.5");
        areaAxis.AxisX.CustomLabels.Add(1, 2, "1.5");
        areaAxis.AxisX.CustomLabels.Add(2, 3, "2.5");
        areaAxis.AxisX.CustomLabels.Add(3, 4, "3.5");
        areaAxis.AxisX.CustomLabels.Add(4, 5, "4.5");
        areaAxis.AxisX.CustomLabels.Add(5, 6, "5.5");
        areaAxis.AxisX.CustomLabels.Add(6, 7, "6.5");

        // Adjust area position
        areaAxis.Position.Y -= axisOffset;
        areaAxis.InnerPlotPosition.Y += labelsSize;

    }

This produces the following result:

enter image description here

PROBLEM:

I can not figure out how to make it so that the title aligns itself above the respective y-axis, any ideas?


Solution

  • I don't think you do that.

    Afaik the recommended workaround is adding more chart Titles.

    You can style them as usual and to move them on top of a axis you can align them to the top left of the respective Chartearea.InnerPlotPosition:

    ChartArea ca1 = thisChart.ChartAreas[0];
    RectangleF rip1 = ca1.InnerPlotPosition.ToRectangleF();
    Title ty1 = thisChart.Titles.Add("ty1");
    ty1.Text = "Y-Axis 1\nTitle";
    ty1.ForeColor = Color.DarkSlateBlue;
    ty1.Position.X = rip1.Left;
    ty1.Position.Y = rip1.Y;
    

    Make sure to have enough space at the top of the chart for the titles..

    enter image description here

    Do note that the values of all ElementPositions, including InnerPlotPosition are in percent of the respective containers, i.e. of the ChartArea for the InnerPlotPosition and of the Chart for the ChartArea..