OxyPlot: How to calculate in TrackerFormatString? - oxyplot

I try to create a line series where not only x- and y-values shall be displayed in the tracker, but one more property:
var series = new LineSeries {TrackerFormatString = "X:{2}\nY:{4}\nZ:{2*(1-4)}"};
series.Points.AddRange(...);
I want another property Z = (1-Y) * X to be displayed in the third row of the tracker. How is this possible?

It is possible by creating a custom
public class CustomDataPoint : IDataPointProvider
{
public double X { get; }
public double Y { get; }
public double Z{ get; }
public CustomDataPoint(double x, double y)
{
X = x;
Y = y;
Z = (1 - Y) * X;
}
public DataPoint GetDataPoint()
{
return new DataPoint(X, Y);
}
}
And then add it to the series:
var series = new LineSeries {TrackerFormatString = "X:{2}\nY:{4}\nZ:{Z}"};
series.ItemsSource = new [] {
new CustomDataPoint(...),
new CustomDataPoint(...)
};
Note that you need to use the ItemsSource property. You cannot simply add points with series.Point.AddRange(...).

Related

my code is only drawing a straight line no matter how many sides i input in the pSides JTextFields

When I input a digit in the JTextfields it should pass through my actionListener to store all the values (ID, number of sides, length of sides and color) into an arraylist. It should then be used in my polygonContainer class that goes through a for loop and a polygon formula, then prints it out. However what comes out all the time is a straight line.
This is the code i tried:
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class ContainerFrame extends JFrame{
ArrayList<PolygonContainer> polygons = new ArrayList<>();
// JTextFields for the number of sides, side length, color, and ID
public JTextField pSides, pSidesLengths, pColor, pID;
// Button for submission
public JButton submitButton;
public void createComponents() {
// Initialize the JTextFields
pSides = new JTextField();
pSidesLengths = new JTextField();
pColor = new JTextField();
pID = new JTextField();
submitButton = new JButton("Submit");
submitButton.addActionListener(new ContainerButtonHandler(this));
JPanel textFieldsPanel = new JPanel();
// uses a gridlayout to organise the textfields then sets it as north
textFieldsPanel.setLayout(new GridLayout(5, 2));
textFieldsPanel.add(new JLabel("Sides:"));
textFieldsPanel.add(pSides);
textFieldsPanel.add(new JLabel("Sides Length:"));
textFieldsPanel.add(pSidesLengths);
textFieldsPanel.add(new JLabel("Color:"));
textFieldsPanel.add(pColor);
textFieldsPanel.add(new JLabel("ID:"));
textFieldsPanel.add(pID);
add(textFieldsPanel, BorderLayout.NORTH);
add(submitButton, BorderLayout.SOUTH);
JPanel drawPanel = new ContainerPanel(this);
add(drawPanel, BorderLayout.CENTER);
setSize(1600, 900);
setVisible(true);
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); // Close action.
}
public static void main(String[] args) {
ContainerFrame cFrame = new ContainerFrame();
cFrame.createComponents();
}
}
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
class ContainerButtonHandler implements ActionListener {
ContainerFrame theApp; // Reference to ContainerFrame object
// ButtonHandler constructor
ContainerButtonHandler(ContainerFrame app) {
theApp = app;
}
public void actionPerformed(ActionEvent e) {
// Get the text from the JTextFields using the getText method
String sides = theApp.pSides.getText();
String sidesLengths = theApp.pSidesLengths.getText();
String id = theApp.pID.getText();
//parse the values as integers
int intSides = Integer.parseInt(sides);
int intSidesLength = Integer.parseInt(sidesLengths);
int intId = Integer.parseInt(id);
//does the input validation where sides, sides length and id needs to be positive integers
if (intId >= 100000 && intId <= 999999 && intSides >= 0 && intSidesLength >= 0) {
// The inputs are valid
String color = theApp.pColor.getText();
// Store the values in an arraylist or other data structure
ArrayList<String> polygonArray = new ArrayList<String>();
polygonArray.add(sides);
polygonArray.add(sidesLengths);
polygonArray.add(color);
polygonArray.add(id);
PolygonContainer polygon = new PolygonContainer(polygonArray);
theApp.polygons.add(polygon);
theApp.repaint();
JOptionPane.showMessageDialog(theApp, "Polygon" + id + "was added to the list.", "Success", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(theApp, "The Polygon" + id + "was not added to the list as a valid Id was not provided.", "Error", JOptionPane.ERROR_MESSAGE);
}
}
}
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
public class PolygonContainer implements Comparable<PolygonContainer>{
Color pColor = Color.BLACK; // Colour of the polygon, set to a Colour object, default set to black
int pId = 000000; // Polygon ID should be a six digit non-negative integer
int pSides; // Number of sides of the polygon, should be non-negative value
int pSideLengths; // Length of each side in pixels of the polygon, should be non-negative value
int polyCenX; // x value of centre point (pixel) of polygon when drawn on the panel
int polyCenY; // y value of centre point (pixel of polygon when drawn on the panel
int [] pointsX; // int array containing x values of each vertex (corner point) of the polygon
int [] pointsY; // int array containing y values of each vertex (corner point) of the polygon
// Constructor currently set the number of sides and the equal length of each side of the Polygon
//Constructor that takes the values from the array
public PolygonContainer(ArrayList<String> values){
this.pSides = Integer.parseInt(values.get(0));
this.pSideLengths = Integer.parseInt(values.get(1));
this.pColor = Color.getColor(values.get(2));
this.pId = Integer.parseInt(values.get(3));
pointsX = new int[pSides];
pointsY = new int[pSides];
}
// Used to populate the points array with the vertices corners (points) and construct a polygon with the
// number of sides defined by pSides and the length of each side defined by pSideLength.
// Dimension object that is passed in as an argument is used to get the width and height of the ContainerPanel
// and used to determine the x and y values of its centre point that will be used to position the drawn Polygon.
public Polygon getPolygonPoints(Dimension dim) {
polyCenX = dim.width / 2; // x value of centre point of the polygon
polyCenY = dim.height / 2; // y value of centre point of the polygon
Polygon p = new Polygon();
for (int i = 0; i < pSides; i++) {
// Calculate the x and y coordinates of the ith point of the polygon
int x = polyCenX + pSideLengths * (int) Math.cos(2.0 * Math.PI * i / pSides);
int y = polyCenY + pSideLengths * (int) Math.sin(2.0 * Math.PI * i / pSides);
// Add the x and y coordinates to the pointsX and pointsY arrays
pointsX[i] = x;
pointsY[i] = y;
// Add the point to the polygon object using the addPoint method
p.addPoint(x, y);
}
return p;
}
// You will need to modify this method to set the colour of the Polygon to be drawn
// Remember that Graphics2D has a setColor() method available for this purpose
public void drawPolygon(Graphics2D g, Dimension d) {
//Set color of polygon
g.setColor(pColor);
Polygon p = getPolygonPoints(d);
g.draw(p);
//this creates a bounding box around the polygon
Rectangle2D bounds = p.getBounds2D();
g.draw(bounds);
}
// gets a stored ID
public int getID() {
return pId;
}
#Override
// method used for comparing PolygonContainer objects based on stored ids, you need to complete the method
public int compareTo(PolygonContainer o) {
return 0;
}
// outputs a string representation of the PolygonContainer object, you need to complete this to use for testing
public String toString()
{
return "";
}
}
import javax.swing.JPanel;
import java.awt.*;
public class ContainerPanel extends JPanel{
ContainerFrame conFrame;
public ContainerPanel(ContainerFrame cf) {
conFrame = cf; // reference to ContainerFrame object
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D comp = (Graphics2D)g; // You will need to use a Graphics2D objects for this
Dimension size = getSize(); // You will need to use this Dimension object to get
// the width / height of the JPanel in which the
// Polygon is going to be drawn
for (PolygonContainer polygon : conFrame.polygons) {
polygon.drawPolygon(comp, size);
}
}
}
JFrame

Creating a class with implicit operators but it only works one way

A UDouble is an object that has units associated with the value (Value). The Unit is much more complex than shown here, but was converted to a string for the example.
public class UDouble
{
public string Unit { get; set; }
public double Value;
public UDouble(string unit)
{
Unit = unit;
}
public UDouble(string unit, double value)
{
Unit = unit;
Value = value;
}
public static implicit operator double(UDouble m)
{
return m.Value;
}
//public static implicit operator UDouble(double d)
//{
// return new UDouble("?????????", d); // wrong - units are lost
//}
}
static void Main()
{
UDouble p = new UDouble("mm", 2.3);
p.Value = 3;
double t = p;
p = 10.5;
}
The last line in the main() function (p = 10.5;) does not compile. What I what is the UDouble to act as if it is a double. In other words, I am trying to get p = 10.5; to work like p.Value = 10.5;
Is there a way to make it work?

How to create kendo pie chart with model in MVC

I am trying to create a Pie chart through model and controller in MVC using Kendo UI which will show the total for two types of food but I am not able to get the results due to the attached error.
Types to show in pie chart:
1)Beverages and
2)Meals
I am referring to this kind of Chart.
Kendo UI Pie chart
This link has shown multiple graphs using foreach but I am just concerned with only single chart that will differentiate the total earnings from Meals and Beverages.
My controller is:
public ActionResult _SpainElectricityProduction()
{
List<PieGraphModel> objList = new List<PieGraphModel>();
for (int i = 0; i < 2; i++)
{
if (i == 0)
{
objList.Add(new PieGraphModel { coke = 10, pepsi = 20, Type = "Beverages", total = 30 });
}
else
{
objList.Add(new PieGraphModel { chiniese = 50, italian = 40, Type = "Meals", total = 90 });
}
}
return Json(objList);
}
#(Html.Kendo().Chart<MvcRepo_Kendo.Models.PieGraphModel>()
.Name("chart")
.HtmlAttributes(new { #class = "small-chart" })
.Legend(legend => legend
.Visible(false)
)
.DataSource(ds =>
{
ds.Read(read => read.Action("_SpainElectricityProduction", "Home"));
}
)
.Series(series => series
.Pie(model => model.total)
.Padding(0)
)
.Tooltip(tooltip => tooltip
.Visible(true)
.Format("{0:N0}")
.Template("#= category # - #= kendo.format('{0:P}', percentage)#")
)
)
The Kendo method for generating a pie chart expects and array of objects, with each object representing one segment in the pie chart. Each object must contain a property for the value (the percentage that each segment will occupy in the whole) and the name of the segment. In addition, it can contain a property for the color (to override the default color) and a bool to indicate if the segment is 'exploded'.
Your PieGraphModel should look like (you can name the properties whatever you want)
public class PieGraphModel
{
public string Name { get; set; }
public float Value { get; set; }
public string Color { get; set; } // optional
public bool Explode { get; set; } // optional
}
and to create a pie chart with 2 segments, "Meals" and "Beverages", being 1/3 and 2/3 respectively, your controller method would be
List<PieGraphModel> model = new List<PieGraphModel>()
{
new PieGraphModel(){ Name = "Meals", Value = 33.33F },
new PieGraphModel(){ Name = "Beverages", Value = 66.67F }
};
return Json(model);
and in the view
.Series(series => series
.Pie(m => m.Value, m => m.Name)
.Padding(0)
)
Note that the expressions must match the names of the properties. If you also wanted to specify Color and Explode, the it would be
.Series(series => series
.Pie(m => m.Value, m => m.Name, m => m.Color, m => m.Explode)
.Padding(0)
)
which would output this pie chart if the data was
List<PieGraphModel> model = new List<PieGraphModel>()
{
new PieGraphModel(){ Name = "Hydro", Value = 22.0F, Color = "#03a9f4", Explode = true },
new PieGraphModel(){ Name = "Solar", Value = 2.0F, Color = "#ff9800"},
new PieGraphModel(){ Name = "Nuclear", Value = 49.0F, Color = "#fad84a"},
new PieGraphModel(){ Name = "Wind", Value = 27.0F, Color = "#4caf50"}
};

arrayList i only show the last element

I have the following problem. I'm trying to show all the elements of a display arrayList but I can only see the last item repeated as many times as there are number of elements in the ArrayList.
import java.util.ArrayList;
import java.util.Iterator;
public class PurebaArrayList {
public static void main(String[] args) {
ArrayList<PuntoDouble> puntos = new ArrayList<>();
PuntoDouble p = new PuntoDouble();
for(int cont = 0; cont< 100; cont++){
p.setX(cont);
p.setY(cont);
puntos.add(p);
}
System.out.println(puntos.toString());
}
}
public class PuntoDouble{
private double x;
private double y;
public PuntoDouble(double x, double y) {
this.x = x;
this.y = y;
}
public PuntoDouble(){
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
#Override
public String toString() {
return "PuntoDouble{" + "x=" + x + ", y=" + y + '}';
}
}
Thanks
You need to create a new PuntoDouble for every entry you add to the list. At the moment you add just a single instance of a PuntoDouble which you modify.
Therefore change the code to:
for(int cont = 0; cont< 100; cont++){
PuntoDouble p = new PuntoDouble();
p.setX(cont);
p.setY(cont);
puntos.add(p);
}
You are, literally, adding the same PuntoDouble as each of the 100 elements of the array. If you want them to be distinct from each other, you need to make a new one for each.
For debugging,slightly change 100 to 3 and add for each iteration to print out the elements in puntos.
// adds to ArrayList
for(int cont = 0; cont< 10; cont++){
p.setX(cont);
p.setY(cont);
System.out.println("[add]" + p);
puntos.add(p);
}
// iterates ArrayList puntos' elements
for(PuntoDouble pd : puntos){
System.out.println("[contain]" + pd);
}
debug output lines:
[add]PuntoDouble{x=0.0, y=0.0}
[add]PuntoDouble{x=1.0, y=1.0}
[add]PuntoDouble{x=2.0, y=2.0}
[add]PuntoDouble{x=3.0, y= 3.0}
[contain]PuntoDouble{x=9.0, y=9.0}
[contain]PuntoDouble{x=9.0, y=9.0}
[contain]PuntoDouble{x=9.0, y=9.0}
What you did is created an PuntoDouble object p and initilized it by invoking default constructor. In the for loop, the values of p modifies, but the reference of p never changed, therefore you kept adding the same object into ArrayList 100 times, all of those added objects refer to the same address in memory(new an object once before the for loop) which the value x is 99.0 and y is 99.0 (the last added values)
What you should do is creating a new object each iterate.
for(int cont = 0; cont< 100; cont++){
puntos.add(new PuntoDouble(cont, cont));
}

Centering DataTip (target) on a ColumnChart in Flex 3

How can I align a DataTip to the vertical center of the corresponding column? I've tried creating a custom dataTipRenderer, but it seems to me that there I can only move the datatip relative to the target (the circle graphic). But that position's just fine, I'd like to move the target itself.
My last idea is to set the showDataTipTargets style of the chart to false and draw the targets within the custom dataTipRenderer. I consider this a dirty hack, so if there's anything more friendly I'd go with that. Plus, in this case, how can I tell the column center coordinates in the datatip renderer's updateDisplayList function?
Hope this snippet of code would help ...
package As
{
import flash.display.*;
import flash.geom.Point;
import mx.charts.*;
import mx.charts.chartClasses.DataTip;
import mx.charts.series.ColumnSeries;
import mx.charts.series.items.ColumnSeriesItem;
public class MyDataTip extends DataTip
{
private var _xBaseLine:int=0;
private var _yBaseLine:int=0;
private var myX = 0
private var myY = 0
public function MyDataTip()
{
super();
}
override public function set data(arg1:Object):void {
var sMessage:String;
var pt:Point;
var hitData:HitData = mx.charts.HitData(arg1);
var chartItem = ColumnSeriesItem(hitData.chartItem);
var renderer = chartItem.itemRenderer;
var series = ColumnSeries(hitData.element);
var colName = chartItem.element.name
var pft = chartItem.xValue
if(renderer != null) {
myX = ( renderer.width / 2 )
myY = ( renderer.height/ 2 ) + ( this.height)
}
super.data=arg1;
}
override public function move (x:Number, y:Number):void {
// Adjusted
var pointAdjusted:Point = new Point(x + _xBaseLine, y + _yBaseLine);
// Call the parent
super.move(pointAdjusted.x, pointAdjusted.y);
}
override protected function updateDisplayList(w:Number, h:Number):void
{
super.updateDisplayList(w, h);
this.x = this.x + myX - 15
this.y = this.y + myY - 7
}
}
}
Cheers !! :)