How can this code produce a similar Graph Diagram as the other one? I have posted my entire code, if someone is an expert on this, share your input. I don't understand drawing fully in WPF! I am still reading on the topic.
My Code:
private void GenerateGraphBtn_Click(object sender, RoutedEventArgs e)
{
// Setting up the bounds of the graph
const double margin = 30;
double xmin = margin;
double xmax = (DrawGraphArea.Width / 2);
double ymin = margin;
double ymax = (DrawGraphArea.Height / 2);
const double step = 12;
// ##########################################################
// Make the X axis.
GeometryGroup xaxis_geom = new GeometryGroup();
// Creates the long Horisontal Line
xaxis_geom.Children.Add(new LineGeometry(
new Point(0, ymax), new Point(DrawGraphArea.Width / 2, ymax)));
// Adds all the mini lines on the horisontal axis (bottom)
for (double x = xmin step;
x <= (DrawGraphArea.Width / 2) - step; x = step)
{
xaxis_geom.Children.Add(new LineGeometry(
new Point(x, ymax - margin / 2),
new Point(x, ymax margin / 2)));
}
/* Adds all the lines that were created in the above code to the graph.
* Stroke thickness = line thickness
* Stroke = line colour
* Data = the geometry you are adding (the points that you have created in the above code)
*/
Path xaxis_path = new Path();
xaxis_path.StrokeThickness = 2;
xaxis_path.Stroke = Brushes.DarkRed;
xaxis_path.Data = xaxis_geom;
DrawGraphArea.Children.Add(xaxis_path);
// ##########################################################
// Creates the Y axis.
GeometryGroup yaxis_geom = new GeometryGroup();
// Adds the long Vertical Line
yaxis_geom.Children.Add(new LineGeometry(
new Point(xmin, 0), new Point(xmin, DrawGraphArea.Height / 2)));
// Adds the mini lines on the vertical axis (Left)
for (double y = step; y <= (DrawGraphArea.Height / 2) - step; y = step)
{
yaxis_geom.Children.Add(new LineGeometry(
new Point(xmin - margin / 2, y),
new Point(xmin margin / 2, y)));
}
// Adds them all to the graph.
Path yaxis_path = new Path();
yaxis_path.StrokeThickness = 1;
yaxis_path.Stroke = Brushes.Black;
yaxis_path.Data = yaxis_geom;
DrawGraphArea.Children.Add(yaxis_path);
// ##########################################################
// This creates the brushes colours
Random rand = new Random();
// This will then go along and create all the colour
for (int data_set = 0; data_set < 1; data_set )
{
int last_y = rand.Next((int)ymin, (int)ymax);
// This is where you add the points to the graph
// Little bit confusing as it is adding 3 lines at once
PointCollection points = new PointCollection();
for (double x = xmin; x <= xmax; x = step)
{
last_y = rand.Next(last_y - 10, last_y 10);
if (last_y < ymin) last_y = (int)ymin;
if (last_y > ymax) last_y = (int)ymax;
points.Add(new Point(x, last_y));
}
// Adds the lines that connect the points
Polyline polyline = new Polyline();
polyline.StrokeThickness = 2;
polyline.Stroke = Brushes.Red;
polyline.Points = points;
// Add the line / points
DrawGraphArea.Children.Add(polyline);
}
}
Current result:
Desired result:
CodePudding user response:
You were on the right path to resolve it, I used your code as guideline.
So, 1st here is the code that provide your desired result,
This goes to the MainWindow xaml:
<Window x:Class="WpfApp2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp2"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="20" />
<RowDefinition />
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Button" HorizontalAlignment="Left" Click="GenerateGraphBtn_Click" />
<Canvas Grid.Row="2" x:Name="GrpahArea" Margin="40" />
</Grid>
</Window>
And this goes into the code-behind of the MainWindow
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace WpfApp2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private Point[] GenerateGraphPoints(int minimumX, int maximumX, int minimumY, int maximumY)
{
var result = new List<Point>();
var rnd = new Random();
for (var x = minimumX; x < maximumX; x )
result.Add(new Point(x, rnd.Next(minimumY, maximumY)));
return result.ToArray();
}
private void PlotXAxes(Panel drawArea, int minimumX, int maximumX, int step, int miniLineExtent)
{
var geometryGroup = new GeometryGroup();
var axePositionY = drawArea.ActualHeight;
geometryGroup.Children.Add(new LineGeometry(new Point(0, axePositionY), new Point(drawArea.ActualWidth, axePositionY)));
var factorX = drawArea.ActualWidth / (maximumX - minimumX);
for (var i = minimumX; i < maximumX; i )
if (i % step == 0)
{
geometryGroup.Children.Add(new LineGeometry(
new Point(i * factorX, axePositionY - miniLineExtent),
new Point(i * factorX, axePositionY miniLineExtent)));
drawArea.Children.Add(new Label
{
Margin = new Thickness(i*factorX, axePositionY miniLineExtent, 0, 0),
Content = i,
Foreground = Brushes.Black
});
}
var path = new Path
{
StrokeThickness = 2,
Stroke = Brushes.DarkRed,
Data = geometryGroup
};
drawArea.Children.Add(path);
}
private void PlotYAxes(Panel drawArea, int minimumY, int maximumY, int step, int miniLineExtent)
{
var labelSize = new Size(30, 26);
var geometryGroup = new GeometryGroup();
var axePositionX = 0;
geometryGroup.Children.Add(new LineGeometry(new Point(axePositionX, 0), new Point(axePositionX, drawArea.ActualHeight)));
var factorY = drawArea.ActualHeight / (maximumY - minimumY);
for (var i = minimumY; i < maximumY; i )
if (i % step == 0)
{
geometryGroup.Children.Add(new LineGeometry(
new Point(axePositionX - miniLineExtent, (maximumY-i) * factorY),
new Point(axePositionX miniLineExtent, (maximumY-i) * factorY)));
drawArea.Children.Add(new Label
{
Width = labelSize.Width,
Height = labelSize.Height,
Margin = new Thickness(
axePositionX - miniLineExtent - labelSize.Width,
(maximumY - i) * factorY - (labelSize.Height / 2), 0, 0),
Content = i,
Foreground = Brushes.Black
});
}
var path = new Path
{
StrokeThickness = 2,
Stroke = Brushes.DarkRed,
Data = geometryGroup
};
drawArea.Children.Add(path);
}
private void PlotGraph(Point[] points, Panel drawArea, int minimumX, int maximumX, int minimumY, int maximumY)
{
var factorX = drawArea.ActualWidth / (maximumX-minimumX);
var factorY = drawArea.ActualHeight / (maximumY-minimumY);
for (var i = 0; i < points.Length; i )
{
points[i].X *= factorX;
//points[i].Y *= factorY;
points[i].Y = (maximumY - points[i].Y) * factorY; //since zero of Y should be in bottom we "swap" the Y value.
}
Polyline polyline = new Polyline();
polyline.StrokeThickness = 2;
polyline.Stroke = Brushes.Blue;
polyline.Points = new PointCollection(points);
drawArea.Children.Add(polyline);
}
private void GenerateGraphBtn_Click(object sender, RoutedEventArgs e)
{
//Step 1: define the data limits and generate the data, this has nothing to do with the view.
const int xmin = 0, xmax = 12;
const int ymin = 0, ymax = 800;
var graphPoints = GenerateGraphPoints(xmin, xmax, ymin, ymax);
//Step 2: Draw yAxes
PlotYAxes(GrpahArea, ymin, ymax, 100, 2);
//Step 3: Draw xAxes
PlotXAxes(GrpahArea, xmin, xmax, 1, 2);
//Step 4: Plot Grpah
var plotPoints = new Point[graphPoints.Length]; //graphPoints is our model, we usually wish to keep the original value of model.
graphPoints.CopyTo(plotPoints,0); //plotPoints is what we going to scale and adjust to the view.
PlotGraph(plotPoints, GrpahArea, xmin, xmax, ymin, ymax);
}
}
}
Now to the 2nd part of my answer, Building a graph component is not that simple task, mostly since graphs are usually developed as generic to many applications, so the amount of allowed customization need to be enormous, this is why the others rightfully directed you to a ready library.
Also, the code I provided you in the answer is not MVVM style, it is very near to the code you provided. This is since writing that in MVVM-style will require creating a set of view model classes and bind them to the view, considering the customizations, it is quite an effort compared to what you asked to resolve.
Nevertheless I hope the code provided can help you do whatever you wanted.
Update, adding labels:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace WpfApp2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private Point[] GenerateGraphPoints(int minimumX, int maximumX, int minimumY, int maximumY)
{
var result = new List<Point>();
var rnd = new Random();
for (var x = minimumX; x < maximumX; x )
result.Add(new Point(x, rnd.Next(minimumY, maximumY)));
return result.ToArray();
}
private void PlotXAxes(Panel drawArea, int minimumX, int maximumX, int step, int miniLineExtent, string title)
{
var geometryGroup = new GeometryGroup();
var axePositionY = drawArea.ActualHeight;
geometryGroup.Children.Add(new LineGeometry(new Point(0, axePositionY), new Point(drawArea.ActualWidth, axePositionY)));
var factorX = drawArea.ActualWidth / (maximumX - minimumX);
for (var i = minimumX; i < maximumX; i )
if (i % step == 0)
{
geometryGroup.Children.Add(new LineGeometry(
new Point(i * factorX, axePositionY - miniLineExtent),
new Point(i * factorX, axePositionY miniLineExtent)));
drawArea.Children.Add(new Label
{
Margin = new Thickness(i*factorX, axePositionY miniLineExtent, 0, 0),
Content = i,
Foreground = Brushes.Black
});
}
var path = new Path
{
StrokeThickness = 2,
Stroke = Brushes.DarkRed,
Data = geometryGroup
};
drawArea.Children.Add(path);
var titleLabel = new Label
{
Margin = new Thickness(drawArea.ActualWidth - 50, drawArea.ActualHeight - 20, 0, 0),
Content = title
};
drawArea.Children.Add(titleLabel);
}
private void PlotYAxes(Panel drawArea, int minimumY, int maximumY, int step, int miniLineExtent, string title)
{
var labelSize = new Size(30, 26);
var geometryGroup = new GeometryGroup();
var axePositionX = 0;
geometryGroup.Children.Add(new LineGeometry(new Point(axePositionX, 0), new Point(axePositionX, drawArea.ActualHeight)));
var factorY = drawArea.ActualHeight / (maximumY - minimumY);
for (var i = minimumY; i < maximumY; i )
if (i % step == 0)
{
geometryGroup.Children.Add(new LineGeometry(
new Point(axePositionX - miniLineExtent, (maximumY-i) * factorY),
new Point(axePositionX miniLineExtent, (maximumY-i) * factorY)));
drawArea.Children.Add(new Label
{
Width = labelSize.Width,
Height = labelSize.Height,
Margin = new Thickness(
axePositionX - miniLineExtent - labelSize.Width,
(maximumY - i) * factorY - (labelSize.Height / 2), 0, 0),
Content = i,
Foreground = Brushes.Black
});
}
var path = new Path
{
StrokeThickness = 2,
Stroke = Brushes.DarkRed,
Data = geometryGroup
};
drawArea.Children.Add(path);
var titleLabel = new Label
{
Margin = new Thickness(0, 0, 0, 0),
Content = title
};
drawArea.Children.Add(titleLabel);
}
private void PlotGraph(Point[] points, Panel drawArea, int minimumX, int maximumX, int minimumY, int maximumY)
{
var factorX = drawArea.ActualWidth / (maximumX-minimumX);
var factorY = drawArea.ActualHeight / (maximumY-minimumY);
for (var i = 0; i < points.Length; i )
{
points[i].X *= factorX;
//points[i].Y *= factorY;
points[i].Y = (maximumY - points[i].Y) * factorY; //since zero of Y should be in bottom we "swap" the Y value.
}
Polyline polyline = new Polyline();
polyline.StrokeThickness = 2;
polyline.Stroke = Brushes.Blue;
polyline.Points = new PointCollection(points);
drawArea.Children.Add(polyline);
}
private void GenerateGraphBtn_Click(object sender, RoutedEventArgs e)
{
//Step 1: define the data limits and generate the data, this has nothing to do with the view.
const int xmin = 0, xmax = 12;
const int ymin = 0, ymax = 800;
var graphPoints = GenerateGraphPoints(xmin, xmax, ymin, ymax);
GrpahArea.Children.Add(new Label
{
Content = "Profits over months",
Margin = new Thickness(GrpahArea.ActualWidth / 2 - 100, -50, 0, 0)
});
//Step 2: Draw yAxes
PlotYAxes(GrpahArea, ymin, ymax, 100, 2, "Profits");
//Step 3: Draw xAxes
PlotXAxes(GrpahArea, xmin, xmax, 1, 2, "Months");
//Step 4: Plot Grpah
var plotPoints = new Point[graphPoints.Length]; //graphPoints is our model, we usually wish to keep the original value of model.
graphPoints.CopyTo(plotPoints,0); //plotPoints is what we going to scale and adjust to the view.
PlotGraph(plotPoints, GrpahArea, xmin, xmax, ymin, ymax);
}
}
}