I am new to c# programming and creating my first Windows forms application. I have a two 1-D Arrays, one represents the X Axis Values and the other represents Y axis.
I am trying to create a graph from them using the following code.
public void drawgraph()
{
chart1.Series["Series1"].Name = MemsName;
for (int i = 0; i < VmicArray.Length; i++)
{
chart1.Series[MemsName].Points.AddXY(VmicArray[i], SensitivityArray[i]);
}
chart1.ChartAreas[0].AxisX.Title = "Vmic Value";
chart1.ChartAreas[0].AxisY.Title = "Sensitivity";
}
I am getting the XAxis values which I have in Array(like -2.333333754 or 6.46870) with the interval of 5 which I have set. The range of X axis is have is from -4 to +8.
Is there anyone who can help me in getting a ouput like we get in Excel Graphs? I am trying for Long time always I mess up with the values of X axis.
I Need the graph with XAxis value from -10 to +10 with the interval of 1 and mapping the Y values to corresponding X values on graph.
Unfortunately I am not able to post any Images :(
If you want to project a certain range of values to another range you need to use linear interpolation between the values. First determine the old min and max values (MinX and MaxX) and define the new limits (-10, 10).
Then use a simple formula to determine the new x value of an arbitrary old value.
double MinX = VmicArray.min;
double MaxX = VmicArray.Max;
double NewMin = -10;
double NewMax = 10;
for (i = 0; i <= VmicArray.Count - 1; i++) {
// Linear interpolation
double NewX = VmicArray(i) / (MaxX - MinX) * (NewMax - NewMin) + NewMin;
}
Recalculate each X value before you use AddXY.
In order to just change the visible bounds of each axis you can use the XAxis.Minimum and XAxis.Maximum as well as the XAxis.Interval properties:
chart1.ChartAreas[0].AxisX.Minimum = -10;
chart1.ChartAreas[0].AxisX.Maximum = 10;
chart1.ChartAreas[0].AxisX.Interval = 1;
Related
I have a set of points I want to show on a 2000x2000 canvas. Here is an example: "61.86, 83 - 61.79, 82.91 - 61.77, 82.77 - 61.92, 82.76 - 61.75, 82.7 - 61.79, 82.58 - 61.85, 82.46 - 61.79, 82.17 - 61.72, 81.88 - 61.61, 81.61 - 61.51, 81.33 - 61.49, 81.02 - 61.33, 80.99 - 61.37, 80.83"
These points are from a 100x100 grid so the first one ought to be in the bottom right quarter of my 2000*2000 canvas.
To do this I have code that finds the biggest X and Y and then rescales.
List<double> MinAndMax(List<Node> spots)
{
List<double> retValues = new List<double>();
double xLowest = spots.Select(s => s.X).Min();
double xHighest = spots.Select(s => s.X).Max();
double xDifference = xHighest - xLowest;
double yLowest = spots.Select(s => s.Y).Min();
double yHighest = spots.Select(s => s.Y).Max();
double yDifference = yHighest - yLowest;
if (xLowest < yLowest)
retValues.Add(xLowest);
else
retValues.Add(yLowest);
if (xHighest < yHighest)
retValues.Add(yHighest);
else
retValues.Add(xHighest);
return retValues;
}
int Rescale(double oldValue, double oldMin, double oldMax, int newMin, int newMax)
{
return Convert.ToInt32(((oldValue - oldMin) * (newMax - newMin) / (oldMax - oldMin)) + newMin);
}
I call it like so:
double zoneMin, zoneMax;
int lowestCanvas = 150, highestCanvas = 1850;
List<Node> path = await PathMaker();
List<double> zoneMinMax = MinAndMax(path);
zoneMin = zoneMinMax[0];
zoneMax = zoneMinMax[1];
foreach (Node spot in path)
{
Point point = new Point();
point.X = Rescale(spot.X, zoneMin, zoneMax, lowestCanvas, highestCanvas);
point.Y = Rescale(spot.Y, zoneMin, zoneMax, lowestCanvas, highestCanvas);
NodeSpot dot = new NodeSpot()
{
Name = spot.Name,
Location = point,
IsInPath = true
};
drawingSurface1.Nodes.Add(dot);
}
drawingSurface1.Invalidate();
Instead of getting my little path nicely spread out, I get this odd clump in the bottom LEFT had quadrant.
I can't see where I am going wrong here. What do I need to do in order to have my 14 points spread out over the canvass?
Your issue is that you are returning a single min value and a single max value. You need separate min and max values for X and Y, as the ranges in each coordinate are different. In your sample data from the question the range of X is [-61.92, 61.86] and the range of Y is [80.83, 83]. Your approach will draw a frame covering [-61.92, -61.92] to [83, 83], with most of the points in one corner.
Your test fails to catch the problem as the X and Y values are the same in the test case. Create a test case where the X values are all negative and the Y values positive, this will show the issue.
let's take [[20, 20], [50, 50], [80, 80]] as an easy exemple.
min and max will be 20 and 80 and wanted scale is 0 to 2000.
for the point [50, 50]
(((oldValue - oldMin) * (newMax - newMin) / (oldMax - oldMin)) + newMin)
gives
((50 - 20) * (2000 - 0) / (80 - 20)) + 0
= 30*2000 / 60
= 1000 (which is half the size of the canvas)
seems coherent so the problem is not coming from the transform function
I suggest trying to debug it by printing the [X, Y] values of the "point" to be sure tho
Also print the min max of the oldScale to be sure this is not the problem
Use the Graphics.PageScale Property
See also Coordinate Systems and Transformations
I created a Line Chart control in Windows Forms.
I divided the ChartArea, AxisX into four intervals but I want to apply back color (unique color) to each interval.
Can someone help me on this?
You could paint those areas, but this would always show above all chart elements including grid and data points.
So, as NLindborn suggests, the best way are StripLines.
They are under all elements and will scale nicely.
Note that their properties are in data values, so you need to know the values, or rather the x-axis range, in your chart.
Here is complete code example using StripLines:
// set up the chart:
ChartArea ca = chart.ChartAreas[0];
chart.Series.Clear();
for (int i = 0; i < 5; i++)
{
Series s = chart.Series.Add("Series" + (i+1));
s.ChartType = SeriesChartType.Line;
s.BorderWidth = 2;
}
// add a few test data
for (int i = 0; i <= 360; i++)
{
chart.Series[0].Points.AddXY(i, Math.Sin(i * Math.PI / 180f));
chart.Series[1].Points.AddXY(i, Math.Cos(i * Math.PI / 180f));
chart.Series[2].Points.AddXY(i, Math.Sin(i * Math.PI / 90f));
chart.Series[3].Points.AddXY(i, Math.Cos(i * Math.PI / 90f));
chart.Series[4].Points.AddXY(i, Math.Sin(i * Math.PI / 30f));
}
// set up the chart area:
Axis ax = ca.AxisX;
ax.Minimum = 0;
ax.Maximum = 360;
ax.Interval = 30;
// a few semi-transparent colors
List<Color> colors = new List<Color>() { Color.FromArgb(64, Color.LightBlue),
Color.FromArgb(64, Color.LightSalmon), Color.FromArgb(64, Color.LightSeaGreen),
Color.FromArgb(64, Color.LightGoldenrodYellow)};
Now we are ready to create the StripLines:
// this is the width of the chart in values:
double hrange = ax.Maximum - ax.Minimum;
// now we create and add four striplines:
for (int i = 0; i < 4; i++)
{
StripLine sl = new StripLine();
sl.Interval = hrange; // no less than the range, so it won't repeat
sl.StripWidth = hrange / 4f; // width
sl.IntervalOffset = sl.StripWidth * i; // x-position
sl.BackColor = colors[i];
ax.StripLines.Add(sl);
}
Note that you will need to adapt the stripline data whenever you change the axis range!
Also note the StripLine use axis values.
Update:
One common issue is to move the striplines when zooming. Without a little help they will stick to the original positions. Codeing the AxisViewChanged will help, maybe like so:
For each of your striplines calculate an IntervalOffset; in the simplest case of the 1st one this should work:
chart1.ChartAreas[0].AxisX.StripLines[0].IntervalOffset =
chart1.Series[0].Points[0].XValue - e.NewPosition;
For the others add the correct multiple of the width as above!
AxisX into four intervals but I want to apply back color (unique color)
These intervals are created with colored StripLine(s). Either via code:
var stripLine = new System.Windows.Forms.DataVisualization.Charting.StripLine()
{
BackColor = Color.Blue,
IntervalOffset = 4, // This is where the stripline starts
StripWidth = 2 // And this is how long the interval is
};
chart1.ChartAreas[0].AxisX.StripLines.Add(stripLine);
You need to add data points for the interval to show.
Or, StripLines can also be added from VS design mode from (Properties) -> ChartAreas -> Select a ChartArea -> Axes -> Select the Axis you want it to show on -> StripLines, then Add StripLine. You have to set a BackColor, IntervalOffset and StripWidth for it to show. If you set StripLine.Interval it will repeat by that interval.
I have downloaded a shapefile from here which provided a cantor map for me.
I have got DotSpatial and loaded the map in c#. I need to traverse the map and get the height of each coordination.
I have created a 3d ViewPort in WPF by C# and have a grid that I just need have the height of each point on the grid to have a 3D map.
1- I don't know whether the file has the heights for coordinations or not. If this site doesn't provide a file with this attribute where can I get files that have height property in them?
2- How can I use DotSpatial to understand the minimum and maximum of Longitude and Latitude of the map?
I want to write some code like this.(It is just a pseudocode)
double dx = Math.Abs(MaxLongitude - minLongitude) / myMapGrid.Nx;
double dy = Math.Abs(MaxLatitude - minLatitude) / myMapGrid.Ny;
for (int x = 0; x < myMapGrid.Nx; x++)
{
for (int y = 0; y < myMapGrid.Ny; y++)
{
double z = GetHeightOfCoordination(map, minLongitude+(x*dx), minLatitude+(y*dy));
SetMapGridData(myMapGrid, x, y, z);
}
}
3- and finally how can I get the height value of each coordination point?
var test = Shapefile.OpenFile(#"C:\yourpath");
while (i < test.Features.Count)
{
var temp = test.GetFeature(i);
var coordinates = temp.Coordinates
for (int geo = 0; geo <= temp.NumGeometries - 1; geo++)
{
foreach (DotSpatial.Topology.Coordinate x in temp.GetBasicGeometryN(geo).Coordinates)
{
int X = x.X;
int Y = x.Y;
int Z = x.Z;
}
}
}
Or if you just wanna look at your temp.Coordinates you will get this:
[{"M":"NaN","X":494869.712,"Y":5458703.355,"Z":"NaN","NumOrdinates":2}]
(Hopefully yours containing a Z value.)
I need to find every single cordination in an X and Y KeyPairValue in C#, is there an easy way to do this?
I have the max X and max Y, and the min just starts at 1
int maxX = room.Model.MapSizeX;
int maxY = room.Model.MapSizeY;
Now, I just need to loop every possibility, but I don't really know how to do that, can someone help me with this? I think I just need to loop through everything in X and everything in Y but for every possibility between 1 and max for x and Y
This is simple with nested for loops. Iterate over the first range, and within that, iterate over the second range.
var minX = 1;
var minY = 1;
var maxX = 99;
var maxY = 99;
for (var currentX = minX; currentX <= maxX; ++currentX)
{
for (var currentY = minY; currentY <= maxY; ++currentY)
{
// do something with each X,Y combination
}
}
I'm working on civilization game in C# and XNA. I use a two dimensional integer array, populated with a loop, to generate tiles, I've done a ton research and have been unable to find a way to generate earth like terrain. Can anyone explain how to do this or at least give me code that could do it, though I would prefer and explanation? Thank you.
I use an algorithm similar to this to make my terrain. Basicly it generates some random numbers and uses a sine wave to generate hills, when combined they give a nice hilly landscape. Note that you can add a loop and array of values if you want more than just 3 passes.
private void GenerateTerrain()
{
terrainContour = new int[Width*Height];
//Make Random Numbers
double rand1 = randomizer.NextDouble() + 1;
double rand2 = randomizer.NextDouble() + 2;
double rand3 = randomizer.NextDouble() + 3;
//Variables, Play with these for unique results!
float peakheight = 20
float flatness = 50
int offset = 30;
//Generate basic terrain sine
for (int x = 0; x < Width; x++)
{
double height = peakheight / rand1 * Math.Sin((float)x / flatness * rand1 + rand1);
height += peakheight / rand2 * Math.Sin((float)x / flatness * rand2 + rand2);
height += peakheight / rand3 * Math.Sin((float)x / flatness * rand3 + rand3);
height += offset;
terrainContour[x] = (int)height;
}
}
Then to fill the heightmap just loop through the values and check if it is above the threshold or not.
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
if (y > terrainContour[x])
tiles[x, y] = Solid Tile
else
tiles[x, y] = Blank Tile
}
}
Theres much more you can add to it, I've added more randomness and indenting some tiles by 1 up or down for better terrain. And adding more sine waves will make it more realistic.
Try using 2D Perlin Noise algorithms, and selecting certain heights to make caves and more advanced terrain, as this is now what I do, but this code here is a good start.