How to set migradoc chart x axis tickmarks - c#

I assign manually values to the labels of the x-axis. Every 150 steps there should be a value. The rest is String.Empty. This part works perfectly.
Chart plotter = plotter_ref.Clone();
XSeries xseries = plotter.XValues.AddXSeries();
xseries.Add("0");
for (int i = 2; i <= 600; i++)
{
if (i % 150 == 0)
{
xseries.Add(i.ToString());
}
else
{
xseries.Add(String.Empty);
}
}
Now I would like to have Tickmarks at those points where the values are. I tried to set the MajorTickMark property
plotter.XAxis.MajorTick = 150;
plotter.XAxis.MajorTickMark = TickMarkType.Cross;
// or this
//plotter.XAxis.MajorTickMark = TickMarkType.Inside;
But it has no effect:
What am I doing wrong?
If I take a closer look at the Tutorial in the sample chart section their example also does not show any x-axis ticks. Is it at all possible?

what if you did another trick? i.e. while printing the values there, you did like this:
xseries.Add( "+" + Environment.NewLine + i.ToString()) );
thus, it will insert like this:
--------------------------------------
+ +
0 150 300
and just positioned 12pixel above?

Related

Battleships game, replace grid with character issues

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

Rotate text only in specific Excel row

I'd like to rotate headers in an Excel file using Microsoft.Office.Interop. To achieve this, I'm using the following code:
worksheet.Range["A1:" + worksheet.UsedRange.Columns.Count + "1"].Style.Orientation
= Excel.XlOrientation.xlUpwards;
The result looks like this:
As you can see, every cell gets rotated although I'm only specifying the first row. However, I just want the headers to be rotated:
I even tried it with a for loop for every column:
for (int counter = 1; counter <= worksheet.UsedRange.Columns.Count; counter++)
worksheet.Range[GetExcelColumnName(counter) + "1"].Style.Orientation
= Excel.XlOrientation.xlUpwards;
But I get the same result. What should I do to only change the orientation of the headers?
(Method GetExcelColumnName)
Just convert the entire row 1.
worksheet.Range["1:1"].Style.Orientation = Excel.XlOrientation.xlUpwards;
worksheet.Rows["1"].Style.Orientation = Excel.XlOrientation.xlUpwards;
fwiw, in VBA this might be best handled with application.intersect of rows(1) and the .usedrange. From your code it looks like that would be,
Excel.Intersect(worksheet.Range["1:1"], worksheet.UsedRange).Style.Orientation = Excel.XlOrientation.xlUpwards;
/* just the cells, not the style */
Excel.Intersect(worksheet.Range["1:1"], worksheet.UsedRange).Cells.Orientation = Excel.XlOrientation.xlUpwards;
What worked for me was:
ws.SelectedRange[1, 1, 1, 15].Style.TextRotation = 180;
TextRotation for vertical text: 90 or 180 (upwards, downwards)

Aligning range column data with x axis labels in chart control

I'm trying to do a range column plot of a set of agents' tasks using the Chart control in C# .NET. I plot agent number across the x axis and task time along the y axis. My only problem is that the column data will not align properly with the agent numbers on the x axis. Does anyone know how to align the columns with their corresponding x axis labels?
Here is an image of my graph:
Here is my code:
chartSchedule.Titles.Add("Agent / Task Schedule");
chartSchedule.ChartAreas[0].AxisX.Title = "Agent";
chartSchedule.ChartAreas[0].AxisY.Title = "Time";
int index = 0;
foreach ( Agent a in _agents )
{
// Create a series for each agent and set up display details
Series agentSeries = chartSchedule.Series.Add("Agent " + a.Id);
agentSeries.ChartType = SeriesChartType.RangeColumn;
// Alternate colours of series lines
if ( index % 2 > 0 )
agentSeries.Color = Color.DodgerBlue;
else
agentSeries.Color = Color.Blue;
// Display start and end columns of every task
List<DataPoint> timeData = new List<DataPoint>();
foreach ( NodeTask t in a.AssignedTasks )
{
agentSeries.Points.AddXY(index + 1, t.StartTime, t.EndTime);
}
index++;
}
The reason for the seeming 'misalignment' is that you are adding a total of five series but each has only one (set of) Datapoint(s) per X-Value.
This existent DataPoint is then combined wih the the four non-existent DataPoints and the five of them are displayed side by side as one block centered at the X-Values/Labels. This looks only right for the middle Series, which actually has the middle point.
You could add a few the other Points to see the effect..:
agentSeries.Points.AddXY(1, 1, 4);
agentSeries.Points.AddXY(2, 1, 2);
agentSeries.Points.AddXY(4, 1, 3);
So the most natural solution is to not add Series with missing data.
Not sure if you are happy with this solution or if there is a better way to do it, but the result looks not so bad..
I have done away with adding all those series and instead add all data to one and same Series.
To create the Legends I hide the regular one by setting its color to transparent. (It needs to be there.) Then I add new Legend CustomItems and give them the colors and names as you did.
Here is the code I used, except for the actual data, which I have simulated:
chartSchedule.Series.Clear();
ChartArea CA = chartSchedule.ChartAreas[0];
chartSchedule.Titles.Add("Agent / Task Schedule");
chartSchedule.ChartAreas[0].AxisX.Title = "Agent";
chartSchedule.ChartAreas[0].AxisY.Title = "Time";
// our only Series
Series agentSeries = chartSchedule.Series.Add(" " );
agentSeries.ChartType = SeriesChartType.RangeColumn;
agentSeries.Color = Color.Transparent; // hide the default series entry!
agentSeries["PixelPointWidth"] = "20"; // <- your choice of width!
int index = 0;
foreach (Agent a in _agents)
{
// Alternate colours
Color color = index % 2 == 0 ? Color.DodgerBlue : Color.Blue;
// Display start and end columns of every task
List<DataPoint> timeData = new List<DataPoint>(); ///???
foreach (NodeTask t in a.AssignedTasks)
{
int p = agentSeries.Points.AddXY(index +1, t.StartTime, t.EndTime);
agentSeries.Points[p].Color = color;
}
chartSchedule.Legends[0].CustomItems.Add(color, "Agent " + index);
index++;
}

Get Series value from a mouse click

I use Microsoft.DataVisualization.Charting and want to get the value of the point when i click on it.
My problem: i want exactly that value i clicked, even if its only a value calculated by the Chart and between 2 points.
Example: 3 points: P(0;3), P(1;6), P(3;12)
When i click at x-Value 2 i want to get 9 as result if the line is linear.
Currently i do that:
HitTestResult[] hits = chart.HitTest(e.X, e.Y, false, ChartElementType.PlottingArea);
//DataInformation save the DateTime and Value for later use
DataInformation[] dinfo = new DataInformation[hits.Length];
foreach (ChartArea area in chart.ChartAreas)
{
area.CursorX.LineWidth = 0; //clear old lines
}
for (int i = 0; i < hits.Length; i++) //for all hits
{
if (hits[i].ChartElementType == ChartElementType.PlottingArea)
{
//val saves the x-value clicked in the ChartArea
double val = hits[i].ChartArea.AxisX.PixelPositionToValue(e.X);
DataPoint pt = chart.Series[hits[i].ChartArea.Name].Points.Last(elem => elem.XValue < val);
dinfo[i].caption = hits[i].ChartArea.Name;
dinfo[i].value = pt.YValues[0].ToString();
//hits[i].ChartArea.CursorX.Position = pt.XValue;
}
}
This show the right values for every existing data point but not that clicked point.
How can i get the exact value?
It seems, there is no way to get the exact value. I changed to OxyPlot. OxyPlot can show the data much faster and you can get the exact value for any point.

Colouring a graph in my program and adding values

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

Categories