1

Тема: Побудова графіка з використанням DataGrigView та Chart

Всім привіт!
Потрібна ваша допомога, щоб коректно побудувати за допомогою Chart та DataGridView графік такої функції:
(Exp(1 / (1 - x^2))) / (1 + x^2)

Як бачите в точках х=+-1 будуть асимптоти.
Але в мене виходить не зовсім те, що має бути (дивіться нижче в коментарях на очікуваний результат і мій наявний)

Ось мій код

namespace WindowsFormsApp_lab3
{
    public partial class Form1 : Form
    {
        bool pointFocusEnabled = false;
        private double startX, endX, maxY, minY, step, startY, endY;
        private int tabulateDotsQuantity;

        public Form1()
        {
            InitializeComponent();
            buttonChartConstruction.Enabled = false;
        }

        private double f(double x)
        {
            return ((Math.Exp(1 / (1 - Math.Pow(x, 2)))) / (1 + Math.Pow(x, 2)));
        }

        private bool parseData()
        {
            //check input data
            if (textBoxX1.Text == "" ||
                textBoxX2.Text == "" ||
                textBoxNumbOfPoint.Text == "")
            {
                MessageBox.Show("Enter all data!",
                               "Critical Warning",
                               MessageBoxButtons.OK,
                               MessageBoxIcon.Warning);
                return false;
            }

            //get data from textBoxes
            startX = Double.Parse(textBoxX1.Text.Replace(".", ","));
            endX = Double.Parse(textBoxX2.Text.Replace(".", ","));
            tabulateDotsQuantity = Int32.Parse(textBoxNumbOfPoint.Text);
            step = (endX - startX) / tabulateDotsQuantity;

            return true;
        }

        private void setChart()
        {
            chart.ChartAreas.Clear();
            chart.Series.Clear();
            chart.Legends.Clear();
            chart.Titles.Clear();

            chart.Series.Add("Main");//set series to visualize graphic line
            chart.Series["Main"].Color = Color.Blue;
            chart.Series.Add("Points");//set series to visualize selected points
            chart.Series["Points"].Color = Color.Red;

            chart.Series["Main"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
            chart.Series["Main"].XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
            chart.Series["Main"].YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;

            chart.Series["Points"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Point;
            chart.Series["Points"].XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
            chart.Series["Points"].YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;

            chart.ChartAreas.Add("Main");
            //set title
            chart.Titles.Add("MainTitle");
            chart.Titles[0].Text = "y = (Math.Exp(1 / (1 - Math.Pow(x, 2)))) / (1 + Math.Pow(x, 2))";
            chart.Titles[0].Alignment = ContentAlignment.TopLeft;
            chart.Titles[0].Visible = false;

            //set up chart area
            chart.ChartAreas["Main"].AxisX.Minimum = startX;
            chart.ChartAreas["Main"].AxisX.Interval = 1;
            chart.ChartAreas["Main"].AxisX.Maximum = endX;
            chart.ChartAreas["Main"].AxisX.ArrowStyle = System.Windows.Forms.DataVisualization.Charting.AxisArrowStyle.SharpTriangle;
            chart.ChartAreas["Main"].AxisX.Name = "X";
            chart.ChartAreas["Main"].AxisX.Title = "X";

            chart.ChartAreas["Main"].AxisY.ArrowStyle = System.Windows.Forms.DataVisualization.Charting.AxisArrowStyle.SharpTriangle;
            chart.ChartAreas["Main"].AxisY.Name = "Y";
            chart.ChartAreas["Main"].AxisY.Title = "Y";

            if (textBoxY1.Text == "" && !(textBoxY2.Text == "")) //для масштабирования относительно y
            {
                endY = Double.Parse(textBoxY2.Text.Replace(".", ","));
                chart.ChartAreas["Main"].AxisY.Minimum = minY;
                chart.ChartAreas["Main"].AxisY.Maximum = endY;
            }
            else if (!(textBoxY1.Text == "") && (textBoxY2.Text == ""))
            {
                startY = Double.Parse(textBoxY1.Text.Replace(".", ","));
                chart.ChartAreas["Main"].AxisY.Minimum = startY;
                chart.ChartAreas["Main"].AxisY.Maximum = maxY;
            }
            else if (!(textBoxY1.Text == "") && !(textBoxY2.Text == ""))
            {
                startY = Double.Parse(textBoxY1.Text.Replace(".", ","));
                endY = Double.Parse(textBoxY2.Text.Replace(".", ","));
                chart.ChartAreas["Main"].AxisY.Minimum = startY;
                chart.ChartAreas["Main"].AxisY.Maximum = endY;
            }

            else if ((textBoxY1.Text == "") && (textBoxY2.Text == ""))
            {
                chart.ChartAreas["Main"].AxisY.Minimum = minY;
                chart.ChartAreas["Main"].AxisY.Maximum = maxY;
            }
        
            //set the position of axes
            chart.ChartAreas["Main"].AxisX.Crossing = 0;
            chart.ChartAreas["Main"].AxisY.Crossing = 0;
        }

        private void dataGridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            //update row indexes after sorting
            foreach (DataGridViewRow row in dataGridView.Rows)
            {
                row.Cells["Number"].Value = row.Index;
            }
        }


        private void textBoxes_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == ',')
            {
                e.KeyChar = '.';
            }

            if ((sender as TextBox) == textBoxNumbOfPoint)
            {
                //verify that input text is only numeric and positive integer and not show other
                if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar))
                {
                    e.Handled = true;
                }
            }
            else
                //Verify that the pressed key is Ctrl or digits or dot or minus and not show others
                if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && (e.KeyChar != '.') && (e.KeyChar != '-'))
            {
                e.Handled = true;
            }
        }

        private void buttonSubmit_Click(object sender, EventArgs e) //табулирования финкции
        {
            if (!parseData())
                return;
            if(!ambit_checkX())
                {
                MessageBox.Show("Error! Enter correct data for X!",
                                       "Critical Warning",
                                       MessageBoxButtons.OK,
                                       MessageBoxIcon.Warning);
                textBoxX2.Text = "";
                textBoxX1.Text = "";
                textBoxX1.Focus();
                return;
            }
             
            dataGridView.Rows.Clear();
            double x, y;

            for (int i = 0; i <= tabulateDotsQuantity; i++)
            {
                x = Math.Round(startX + step * i, 4);
                y = Math.Round(f(startX + step * i), 4);

                if (y > maxY)
                    maxY = y;
                else if (y < minY)
                    minY = y;

                dataGridView.Rows.Add(i, x, y);//add row with tabulated values in dataGridView table
            }
            //set values in min-max textBoxes
            textBoxFmax.Text = maxY.ToString();
            textBoxFmin.Text = minY.ToString();
            setChart();

            //enable appropriate buttons
            buttonChartConstruction.Enabled = true;
        }

        private bool ambit_checkX() //check x1 <= x2
        {
            if (Double.TryParse(textBoxX1.Text, out startX) && Double.TryParse(textBoxX2.Text, out endX))
            {
                double x1, x2;
                x1 = double.Parse(textBoxX1.Text);
                x2 = double.Parse(textBoxX2.Text);
                if (x1 >= x2)
                { return false; }
            }
            return true;
}


        private void buttonLoadChart_Click(object sender, EventArgs e) 
        {
            if (dataGridView.Rows.Count == 1)
            {
                MessageBox.Show("Please, enter data!",
                               "Critical Warning",
                               MessageBoxButtons.OK,
                               MessageBoxIcon.Warning);
                return;
            }

            chart.Series["Main"].Points.Clear();
            chart.Titles[0].Visible = true;

            if (dataGridView.SelectedRows.Count == 0)
            {
                //visualize all data rows
                for (int i = 0; i < dataGridView.RowCount - 1; i++)
                {
                    chart.Series["Main"].Points.AddXY(dataGridView[1, i].Value, dataGridView[2, i].Value);
                }

            }
            else
            {
                //visualize only selected data rows
                int i;
                for (int j = 0; j < dataGridView.SelectedRows.Count; j++)
                {
                    i = dataGridView.Rows.IndexOf(dataGridView.SelectedRows[j]);
                    chart.Series["Main"].Points.AddXY(dataGridView[1, i].Value, dataGridView[2, i].Value);
                }
            }
            pointFocusEnabled = true;
        }

        private void textBoxDotsQuantity_Leave(object sender, EventArgs e)
        {
            //check quantity of dots to tabulate
            if (textBoxNumbOfPoint.Text == "")
                return;
            int dots = Int32.Parse(textBoxNumbOfPoint.Text);
            if (dots <= 1)
            {
                MessageBox.Show("Enter more than 2 point for the tab!",
                               "Critical Warning",
                               MessageBoxButtons.OK,
                               MessageBoxIcon.Warning);
                textBoxNumbOfPoint.Text = "";
                textBoxNumbOfPoint.Focus();
            }

        }

        private void dataGridView_RowHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (pointFocusEnabled == false)
                return;

            chart.Series["Points"].Points.Clear();

            //add selected dots from selected rows to visualize on chart
            int i;
            for (int j = 0; j < dataGridView.SelectedRows.Count; j++)
            {
                i = dataGridView.Rows.IndexOf(dataGridView.SelectedRows[j]);
                chart.Series["Points"].Points.AddXY(dataGridView[1, i].Value, dataGridView[2, i].Value);
            }
            chart.Update();
        }

        private void dataGridView_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            chart.Series["Points"].Points.Clear();
            chart.Update();
        }


        private void textBoxStartY_Leave(object sender, EventArgs e)
        {
            if (textBoxX1.Text == "" || textBoxX2.Text == "")
                return;

            //check ranges of interval
            double startY, endY;
            startY = Double.Parse(textBoxY1.Text);
            endY = Double.Parse(textBoxY2.Text);

            if (startY >= endY)
            {
                MessageBox.Show("Error! Enter correct data for Y",
                               "Critical Warning",
                               MessageBoxButtons.OK,
                               MessageBoxIcon.Warning);
                textBoxY1.Text = "";
                textBoxY2.Text = "";
                textBoxY1.Focus();
            }
        }
    }
}

Я пробувала будувати три різних графіки на інтервалах (-infinity; -1), (-1; 1), (1; infinity), але всеодно не виходило коректно реалізувати завдання.
Допоможіть, будь ласка, вирішити дану проблему)

2 Востаннє редагувалося maryX (09.05.2019 15:08:10)

Re: Побудова графіка з використанням DataGrigView та Chart

Очікуваний графік функції
https://replace.org.ua/misc.php?action=pun_attachment&amp;item=1976

Post's attachments

photo5377310093114190487.png 49.45 kb, 113 downloads since 2019-05-09 

3 Востаннє редагувалося maryX (09.05.2019 15:12:19)

Re: Побудова графіка з використанням DataGrigView та Chart

Результат роботи моєї програми
https://replace.org.ua/misc.php?action=pun_attachment&amp;item=1977

Post's attachments

photo5377310093114190474.jpg 55.68 kb, 64 downloads since 2019-05-09 

4

Re: Побудова графіка з використанням DataGrigView та Chart

Проблема в тому, що з точки зору Chart тут не один, а три різні графіки - якраз тому, що є дві точки розриву. Просто пофарбуйте їх в один колір і стежте, щоб x ніде не було ±1. Приблизно так:

x = Math.Round(startX + step * i, 4);
if(x<-1){
                y = Math.Round(f(startX + step * i), 4);
                додати_в_графік_1
} else if (x<1) {
                y = Math.Round(f(startX + step * i), 4);
                додати_в_графік_2
} else if(x>1) {
                y = Math.Round(f(startX + step * i), 4);
                додати_в_графік_3
}

Звертаю увагу, що у всіх гілках є перевірка, тому якщо x буде -1 чи 1, значення просто не буде обчислене.

5 Востаннє редагувалося maryX (09.05.2019 17:51:48)

Re: Побудова графіка з використанням DataGrigView та Chart

Ще таке, можливо, тупе питання, тоді мені знадобиться 3 елементи DataGridView, оскільки графіків буде 3, правильно?

6

Re: Побудова графіка з використанням DataGrigView та Chart

Я не знаю, як воно в шарпі працює, але за логікою мають бути додаткові Series

7 Востаннє редагувалося maryX (09.05.2019 22:31:44)

Re: Побудова графіка з використанням DataGrigView та Chart

Можливо хтось може допомогти з побудовою цих графіків при заданих умовах (див. коментар вище), саме на одному Chart?, бо всі мої старання поки не дали результату(

8

Re: Побудова графіка з використанням DataGrigView та Chart

Вибачте, це взагалі ваш код? Я:
- ніколи не працював серйозно із C# - лише трохи для себе розбирав;
- точно ніколи не працював із GUI в C#;
- прямо вам написав, що вам треба додати Series для трьох фрагментів графіку.
Так, трохи ще покопався у вас - дані з DataGridView перекачуються в Series ось тут:

                //visualize all data rows
                for (int i = 0; i < dataGridView.RowCount - 1; i++)
                {
                    chart.Series["Main"].Points.AddXY(dataGridView[1, i].Value, dataGridView[2, i].Value);
                }

У чому проблема переробити це на три Series залежно від значення x, як я написав вище?

Подякували: leofun011

9

Re: Побудова графіка з використанням DataGrigView та Chart

Так, дякую) тепер вже все ок