Androidplot - Format PointLabel (remove decimals) on Bar Graph - androidplot

I have been searching for how to format the text (remove decimals) of point labels on Bar graph.
This is my code:
BarFormatter bf = new BarFormatter(Color.CYAN,Color.CYAN);
PointLabelFormatter plf = new PointLabelFormatter();
plf.getTextPaint().setColor(Color.BLUE);
bf.setPointLabelFormatter(plf);
i can only set the color here. The label is displayed with decimals. How to remove it or set a decimal format in this?
This comment https://stackoverflow.com/a/39482297/9969285 here describes pointlabeler under lineandpointformatter. How to implement this for a bar graph?

Should be the same as what you linked - BarFormatter extends LineAndPointFormatter:
bf.setPointLabeler(new PointLabeler<XYSeries>() {
final DecimalFormat df = new DecimalFormat("#");
#Override
public String getLabel(XYSeries series, int index) {
return df.format(series.getY(index));
}
});

Related

Line Chart in Trinidad

I want plot a line chart using Trinidad 1.2. I have a class called AcidenteTO which consists in int indicating the year and a array of int indicating the values for each month. In ChartModel used to populate my chart, I passed a List of AcidenteTO's.
public class AcidenteTO implements Serializable {
// -------------[ Atributos ]----------------------
private int ano; // year
private int[] quantidades = new int[12]; // quantities for month
// Getters & Setters as usual
}
public class AcidentesChartModel extends ChartModel {
private final List<AcidenteTO> acidentes;
// Indicate the labels for each year
private final List<String> anosLabel;
private List<List<Double>> yValues;
private final Double maxYValue;
// Month labels
private final List<String> mesesLabels =
Arrays.asList("Janeiro", "Fevereiro", "Março", "Abril", "Maio",
"Junho", "Julho", "Agosto", "Setembro", "Outubro",
"Novembro", "Dezembro");
AcidentesChartModel(List<AcidenteTO> acidentes) {
this.acidentes = acidentes;
yValues = new ArrayList<List<Double>>(this.acidentes.size());
List<String> anosLabel = new ArrayList<String>(this.acidentes.size());
this.anosLabel = new ArrayList<String>(this.acidentes.size());
double maxY = 0D;
for (AcidenteTO a : this.acidentes) {
maxY = preencherDados(a, maxY);
}
this.maxYValue = maxY;
}
private double preencherDados(AcidenteTO a, double maxY) {
List<Double> mesesValues = new ArrayList<Double>(12); // Monthly values for each year
for (int i = 0; i < 12; i++) {
mesesValues.add((double)a.getQuantidades()[i]);
if (a.getQuantidades()[i] > maxY) {
maxY = a.getQuantidades()[i];
}
}
this.anosLabel.add(String.valueOf(a.getAno()));
this.yValues.add(mesesValues);
return maxY;
}
public List<String> getSeriesLabels() {
return this.anosLabel;
}
public List<String> getGroupLabels() {
return this.mesesLabels;
}
public List<List<Double>> getYValues() {
return this.yValues;
}
public Double getMaxYValue() {
return this.maxYValue;
}
}
What I was expecting is that as for each Year I have 12 data to plot, it would be plot all 12 values for each year. However what actually happened was the following: If I pass a List of 3 AcidenteTO's, the generated plot shows data until 3rd month. If I pass 4 AcidenteTO's List, the plot shows data until 4th month. 7 AcidenteTO's List, until 7th month (see picture below), and so on.
I could not found no example in the net showing how to use a ChartModel to create a Trinidad line chart. Just this one for pie charts. Therefore I was not able to discover where is my mistake.
Thanks,
Rafael Afonso.
Ever considered using Highcharts to generate graphs in your Trinidad project? We do and it works like a charm! Highcharts has way more possibilities to generate graphs and add interactivity then <tr:chart>. See these examples for pie charts and other graphs in Highcharts.
The downside is that you don't have a JSF component to work with. Creating a static graph will be easy, but you might want to write a few lines of code to pass your data to the Highcharts Javascript to get things a bit more interesting. Trinidad's ExtendedRenderKitService comes in handy there:
ExtendedRenderKitService service =
Service.getRenderKitService(facesContext, ExtendedRenderKitService.class);
service.addScript(facesContext, "alert('foo');");
Edit
I just found this, haven't tried it yet, but I will test it: Java API for generating highchart JSON.

Displaying javafx 2 linechart values on hover

I have been using this example for my project, and it works really nice.
My question: Is it possible to offset the hovered node such that it does not overlay the underlying data point. The example centers the hovered node right over the "normal" node. It kind of gets in the way on a chart with a lot of data points.
A simple solution is to set a custom translation to the displayed Label. The following code is extracted from the example.
private Label createDataThresholdLabel(int priorValue, int value)
{
final Label label = new Label(value + "");
label.setTranslateY(-25); //Move label 25 pixels up
label.getStyleClass().addAll("default-color0", "chart-line-symbol", "chart-series-line");
label.setStyle("-fx-font-size: 20; -fx-font-weight: bold;");
if (priorValue == 0)
{
label.setTextFill(Color.DARKGRAY);
}
else if (value > priorValue)
{
label.setTextFill(Color.FORESTGREEN);
}
else
{
label.setTextFill(Color.FIREBRICK);
}
label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
return label;
}

Test for Label overrun

I have a multiline label whose text has a chance of overrunning. If it does this, I want to decrease the font size until it isn't overrunning, or until it hits some minimum size. This would hopefully make it so that the label will change size until the entire string is visible.
My problem it that I am not sure how to test to see if the text has overrun. I have tried testing to see if the label's text ends with the ellipse string, but I believe the ellipse is not technically added to the textProperty of the label. So does anyone know of a good way to test for this?
The short and disappointing answer: You simply cannot do this in a reliable way.
The slightly longer answer is, that the label itself does not even know whether it's overflown or not. Whenever a label is resized, the skin class (LabeledSkinBase) is responsible for updating the displayed text. This class, however, uses a JavaFX utils class to compute the ellipsoided text. The problem here is that the respective method just returns a string that is ellipsoid if this is required by the label's dimensions. The skin itself never gets informed about whether the text was actually ellipsoided or not, it just updates the displayed text to the returned result.
What you could try is to check the displayed text of the skin class, but it's protected. So you would need to do is to subclass LabelSkin, and implement something like that:
package com.sun.javafx.scene.control.skin;
import java.lang.reflect.Field;
import javafx.scene.control.Label;
#SuppressWarnings("restriction")
public class TestLabel extends LabelSkin {
private LabeledText labelledText;
public TestLabel(Label label) throws Exception {
super(label);
for (Field field : LabeledSkinBase.class.getDeclaredFields()) {
if (field.getName().equals("text")) {
field.setAccessible(true);
labelledText = (LabeledText) field.get(this);
break;
}
}
}
public boolean isEllipsoided() {
return labelledText != null && labelledText.getText() != null && !getSkinnable().getText().equals(labelledText.getText());
}
}
If you use this skin for you Label, you should be able to detect whether your text is ellipsoided. If you wonder about the loop and the reflection: Java didn't allow me to access the text field by other means, so this may be a strong indicator that you really should not do this ;-) Nevertheless: It works!
Disclaimer: I've only checked for JavaFX 8
minisu posted a way to detect an overrun in this answer:
https://stackoverflow.com/a/15178908/9492864
This way works for all labeled and I tested it on Buttons with JavaFX 8.
You can add a listener for example to the needsLayoutProperty:
labeled.needsLayoutProperty().addListener((observable, oldValue, newValue) -> {
String originalString = labeled.getText();
Text textNode = (Text) labeled.lookup(".text"); // "text" is the style class of Text
String actualString = textNode.getText();
boolean clipped = !actualString.isEmpty() && !originalString.equals(actualString);
System.out.println("is " + originalString + " clipped: " + clipped);
});
This work for me !!
In javafx
public class LabelHelper{
public static boolean necesitaTooltip(Font font, Label label){
Text text = new Text(label.getText());
text.setFont(font);
Bounds tb = text.getBoundsInLocal();
Rectangle stencil = new Rectangle(
tb.getMinX(), tb.getMinY(), tb.getWidth(), tb.getHeight()
);
Shape intersection = Shape.intersect(text, stencil);
Bounds ib = intersection.getBoundsInLocal();
return ib.getWidth() > label.getPrefWidth();
}
public static void asignarTexto(Label label, String texto){
label.setText(texto);
if (necesitaTooltip(label.getFont(), label)){
Tooltip tp = new Tooltip(texto);
label.setTooltip(tp);
}
}
}
Only call a asignarTexto(label, texto) for set text a label and check if the text is overrun in the label then add a tooltip for label.
It's already been mentioned by Johann that you can use (Text)labeled.lookup(".text") to get the actual displayed text for a Label, then compare it to the intended String... However, in my case, this did not work. Perhaps it was because I was updating the Label with a high frequency, but the actual String was always a few chars less than the intended...
So, I opted to use the setEllipsisString(String value) method to set the ellipsis string (what's appended to the end of a Label when there's overrun, the default being "...") to an (unused)
ASCII control character like 0x03 (appropriately named "end of text"), then after each time I set the Label text I check if the last char of the actual String is the control char.
Example using Platform.runLater(Runnable):
import javafx.scene.control.Label;
import javafx.application.Platform;
import javafx.scene.text.Text;
...
Label label = new Label();
...
label.setEllipsisString("\003");
...
final String newText = "fef foo";
Platform.runLater(() -> {
label.setText(newText);
String actual = ((Text)label.lookup(".text")).getText();
// \003 is octal for the aforementioned "end of text" control char
if (actual.length() > 0 && actual.charAt(actual.length()-1) == '\003') {
// Handle text now that you know it's clipped
}
});
Note that you can set the control char to anything really, and it doesn't need to be just one char; however if you opt for a control character, check that it isn't commonly used.

Javafx change PieChart color

I have a list of color representing a color sequence. I want to apply the new color sequence to the piechart data.
private final int CASPIAN_COLOR_COUNTS = 8;
public void setPieChartColor(PieChart chart, List<String> colors) {
chart.getData().get(i); // for debug to get the node name (.data)
/**
* Set Pie color
*/
int i = 0;
for (String color : colors) {
final Node node = chart.lookup(".data" + i);
node.getStyleClass().remove("default-color" + (i % CASPIAN_COLOR_COUNTS));
node.getStyleClass().add(color);
i++;
}
but all chart data take Only one color from Caspian color.
You can achieve custom pie colors in code using a method such as:
private void applyCustomColorSequence(
ObservableList<PieChart.Data> pieChartData,
String... pieColors) {
int i = 0;
for (PieChart.Data data : pieChartData) {
data.getNode().setStyle(
"-fx-pie-color: " + pieColors[i % pieColors.length] + ";"
);
i++;
}
}
Note that the method must be applied after the chart has been shown on an active scene (otherwise the data.getNode() call will return null).
Here is some sample code which uses it.
You can accomplish the same effect using css stylesheets.
For example a css stylesheet containing the following style definitions will change the default colors of a pie chart when the stylesheet is applied against a given chart.
.default-color0.chart-pie { -fx-pie-color: #ffd700; }
.default-color1.chart-pie { -fx-pie-color: #ffa500; }
.default-color2.chart-pie { -fx-pie-color: #860061; }
.default-color3.chart-pie { -fx-pie-color: #adff2f; }
.default-color4.chart-pie { -fx-pie-color: #ff5700; }
For an example of the stylesheet based approach: see the "Setting Colors of a Pie Chart" section of the Styling Charts with CSS tutorial.
The stylesheet approach has an advantage that the styles are separated from the code. It has the disadvantage that the colors are must be set the time the stylesheet are created rather than at runtime and the color sequence is restricted to a fixed number of colors (8).
In general, the stylesheet approach is recommended for most applications.
The css styles might not work if your values are negative. This might be a bug but I had to convert my values to positive values for the styles to work. When the values were negative all pies were white in color.

How to get the value of the x-axis when the mouse is clicked in time seires chart

I was using dynamic time chart.
Timeseries chart when the mouse is clicked I want to get the time value.
But the method I used was able to get the y-axis value.
How can I get the x-axis time?
Please help me.
code
chartComposite.addChartMouseListener(new ChartMouseListener() {
#Override
public void chartMouseMoved(ChartMouseEvent arg0) {
}
#Override
public void chartMouseClicked(ChartMouseEvent event) {
XYItemEntity entity = (XYItemEntity)event.getEntity();
XYDataset dataset = entity.getDataset();
int series = entity.getSeriesIndex();
int item = entity.getItem();
Comparable seriesKey = dataset.getSeriesKey(series);
System.out.println(series + " " + item + " " + seriesKey);
}
});
have you tried this?
Date date = new Date(dataset.getX(entity.getSeriesIndex(),entity.getItem()).longValue());

Resources