Unable to display 2D chart correctly with Teechart on Monotouch - xamarin.ios

Having fun evaluating Teechart for .NET Monotouch for iOS. Run into several problems that cannot solve. Basically I am trying to present a 2D bar chart with two or three series with up to 24 data points.
Here is my test code
chart3.Aspect.View3D = false;
chart3.Legend.Visible = false;
chart3.Chart.Aspect.ZoomScrollStyle = Steema.TeeChart.Drawing.Aspect.ZoomScrollStyles.Auto;
Axis left=chart3.Axes.Left;
left.Grid.Visible = false;
left.Automatic=false;
left.Minimum=0;
left.Maximum=20;
left.Increment=1;
Axis bottom=chart3.Axes.Bottom;
bottom.Visible=true;
bottom.Grid.Visible = false;
Steema.TeeChart.Styles.Bar bar1=new Steema.TeeChart.Styles.Bar();
chart3.Series.Add(bar1);
bar1.Add(12.0,"Jun 2012");
bar1.Add(8.0,"Jul 2012");
bar1.Add(0.5,"Aug 2012");
bar1.Add(6.7,"Sep 2012");
bar1.Pen.Width = 0;
bar1.Gradient.Visible = true;
bar1.GetSeriesMark += (series, e) => {object v=series.YValues[e.ValueIndex]; e.MarkText=""+v;};
Steema.TeeChart.Styles.Bar bar2=new Steema.TeeChart.Styles.Bar();
chart3.Series.Add(bar2);
bar2.Add(8.0,"Jun 2012");
bar2.Add(5.0,"Jul 2012");
bar2.Add(5.0,"Aug 2012");
bar2.Add(14.0,"Sep 2012");
bar2.Pen.Width = 0;
bar2.Gradient.Visible = true;
bar2.GetSeriesMark += (series, e) => {object v=series.YValues[e.ValueIndex]; e.MarkText=""+v;};
Above code creates two 2D bar style series with four points.
Here is the result I am getting
The major problem is that all bars are floating 0.5 point above zero (notice 8.5 on the left axis where value is 8). Scrolling up shows this
Second issue I am facing is that the library doesn't take into consideration Maximum value set for the last axis.
If I set Aspect.View3D to true that chart looks much better
3D comes with its own set of issues but we need 2D anyway.
My question is: what I am doing wrong?

yes, you're correct. I can reproduce the problem here.
A fix will be included into the next maintenance release which will be available soon.
In meantime, a workaround would be to set to Manual the ZoomScroll style, which makes to use the default zoom and scroll of the TeeChart library :
Code :
_controller.chart.Chart.Aspect.ZoomScrollStyle = Steema.TeeChart.Drawing.Aspect.ZoomScrollStyles.Manual

Related

SVG getScreenCTM() on FireFox

GOAL
I am trying to build a signature pad in SVG. You can view
Sample project here.
Description
So far, it works in Chrome, Edge and Opera as desired but, in Firefox, getScreenCTM() doesn't account for the scale.
Research
I went through a bunch of documentation from bugzilla and a couple of posts here in SO such as SVG: GetScreenCTM() for nested SVG is different in Firefox but, still couldn't figure out how to fix my issue.
Problem
I've added a browse check to handle only Firefox (since all other browsers provides the desired result) which allows me to add extra code to fix the problem but, thus far, had no success. (SPSignature:416)
Reproduce the error
To reproduce the error, open the sample link in FireFox than, resize the box so it is at least 20% smaller as in fullscreen. You will see the mouseX/Y position change as scale changes.
I've tried to get the matrix transform from the group tag but, it returns similar result from the SVG. How do I calculate the CTM, so its result is similar/equal to Chrome?
Code
Source code here SPSignature:416
_getCursorPoint(event)
{
const svg = document.querySelector('.spsignature svg');
let pt = svg.createSVGPoint();
pt.x = event.clientX;
pt.y = event.clientY;
// firefox workaround:
if (this._checkBrowser() === 'Firefox') {
const matrix = this._decomposeMatrix(svg.getScreenCTM());
let cood = {
x: event.layerX,
y: event.layerY
};
if (matrix.scaleX < 0.9 || matrix.scaleY < 0.9) {
console.log('%c #todo: fix mouse position for FF on getScreenCTM().', 'background:#c00;color:#fff;padding:3px;');
}
return cood;
}
return pt.matrixTransform(svg.getScreenCTM().inverse());
}
To "fix" the mouse XY problem on FF, I've used the root scale value to allow for the calculation of the cursor XY position.
The scale can be retrieved from the matrix based on https://gist.github.com/2052247.
Also, in FF, I've used the event.layerX and event.layerY instead of event.clientX and event.clientY for the initial mouse coordinate values.
So, instead of using matrixTransform(svg.getScreenCTM().inverse()) to return the calculated XY relative to the SVG, I've used the scale and layerXY to calculate the right XY position.

How to flip axes and show it zoomed in for LineGraph MPAndroidchart

I'm not sure how to flip the axes of my chart. Below is the code I'm using.
Please see also the picture on how it looks right now. Instead of drawing the data vertically I'd like to show it horizontally. It suppose to look like a stock chart because that is what it actually is. I'm using YQL to get the historical data of the symbol as Json format.
I also see the data is scooped in the whole screen. I'd like to see the last month for example and just allow the user to swipe to the right for more or just to zoom out.
I'd appreciate some help.
float vals=0;
String[] resultStrs = new String[StockHistoryArray.length()];
for (int i = 0; i < StockHistoryArray.length(); i++) {
JSONObject chartDataObj = StockHistoryArray.getJSONObject(i);
yVals.add(new Entry(vals,(int) Float.parseFloat(chartDataObj.getString("Adj_Close")),i+1));
xVals.add(i, String.valueOf(vals));
vals++;
}
LineDataSet setting = new LineDataSet(yVals, "Stock Chart");
ArrayList<ILineDataSet> dataSets = new
ArrayList<ILineDataSet>();
dataSets.add(setting);
LineData data = new LineData(xVals, dataSets);
lineChart.setData(data);
Legend l = lineChart.getLegend();
l.setForm(Legend.LegendForm.LINE);
l.setTextColor(Color.WHITE);
XAxis x1 = lineChart.getXAxis();
x1.setTextColor(Color.WHITE);
x1.setDrawGridLines(false);
x1.setAvoidFirstLastClipping(true);
YAxis y1 = lineChart.getAxisLeft();
y1.setTextColor(Color.WHITE);
y1.setAxisMaxValue(120f);
y1.setDrawGridLines(true);
return null;
Here is the screen shot after I run this code. It is one year history.
screen capture
You are doing wrong in the following line.
yVals.add(new Entry(vals,(int) Float.parseFloat(chartDataObj.getString("Adj_Close")),i+1));
Use like this to draw the chart correctly
yVals.add(new Entry(entryVal,entryXIndex);
If your value in chartDataObj.getString("Adj_Close")
then you need to add like this
yVals.add(new Entry(Float.parseFloat(chartDataObj.getString("Adj_Close")), i);

Dynamically selecting JavaFX LIneChart symbol colors

I have a JavaFX app which contains a line chart. I want users to be able to select the color of each series in the chart. Since the selection is dynamic I can't use static CSS to set the colors. I also have other controls that I need to set to the same color as the associated series. It's possible to set the line color of a series dynamically using code like this:
series.getNode().setStyle("-fx-stroke: " + color + ";");
That works well and I can use the user-specified color on the associated controls.
My problem is that I also need to set the color of the symbols for each series to the same color. I can't find any way to do that dynamically. All of the tutorials, documentation, and posts that I've read on the topic point to the static CSS approach.
Most charting widgets make this sort of thing very easy to do, but I've found no clues here or on the Oracle forums. Any guidance would be greatly appreciated.
-- Update --
I've found no way to do this other than to enumerate every data point in every series, grab the associated symbol node and set the style individually. Not what I was hoping for. In the process I realized that the default Node allocated for a symbol is a StackPane. I didn't need that flexibility so I replaced it with a Rectangle. This made rendering faster.
I'm late to the game, but maybe someone can use my solution. What worked for me, was iterating through every item in the data series and setting the CSS style for each one.
for (int index = 0; index < series.getData().size(); index++) {
XYChart.Data dataPoint = series.getData().get(index);
Node lineSymbol = dataPoint.getNode().lookup(".chart-line-symbol");
lineSymbol.setStyle("-fx-background-color: #00ff00, #000000; -fx-background-insets: 0, 2;\n" +
" -fx-background-radius: 3px;\n" +
" -fx-padding: 3px;");
}
I was stuck with a similar problem. I don't know upfront which data is going to be added to the graph, so I can't make use of a fixed stylesheet.
I came up with this solution. This code listens for new series added to graph. For every added series, it will create a new listener for data added to the series.
This listener will look up which series this is, the 0th, 1st, etc and then find the two nodes for the coloring of the line and of the legend/symbol.
As soon as it has set both, it can unsubscribe.
Problem can be that the legend/symbol node is not available yet when you receive the callback on the first added datapoint.
I'm aware it's very convoluted and I'm open to hear improvements.
At least it will give you the option to dynamically set the color to anything you want.
final LineChart<Number, Number> chart = new LineChart<>(new NumberAxis(), new NumberAxis());
final ObservableList<Series<Number, Number>> series = chart.getData();
series.addListener(new ListChangeListener<Series<Number, Number>>() {
#Override
public void onChanged(Change<? extends Series<Number, Number>> change) {
ObservableList<? extends Series<Number, Number>> list = change.getList();
for (final Series<Number, Number> serie : list) {
serie.getData().addListener(new ListChangeListener<Data<Number, Number>>() {
#Override
public void onChanged(Change<? extends Data<Number, Number>> ignore) {
int index = series.indexOf(serie);
Set<Node> nodes = chart.lookupAll(".series" + index);
boolean isStyleSet = false;
for (Node n : nodes) {
if (StringUtils.isEmpty(n.getStyle())) {
String css = "-fx-stroke: %s; -fx-background-color: %s, white; ";
String color = //assign dynamically here, for instance based on the name of the series
n.setStyle(String.format(css, color, color));
isStyleSet = true;
}
}
if (!isStyleSet & nodes.size() > 1) {
serie.getData().removeListener(this);
}
}
});
}
}
});
I had a problem which might be slightly different (possibly more complex); I needed to style some nodes of a series one color, others within the same series another color (I also needed to be able to change the allocation of color dynamically). I am working in JavaFx 2.2; I have css-styling, but of course that does not help here. I could not find my issue addressed anywhere; this was the closest I've found.
I just want to say that I could not get "series.getNode().setStyle("-fx-stroke: " + color + ";")" to work. However, using "-fx-background" instead does work. I hope this helps someone.

EPPlus Barchart bars not showing colors for negative value in Excel 2013, but works fine in Excel 2007

I am using a BarClustered chart using EPPlus for Excel Package in C#. I am able to generate the bar chart as required. Only problem I am facing is that when I have a negative value, the bar does not show any color. It would be as if a transparent bar with only the border.
I am facing this issue with Excel 2013. However this works fine in Excel 2007.
ExcelWorksheet wsDataSource = xlPackage.Workbook.Worksheets.Add("DataSource");
wsDataSource.Hidden = eWorkSheetHidden.VeryHidden;
var namedStyle = xlPackage.Workbook.Styles.CreateNamedStyle("HyperLink");
namedStyle.Style.Font.UnderLine = true;
namedStyle.Style.Font.Color.SetColor(Color.Blue);
//Here I iterate through an array and populate the wsDataSource values as below starting from 3rd row:
Feb 2000 5000
March -2000 2770
April 4000 4643
var chart = worksheet.Drawings.AddChart("Chart", OfficeOpenXml.Drawing.Chart.eChartType.BarClustered);
//row is the offset int variable
chart.SetPosition(row + 2, 0, 0, 10);
chart.SetSize(750, 30);
chart.Title.Text = "Data Graph";
chart.Legend.Position = eLegendPosition.Top;
var barChart = chart as ExcelBarChart;
barChart.DataLabel.ShowValue = true;
var mySeries = chart.Series.Add(wsDataSource.Cells[3, 2, intDataRow - 1, 2], wsDataSource.Cells[3, 1, intDataRow - 1, 1]);
mySeries.Header = "Current Year";
//isPreviousYearDataAvailable is a boolean which indicates if previous year data for the user is available.
if (isPreviousYearDataAvailable)
{
var mySeries2 = chart.Series.Add(wsDataSource.Cells[3, 3, intDataRow, 3], wsDataSource.Cells[3, 1, intDataRow - 1, 1]);
mySeries2.Header = "Previous Year"
}
Below is the image I get for negative values when opening using Excel 2013.
It appears that EPPlus doesn't have support for the "invertIfNegative" tag for data series. You might have to contact the authors for help, or add in the feature yourself. The Open XML specs state that:
This element specifies the parent element shall invert its colors if the value is negative.
Also:
A value of on, 1, or true specifies that the property is applied. This is the default value for this attribute, and is implied when the parent element is present, but this attribute is omitted.
Since EPPlus doesn't render this tag, the default value is used, which is "true". The "parent element" in this case is the data series XML element. So this means colors will be inverted if the cell value is negative. Hence the transparent color you see.
I have found that different versions of Excel obey the Open XML specs slightly differently. Excel 2013 appears to obey more strictly to the Open XML specs, which is why you get a transparent color. Excel 2007 probably ignored the absent "invertIfNegative" tag (meaning if absent, you don't want to have anything to do with inverting colors and so on, and so Excel will just render the color). In this sense, Excel 2007 is more forgiving of mistakes, which may or may not be a good thing.
Adding <c:invertIfNegative val="0"/> to the XML manually seemed to work for me:
System.Xml.XmlNode invertIfNegativeNode = chart.ChartXml.CreateElement(
"c", "invertIfNegative", "http://schemas.openxmlformats.org/drawingml/2006/chart");
System.Xml.XmlAttribute invertIfNegativeAttribute = chart.ChartXml.CreateAttribute("val");
invertIfNegativeAttribute.Value = "0";
invertIfNegativeNode.Attributes.Append(invertIfNegativeAttribute);
chart.ChartXml.DocumentElement["c:chart"]["c:plotArea"]["c:barChart"]["ser"].AppendChild(invertIfNegativeNode);
Adding to this old post, I hit the same problem in Excel 2016 but was unable to resolve it with #Saxon Druce answer directly. When I examine chart1.xml behind the Excel, only ser contains invertIfNegative and setting it's val attribute to 0 does not apply to any bar (still remain inverted / transparent). When I open the file in Excel and uncheck Series Option/Invert if negative option and reopen chart1.xml, I found each and every bar dPt is inject with invertIfNegative node.
So I modified #Saxon Druce answer a bit, create and append invertIfNegative node to each bar's dPt (2nd arrow) instead of appending to parent node ser (1st arrow). Then the ExcelBarChart turns out ok with all bars colored (not inverted).
I banged my head for hours so hopefully this help someone with Excel 2016.
var nsuri = chartXml.DocumentElement.NamespaceURI;
var dPt = chartXml.CreateNode(XmlNodeType.Element, "dPt", nsuri);
var invertIfNegative = chartXml.CreateNode(XmlNodeType.Element, "invertIfNegative", nsuri);
var att = chartXml.CreateAttribute("val", nsuri);
att.Value = "0";
invertIfNegative.Attributes.Append(att);
dPt.AppendChild(invertIfNegative);
// Other xml changes
var idx = chartXml.CreateNode(XmlNodeType.Element, "idx", nsuri);
att = chartXml.CreateAttribute("val", nsuri);
att.Value = i.ToString();
idx.Attributes.Append(att);
dPt.AppendChild(idx);

Flot pie charts - externally selecting slices

I found this solution.
If type of chart is pie, how specify parameters (x,y) of highlight(x, y)?
Thanks
Sorry for my bad English.
Unfortunately, flot doesn't expose the pie highlighting code to the user. So we are pretty much out of luck, but what may work for you is synthesizing a click event at the appropriate place on the page:
$("#highligher").click(function () {
var e = jQuery.Event('click');
e.pageX = 250; //add a made up x/y coordinate to the click event
e.pageY = 250;
$('#plot canvas:first').trigger(e); //trigger the click event on the canvas
});
Here it is in action: http://jsfiddle.net/ryleyb/mHJm5/
The problem is you have to know where the slice you want to highlight is already. This would be easy enough to set if the graph is static. If it's a dynamic graph, you'd have to dig into the source of the pie code to figure out how to calculate where the pie slice is. It might be easier in that case to just have a copy of all the pie functions and manually draw on the pie overlay.
Just got this working by altering a few things...
I changed highlight and unhighlight in jquery.flot.pie.js to pieHighlight and pieUnhighlight.
Then, after these two lines in jquery.flot.pie.js...
plot.hooks.processOptions.push(function(plot, options) {
if (options.series.pie.show) {
I added...
plot.highlight = pieHighlight;
plot.unhighlight = pieUnhighlight;
We're maintaining selection state outside of the chart (as a backbone model). When a selection event (click) occurs, we set the selected slice in the model. When selection changes, we refresh the chart using a selection color for the pie slices that are selected.
var data = [];
var color = slice.index == selected ? '#FF0000' : '#0000FF';
data.push({label:slice.Label,data:slice.Value,color:color});
The snippet above uses blue for all non-selected slices, red for the selected slice. Your color logic will be more sophisticated.
NOTE: You can also use rgba CSS for the colors, which gives a really nice effect. For example:
var color = slice.index == selected ? 'rgba(0,0,255,1)' : 'rgba(0,0,255,0.5)';

Resources