I want to ask if its possible to color the negative values of the chart a different color from the positive ones. Also how can i enter marks on the values like tagg the values at 1,2,3..10 etc! The values range from -300000 up to 700000
The chart is in C# and i have a button that executes the following:
decimal[] numbers = new decimal[20];
for (int i = 0; i < 20; i++)
{
numbers[i] = Convert.ToDecimal(dataGridView1[7, i].Value);
chart1.Series["Loan_Balance"].Points.AddXY(i+1, numbers[i]); }
chart1.Series["Loan_Balance"].Color = Color.Blue;
chart1.ChartAreas[0].AxisX.Interval = 1;
chart1.ChartAreas[0].AxisY.Interval = 50000;
chart1.Series["Loan_Balance"].ChartType = SeriesChartType.Range;
}
Also i wanted to ask, why when i enter the values straight from the database (datagridview). For example in the for loop, instead of creating an array and convert the values from the datagridview to decimal, to plot them straight in like:
chart1.Series["Loan_Balance"].Points.AddXY(i, dataGridView2[i, 0].Value);
the chart1.ChartAreas[0].AxisY.Interval = 50000;
behaves strangely, most of the times it doesn't work at all
The coloring problem is much more important if you could help me i would truly appreciate it.
Thanking you in advance
Best Regards
George Georgiou
You should be creating the points directly rather than using AddXY. This gives you full control over the point including it's color. So, rather than:
chart1.Series["Loan_Balance"].Points.AddXY(i+1, numbers[i]);
Use:
var point = new DataPoint(i+1, numbers[i]);
point.Color = numbers[i] < 0 ? Color.Red : Color.Black; // or whatever logic
point.Label = numbers[i].ToString(); // and so on
chart1.Series["Loan_Balance"].Points.Add(point);
You can see what other properties are available on the DataPoint here: http://msdn.microsoft.com/en-us/library/system.windows.forms.datavisualization.charting.datapoint.aspx
Related
I am trying to do something similar to the one in the example but changing the colour of the text/label.
Example:
Label1.Text = Label2.Text;
Label2.Text = Label3.Text;
Label3.Text = Label4.Text;
//so and and so forth
I am looking for a very simple solution like the one shown in the example but with colors.
I am using Windows Form App with .Net Framework 4.7.2, I am using C# 9.0.
I have tried using .ForceColor as a way to change the color but as you can see, i am trying to accomplish a similar thing as the one in the example.
At first, I suggest put labels in a container, And don't put anything except labels.
Then:
Do for loop, and length = ContainerPanel.Controls.Count - 1, with condition i = ContainerPanel.Controls.Count
Cast Control[i] to labelFirst
Cast Control[i + 1] to labelSecond
labelFirst.ForeColor = labelSecond.ForeColor
In this example, Container is: ContainerPanel
for (int i = 0; i < ContainerPanel.Controls.Count - 1; i++)
{
// This is a simple way without variables
(Label(ContainerPanel.Controls[i])).ForeColor = (Label(ContainerPanel.Controls[i + 1]));
}
Note: last Label You should change its ForeColor, Or it will not be changed.
Q&A
Q: Why length = ContainerPanel.Controls.Count - 1??
A: Because we should get Cast Control[i + 1] to labelSecond, And we can't, except if the length is less than controls count by one
I'm currently trying to create a battleships console application. I've very new to c# but I'm almost there now there's just issue.
What I'm trying to do is replace a string with H or M when a ship is hit the works fine the only issue I have is when the H or M is inserted it doesn't replace the character in its place and it just moves the characters alone, for example if I have 5 characters in a row it like so: 0 0 0 0 0 it would insert the H or M and show: M0 0 0 0 0
I've been trying all sorts to fix this but as I said my knowledge is very limited.
Ints and Grid creation:
int gridSize = 10;
int BattleShip = 5;
int Destroyer1 = 4;
int Destroyer2 = 4;
int Row;
int Column;
char[,] Vgrid = new char [gridSize, gridSize];
This generates the grid:
for (Row = 0; Row < gridSize; Row++)
{
Console.WriteLine();
Console.Write("{0} | ", GridNumber++);
for (Column = 0; Column < gridSize; Column++)
Console.Write(Vgrid[Column, Row] + "~ ");
}
This code controls the H or M replacing:
if (grid[temp, temp1] == Destroyer1 || grid[temp, temp1] == Destroyer2 || grid[temp, temp1] == BattleShip)
{
Console.WriteLine("HIT!");
Hit++;
Vgrid[temp, temp1] = 'H';
}
else
{
Console.WriteLine("MISS!");
Miss++;
Vgrid[temp, temp1] = 'M';
}
Is there a way I can do this? I just want to be able to replace the character in the grid with the H or M characters.
This grid is actually an overlay as the actual grid is an int and that is where the ships are plotted, this is the only way I thought I can use letters to signify a hit instead of numbers and keep the ships hidden to the players.
Attempting to alter the output of the Console window directly isn't necessarily the best approach for what you're wanting to achieve. Ideally, we should control what we write to the window, rather than try and control the window directly.
A simpler idea to achieve your goal might be to store two grids, one for your ships and another one for your shots. This allows you to separate what you draw to the console window from what you use to check if the player has landed a shot easily, keeping your ships hidden.
Firstly, let's create our setup:
int gridSize = 10;
int BattleShip = 5;
int Destroyer1 = 4;
int Destroyer2 = 4;
int[,] shipGrid = new int[gridSize, gridSize];
char[,] shotGrid = new char[gridSize, gridSize];
The big change is the grids - one for the ships, and another for the shots. We use the same gridSize variable to make sure that the grids are exactly the same size. This is important to make sure that the two grids line up exactly.
Then, we'll set our default values for our shotGrid. We can do this with a simple method that just sets every value to the default, in this case '~':
public void CreateShotGridDefaultValues ()
{
for (int y = 0; y < shotGrid.GetLength(1); y++)
{
for (int x = 0; x < shotGrid.GetLength(0); x++)
{
shotGrid[x, y] = '~';
}
}
}
Next, to check if a player has landed a shot, we use the shipGrid to check if the player's selection relates to a ship, but we update the shotGrid with the information we want to draw to the console window:
public void CheckPlayerShot(int xCoordinate, int yCoordinate)
{
if (shipGrid[xCoordinate, yCoordinate] == Destroyer1 || shipGrid[xCoordinate, yCoordinate] == Destroyer2 || shipGrid[xCoordinate, yCoordinate] == BattleShip)
{
Console.WriteLine("HIT!");
Hit++;
shotGrid[xCoordinate, yCoordinate] = 'H';
}
else
{
Console.WriteLine("MISS!");
Miss++;
shotGrid[xCoordinate, yCoordinate] = 'M';
}
}
Then, we draw out the shotGrid to the console window as follows:
public void DrawGrid()
{
Console.WriteLine();
for (int y = 0; y < shotGrid.GetLength(1); y++)
{
string currentLine = $"{y + 1} | ";
for (int x = 0; x < shotGrid.GetLength(0); x++)
{
char shot = shotGrid[x, y];
currentLine += shot.ToString() + " ";
}
Console.WriteLine(currentLine);
}
Console.WriteLine();
}
This method is a little different to yours, so let me explain a little further. The idea for this method is to build up the information we want to write to the console window one line at a time, rather than draw out every character one at a time. This prevents us from needing to change the console window output directly.
To achieve this, we use two loops, just like you did. The second for() loop iterates through the row's grid cells, and adds them to the currentLine string. Once we've finished a row, we just write out that string to the console window all at once.
With all that in place, you just need call the DrawGrid() method whenever you want to update the grid in the console window. To better understand when and where the best time and place to update the window might be, requires a better understanding of Game Loops. This page should be a terrific start on that path..
Edit: Updated answer to reflect comments.
You could use
Console.SetCursorPosition(Int32, Int32) Method
Sets the position of the cursor.
Or you could just keep everything in a matrix and redraw the screen on change
I'm trying to figure out if I can find any exist chart in winforms C# application.
I have several integer inputs a, b, c... and at the end of processing I got results with wide range of values like 12, 342, 445879 etc.
On chart I want to see only hierarchy from higher size to lower without equivalent scale distance between higher and lower line ends. Just stairway by downward curve for each input.
So two things is needed, if some kind of such chart tool is already exist, is a sorting of sequence from higher to lower with names attached to the lines and non-scaled value display in the ratio between each other.
For example I have inputs:
int a = 12989;
int b = 324;
int c = 23;
int d = 12;
int e = 3;
and second process results:
int a = 4;
int b = 25;
int c = 1;
int d = 4;
int e = 14;
I have tried to use different graphs in list of VS,
private void Size(int a, int b)
{
this.chart1.Series["Series1"].Points.AddXY("a1", a);
this.chart1.Series["Series1"].Points.AddXY("a2", b);
}
but seems like I need different thing.
Here is desired results:
Yes, this is possible.
For x-values there is in fact a Series property IsXValueIndexed to enforce an unscaled display. There is no such thing for the y-values, though.
(The reason is probably that unscaled y-values are not really useful, as they will arguably mislead the user about the data..(..which may or may not be true of x-values; x-values containing, say, zip codes or other IDs should be displayed unscaled!))
To workaround you need to set the x and y-values to a count value and set the Labels of each DataPoint explicitly to the actual values you have.
Example:
// create an odered list of data:
List<double> data = new List<double>();
for (int i = 0; i < 12; i++) data.Add(rnd.Next(100) * rnd.Next(i * 5));
data = data.OrderByDescending(x => x).ToList();
// now add with dummy x and y-values:
Series s = chart1.Series[0];
for (int i = 0; i < data.Count; i++)
{
int p = s.Points.AddXY(i, data.Count - i); // dummy values
DataPoint dp = s.Points[p];
dp.Label = data[i] +""; // real value, formatted
dp.Tag= data[i]; // real value
}
To get rid of the axes, which can't show ay meanigful values, disable them:
chart1.ChartAreas[0].AxisX.Enabled = AxisEnabled.False;
chart1.ChartAreas[0].AxisY.Enabled = AxisEnabled.False;
More styling:
s.SetCustomProperty("PixelPointWidth","15");
s.Color = Color.DarkSlateGray;
Note the as the y-values are really just dummies, if you need to access them, you will have to use the Labels and convert them from string to number type. Also note that if they are double or floats those strings will either be terribly long or formatted to a short string. To preserve the actual values you can store these additionally in the Tag field of each DataPoint..
I need to get data from a single DataGridView into 3 distinct Charts, each column to a chart.
This is the first time I'm working with charts, so I've researched a bit about them but couldn't find anything that could help me with this specific problem.
Here follows a screenshot of what my DataGridView and my Charts are like, with their respective legends:
What I need is (at least in theory) a very simple thing. In the "SANITY" chart I need to get the value located at Table[0, 0] into something like sanityChart.Series[0] as its 'Y' value, and so on. Same thing for "UNIT" and "ISSUES DB".
Any help will be much appreciated.
From the way you asked the question and the image you have shown I believe that you want something like this:
I use only one Chart and I have added one Series for each of your Columns.
After setting up the chart I have added one data point for each row in the table to each of the series/columns..:
// setting up the datagridview
Table.Rows.Clear();
Table.Columns.Clear();
Table.Columns.Add("state", "");
Table.Columns.Add("sanity", "SANITY");
Table.Columns.Add("unit", "UNIT");
Table.Columns.Add("issuesDb", "ISSUES DB");
// filling in some data
Table.Rows.Add("ALL PASSED", 86, 21, 2);
Table.Rows.Add("FAILED", 7, 0, 1);
Table.Rows.Add("Cancelled", 0, 0, 0);
// Now we can set up the Chart:
List<Color> colors = new List<Color>{Color.Green, Color.Red, Color.Black};
chart1.Series.Clear();
for (int i = 0 ; i < Table.Rows.Count; i++)
{
Series S = chart1.Series.Add(Table[0, i].Value.ToString());
S.ChartType = SeriesChartType.Column;
S.Color = colors[i];
}
// and fill in all the values from the dgv to the chart:
for (int i = 0 ; i < Table.Rows.Count; i++)
{
for (int j = 1 ; j < Table.Columns.Count; j++)
{
int p = chart1.Series[i].Points.AddXY(Table.Columns[j].HeaderText, Table[j, i].Value);
}
}
Note that I have chosen to add the DataPoints with the AddXY overload and also decided that I want to make my life a little easier by adding the X-Values as strings. Internally they are still transformed to doubles and will all have a value of 0! Not a problem for us here, but it is important to understand that we didn't use valid numbers and therefore can't treat them as numbers! The advantage is that the axis labels are being set to the column headers without any further work..
Ok so I am making a sudoku solver for fun (yes I know it's already been made many times over) so to let people input there values before solving I used numericalupdown (81 one of them to be exact)
and i wanted to assign all of them to an array:
int[,] Sudoku = new int[9, 9];
and then on clicking "solve" the first thing it's supposed to do is put all the values in the array:
private void button1_Click(object sender, EventArgs e)
{
for (int x = 0; x < 81; x++)
{
for (int y = 0; y < 9; y++)
{
if (x-1 == 0)
{
Sudoku[x - 1, y - 1] = Convert.ToInt32(numericUpDown[y].Value);
}
else
{
Sudoku[x - 1, y - 1] = Convert.ToInt32(numericUpDown[x][y].Value);
}
}
}
}
obviously you can't do: "numbericupdown[y]" but thats for you to see what I am trying to do....
sooooo thoughts?
THANKS,
Craiggles
If you put your numericUpDown controls into a 9x9 grid just like you have for the results, then copying the values will be straightforward.
private void button1_Click(object sender, EventArgs e)
{
for (int x = 0; x < 9; x++)
{
for (int y = 0; y < 9; y++)
{
Sudoku[x, y] = Convert.ToInt32(numericUpDown[x, y].Value);
}
}
}
If the controls are actually all dropped onto the form, then don't do that, remove them from the form. Use code to create them, place them programmatically, and put them into a 2d array. Since this is a learning program anyways, that's good practice for doing GUI's programmatically instead of just by drag-n-drop.
I would go about constructing/placing them dynamically and at the same time putting them into an array or list, but if they are already laid out onto a form you can just add them to a generic list to iterate over them.
List<NumericUpDown> nums = new List<NumericUpDown>();
nums.add(numericUpDwown1);
then you could calculate nums[1]*nums[9]... or whatever
I think I understand what you are doing... Two suggestions: 1) put all of your controls into an array of NumericaUpDown objects. Then you could do numericUpDown[y].Value. Otherwise, 2) name the controls ending with numbers (or some similar convention) then use reflection to find the right one and get its value.
Actually there is no reason at all why you cannot create controls and store them in various collection classes - not just arrays.
I would consider putting these into some sort of structured set of collections that reflect the structure of a sudoku grid.
You could dynamically create and place the controls on the form as well as holding them in the collection.