I am using com.github.mikephil.charting.charts.LineChart to display the chart of weights, but I want to change the value 208 Kg to 208L or 208K. I am using the famous MpAndroidChart. I am not able to change the line data unit from "Kg" to "L".
This is the code->
entries.add(new Entry(i, 208f));
private void setUpChart() {
mBinding.flChartHolder.removeAllViews();
mBinding.barChart.setData(null);
mBinding.barChart.invalidate();
mBinding.barChart.setDescription(null);
mBinding.barChart.setGridBackgroundColor(R.color.white);
mBinding.barChart.getLegend().setEnabled(false);
mBinding.barChart.setScaleEnabled(false);
mBinding.barChart.setData(generateLineData());
YAxis rightAxis = mBinding.barChart.getAxisRight();
rightAxis.setDrawLabels(false);
rightAxis.setDrawGridLines(false);
rightAxis.setXOffset(8f);
rightAxis.setAxisLineColor(Color.TRANSPARENT);
rightAxis.setGranularity(0f);
XAxis xAxis = mBinding.barChart.getXAxis();
xAxis.setDrawLabels(true);
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xAxis.setDrawGridLines(false);
xAxis.setYOffset(4f);
xAxis.setAxisLineColor(Color.TRANSPARENT);
xAxis.setGranularity(0f);
xAxis.setTextColor(ContextCompat.getColor(this, R.color.colorGreen));
xAxis.setGranularityEnabled(true);
xAxis.setTextSize(10f);
YAxis leftAxis = mBinding.barChart.getAxisLeft();
leftAxis.setXOffset(4f);
leftAxis.setAxisLineColor(Color.TRANSPARENT);
leftAxis.setGranularity(0f);
leftAxis.setDrawZeroLine(false);
leftAxis.setTextColor(ContextCompat.getColor(this, R.color.dinner_color));
leftAxis.setGranularityEnabled(true);
if (mResult.getGraph() != null && mResult.getGraph().size() > 0) {
leftAxis.setAxisMinimum((float) (startValue - (float) 60));
leftAxis.setAxisMaximum((float) (startValue + (float) 60));
}
leftAxis.setLabelCount((int) leftAxis.getAxisMaximum() / 20, true);
leftAxis.setTextSize(10f);
xAxis.setLabelCount(mResult.getGraph().size(), true);
xAxis.setValueFormatter(new ValueFormatter() {
#Override
public String getFormattedValue(float value) {
Logger.e("valus---" + value);
int index = (int) value;
return getStringFromDate(index);
}
});
mBinding.barChart.invalidate();
mBinding.flChartHolder.addView(mBinding.barChart);
}
private LineData generateLineData() {
LineData d = new LineData();
ArrayList<Entry> entries = new ArrayList<>();
for (int i = 0; i < mResult.getGraph().size(); i++) {
if (mUserData.getCurrentUnitMeasure() != IMERIAL_UNIT) {
entries.add(new Entry(i, toLbs(Float.valueOf(String.valueOf(mResult.getGraph().get(i).getWeightKg())))));
} else {
entries.add(new Entry(i, Float.valueOf(String.valueOf(mResult.getGraph().get(i).getWeightKg()))));
}
}
entries.add(new Entry(0, 0f));
LineDataSet set = new LineDataSet(entries, "rttrtrt");
set.notifyDataSetChanged();
set.setDrawIcons(false);
set.setColors(ContextCompat.getColor(this, R.color.colorGreen));
set.setDrawCircles(true);
set.setLabel("test");
set.setCircleColor(ContextCompat.getColor(this, R.color.colorGreen));
set.setCircleRadius(3.5f);
set.setCircleHoleRadius(0f);
set.setLineWidth(1.5f);
set.setValueTextColor(ContextCompat.getColor(this, R.color.colorGreen));
set.setDrawHorizontalHighlightIndicator(true);
set.setValueTextSize(12f);
set.setDrawHorizontalHighlightIndicator(false);
set.setDrawVerticalHighlightIndicator(false);
set.setValueFormatter(new ValueFormatter() {
#Override
public String getPointLabel(Entry entry) {
DecimalFormat df = new DecimalFormat("#.00");
Float weight2DecimalsAtEnd = Float.valueOf(df.format(entry.getY()));
Log.d("weight2DecimalsAtEnd", weight2DecimalsAtEnd.toString());
if (mUserData.getCurrentUnitMeasure() != IMERIAL_UNIT) {
return weight2DecimalsAtEnd + "L";
} else {
return weight2DecimalsAtEnd + "K";
}
}
});
d.addDataSet(set);
return d;
}
The output should be 208.45L
I am using com.github.mikephil.charting.charts.LineChart to display the chart of weights, but I want to change the value 208 Kg to 208L or 208K. I am using the famous MpAndroidChart. I am not able to change the line data unit from "Kg" to "L".
You can use the ValueFormatter provided by the library like this
val formatter: ValueFormatter = object : ValueFormatter() {
override fun getPointLabel(entry: Entry?): String {
//formatted string label
return entry?.y.toString()+" Lbs"
}
}
Set the formatter to your dataset
// add entries to dataset
val dataSet = LineDataSet(entries, "Random Chart")
dataSet.valueFormatter = formatter
...// rest of your code
Kotlin is just to give you example you can find Java code here in documentation.
Related
This is the code for this issue for you to check if there is any problem in the code.
Now the problem is when I limit the rows to 45 (this number fits in one page) every row will print in one page.
But, If I don't limit the rows and the row size (approximately 100-200), every row goes to new page in the PDF. The PDF page number goes to approximately equal to row numbers.
I have opened this issue in Boxable's git but it's not active so I came for help here.
Following are the files generated in both conditions:
LimitTemp.pdf
noLimitTemp.pdf
public class CSVtoPDF {
private float marginBetweenYElements = 10;
private float titleFontSize = 18;
private float fontSize = 8;
private float headerFontSize = 12;
private float header1FontSize = 14;
private float header2FontSize = 12;
private float headerCellHeight = 19;
private float dataCellHeight = 12;
private PDFont font = PDType1Font.HELVETICA;
private PDFont headerFont = PDType1Font.TIMES_BOLD;
List filteredData = new ArrayList();
ReportSettings rs = new ReportSettings();
String filePath, destPath, header1, header2, filename;
public CSVtoPDF(List data, Audit audit) throws IOException {
this.filteredData = data;
Date liveDate = new Date();
SimpleDateFormat format= new SimpleDateFormat("YYYY-MM-DD HH:mm:ss");
liveDate = Calendar.getInstance().getTime();
float headerCellHeight = 18;
PDDocument doc = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
//page.setMediaBox(new PDRectangle(PDRectangle.A4.getHeight(),
// PDRectangle.A4.getWidth()));
PDPageContentStream cos = new PDPageContentStream(doc, page);
/* Add page to PDDocument */
doc.addPage(page);
System.out.println("Inside Main csvtopdf");
//Draw Header
Preferences prefs = Preferences.userRoot().node(this.getClass().getName());
try {
String[] keys = prefs.keys();
//destPath = prefs.get("destpath", rs.getDestPath());
//filename = prefs.get("file_name", rs.getFileName());
//header1 = prefs.get("header1", rs.getHeader1());
//header2 = prefs.get("header2", rs.getHeader2());
} catch (BackingStoreException ex) {
System.err.println(ex);
}
header1= "Header 1";
header2= "Header 2";
cos.beginText();
cos.moveTextPositionByAmount(220, 810);
cos.setFont(headerFont, header1FontSize);
cos.drawString(header1);
cos.endText();
cos.beginText();
cos.moveTextPositionByAmount(220, 800);
cos.setFont(headerFont, header2FontSize);
cos.drawString(header2);
cos.endText();
cos.beginText();
cos.moveTextPositionByAmount(220, 790);
cos.setFont(headerFont, headerFontSize);
cos.drawString("Report: Filtered Audit Report");
cos.endText();
//cos.beginText();
// cos.moveTo(200, 30);
//cos.setFont(headerFont, headerFontSize);
// cos.drawString(header2);
//cos.endText();
/* Initialize DataTable */
float margin = 20;
float tableWidth = page.getMediaBox().getWidth() - (2 * margin);
float yStartNewPage = page.getMediaBox().getHeight() - (2 * margin);
float yStart = yStartNewPage;
float bottomMargin = -800;
BaseTable table = new BaseTable(yStart, yStartNewPage,
bottomMargin, tableWidth, margin, doc, page, true, true);
Row<PDPage> dataRow = table.createRow(dataCellHeight);
for (int i = 0; i < data.size() - 1; i++) {
System.out.println(data.get(i));
}
drawTableData(table, dataCellHeight, 20, data, 1,doc,page);
table.draw();
File result;
if (Objects.isNull(destPath)) {
cos.close();
result = new File("temp.pdf");
} else {
result = new File(destPath);
}
System.out.println("befor save result");
doc.save(result);
System.out.println("after save result");
}
public void drawTableData(BaseTable table, float dataCellHeight, float
cellWidth, List<Audit> data, int style,PDDocument doc,PDPage page) {
String s;
Cell<PDPage> cell;
// for (int k = 0; k < data.size(); k++) {
System.out.println("inside drawtable for ");
for (int i = 0; i < data.size(); i++) { // add row
System.out.println("inside drawtable for " + i);
Audit atmp = data.get(i);
//if (i==35) {
// doc.addPage(page);
//}
Row<PDPage> sTableRow = table.createRow(dataCellHeight);
for (int j = 0; j <= 2; j++) { //add cell in the rows
if (j == 0) { // normal cells on right
s = atmp.getTimeStamp();
s = s.replaceAll("^\"|\"$", "");
cell = sTableRow.createCell(cellWidth, s, HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
setStyle(style, cell);
//k++;
} else if (j == 1) { //big cells on left
s = atmp.getDiscription();
s = s.replaceAll("^\"|\"$", "");
cell = sTableRow.createCell(cellWidth + 50, s, HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
setStyle(style, cell);
// k++;
} else if (j == 2) { //top blank cell
//System.out.println("In j null and 0 " + j);
s = atmp.getUserID();
s = s.replaceAll("^\"|\"$", "");
cell = sTableRow.createCell(cellWidth - 10, s, HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
//cell.setBottomBorderStyle(null);
setStyle(style, cell);
//k++;
}
}
table.addHeaderRow(sTableRow);
System.out.println(" row added ");
}
//}
}
public void setStyle(int type, Cell cell) {
// type : 0 as header, 1 as table body
if (type == 0) {
cell.setFont(headerFont);
//cell.setHeight(headerCellHeight);
cell.setFontSize(headerFontSize);
cell.setBottomPadding(3);
} else if (type == 1) {
cell.setTopPadding(1);
cell.setFont(font);
cell.setAlign(HorizontalAlignment.LEFT);
//cell.setHeight(dataCellHeight);
cell.setFontSize(fontSize);
cell.setBottomPadding(1);
}
}
I found a silly problem in my code. I am telling this so that someone else must not repeat this.
I treated every row of the data table as header row. So it went to new page.
To be specific. In the function drawTableData I removed table.addHeaderRow(sTableRow)
i have problem with remove data from line chart. I wrote a program drawing graphs that after the action click on the button completes the chart data.
dataSeries1.getData().removeAll(); <- doesn't work.
Code:
NumberAxis xAxis = new NumberAxis();
xAxis.setLabel("Oś Y");
NumberAxis yAxis = new NumberAxis();
yAxis.setLabel("Oś X");
final LineChart lineChart = new LineChart(xAxis, yAxis);
final XYChart.Series dataSeries1 = new XYChart.Series();
lineChart.setCreateSymbols(false);
lineChart.getData().add(dataSeries1);
Button action:
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
int lewy = Integer.parseInt(kresLewy.getText());
int prawy = Integer.parseInt(kresPrawy.getText());
String rownanie = field.getText();
try {
String tekst = lewy + "; " + prawy + "; " + rownanie;
StringReader tekstReader = new StringReader(tekst);
parsery.interpreter.parser parser_obj
= new parsery.interpreter.parser(new parsery.interpreter.MyLexer(tekstReader));
Object result = parser_obj.parse().value;
String sWynik = result.toString();
ZmiennaX zX = new ZmiennaX();
ArrayList<Double> xArr = new ArrayList<Double>();
for (double i = lewy; i <= prawy + 0.001; i = i + zX.getDokladnosc()) // +0.001 dla bledow zaokraglenia
{
xArr.add(zX.round2(i));
}
String sX = xArr.toString();
String wartosciX = sX.substring(1, sX.length() - 1);
String wartosciY = sWynik.substring(1, sWynik.length() - 1);
String XbezSpacji = wartosciX.replace(" ", "");
String YbezSpacji = wartosciY.replace(" ", "");
String[] splitX = XbezSpacji.split(",");
String[] splitY = YbezSpacji.split(",");
dataSeries1.getData().removeAll();
for(int i=0; i<splitX.length; i++){
double x = Double.parseDouble(splitX[i]);
double y = Double.parseDouble(splitY[i]);
dataSeries1.getData().add(new XYChart.Data(x, y));
}
} catch (Exception e) {
System.out.println("Podczs obliczenia wystapil blad. (" + e.getMessage() + ")");
} catch (Error error) {
System.out.println("Podczs obliczenia wystapil blad. (" + error.getMessage() + ")");
}
}
});
Can anyone help me to remove data after drawing a new chart?
removeAll requires elements to be removed passed in its parameter. Since you provided none - nothing gets removed:
dataSeries1.getData().removeAll();
You want to use clear() instead in the line above.
public void clear()
Removes all of the elements from this list (optional operation). The list will be empty after this call returns.
You can use Collections.singleton to remove all data:
dataSeries1.getData().removeAll(Collections.singleton(barChart.getData().setAll()));
See Oracle documentation for Collections.singleton https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html
I have a requirement to create a csv file from all the metric values from Kairosdb.
The kairosdb UI already has a save as feature but it doesn't have a metric name in the exported file. Also we can't export multiple metrics into a single file.
The problem I am facing is with matching the timestamp from multiple metrics. For ex, One metric might return 5 timestamp values. Another metric might return 10 timestamp values which may be matching with previous metric or not.
So I need to generate a csv like below:
tmestamp,metric1,metric2,tmetric3\n
0,1,,2\n
1,,2,\n
2,1,3,6\n
3,5,5, \n
4,,,5\n
The value returned from the query might be more than 10000 datapoints. How can I approach this problem. Can I run this program in spark cluster.
The code that I tried:
package com.example;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.kairosdb.client.builder.DataPoint;
public class Test {
private static Map<MetricMap, String> metricMaps = new HashMap<>();
public static void main(String args[]) {
Map<String, List<DataPoint>> metriDps = new HashMap<>();
String[] metricNames = new String[] { "m1", "m2", "m3" };
List<DataPoint> dataPoints1 = new ArrayList<DataPoint>();
DataPoint dp1 = new DataPoint(0, 1);
DataPoint dp2 = new DataPoint(2, 1);
DataPoint dp3 = new DataPoint(3, 5);
dataPoints1.add(dp1);
dataPoints1.add(dp2);
dataPoints1.add(dp3);
metriDps.put("m1", dataPoints1);
List<DataPoint> dataPoints2 = new ArrayList<DataPoint>();
DataPoint dp21 = new DataPoint(1, 2);
DataPoint dp22 = new DataPoint(2, 3);
DataPoint dp23 = new DataPoint(3, 5);
dataPoints2.add(dp21);
dataPoints2.add(dp22);
dataPoints2.add(dp23);
metriDps.put("m2", dataPoints2);
List<DataPoint> dataPoints3 = new ArrayList<DataPoint>();
DataPoint dp31 = new DataPoint(0, 2);
DataPoint dp32 = new DataPoint(2, 6);
DataPoint dp33 = new DataPoint(4, 5);
dataPoints3.add(dp31);
dataPoints3.add(dp32);
dataPoints3.add(dp33);
metriDps.put("m3", dataPoints3);
try {
FileWriter writer = new FileWriter("/home/lr/Desktop/csv1.csv");
metriDps.keySet().stream().forEach(key -> createMap(metriDps.get(key), key));
String value;
for (MetricMap metricMap : metricMaps.keySet()) {
String time = metricMap.getTime();
writer.append(time);
writer.append(',');
for (int i = 0; i < 3; i++) {
MetricMap map = new MetricMap();
map.setName(metricNames[i]);
map.setTime(time);
value = metricMaps.get(map);
if (value != null)
writer.append(metricMaps.get(map));
else
writer.append("");
if (i == 2)
writer.append('\n');
else
writer.append(',');
}
}
// generate whatever data you want
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void createMap(List<DataPoint> list, String key) {
MetricMap map = null;
for (DataPoint dp : list) {
map = new MetricMap();
map.setName(key);
map.setTime(String.valueOf(dp.getTimestamp()));
metricMaps.put(map, String.valueOf(dp.getValue()));
}
}
}
I really appreciate your help.
To make your algorithm work, you'll have to map that has time as key, and point's value + metric names as value. The following does that:
Map<String, List<DataPoint>> metriDps = new HashMap<>();
String[] metricNames = new String[] {
"m1", "m2", "m3"
};
List<DataPoint> dataPoints1 = new ArrayList<DataPoint>();
dataPoints1.add(new DataPoint(0, 1));
dataPoints1.add(new DataPoint(2, 1));
dataPoints1.add(new DataPoint(3, 5));
metriDps.put("m1", dataPoints1);
List<DataPoint> dataPoints2 = new ArrayList<DataPoint>();
dataPoints2.add(new DataPoint(1, 2));
dataPoints2.add(new DataPoint(2, 3));
dataPoints2.add(new DataPoint(3, 5));
metriDps.put("m2", dataPoints2);
List<DataPoint> dataPoints3 = new ArrayList<DataPoint>();
dataPoints3.add(new DataPoint(0, 2));
dataPoints3.add(new DataPoint(2, 6));
dataPoints3.add(new DataPoint(4, 5));
metriDps.put("m3", dataPoints3);
SortedMap<Long, Map<String, String>> map = new TreeMap<>();
// format:
// time1 -> [(metricName, value), (metricName, value), ..]
// time2 -> [(metricName, value), (metricName, value), ..]
// ..
metriDps.entrySet().stream()
.forEach(entry -> {
List<DataPoint> points = entry.getValue();
String metric = entry.getKey();
points.forEach(point -> {
Long time = point.getTimestamp();
Object value = point.getValue();
if (value != null)
// add (metricName, value) to map stored under time
map.computeIfAbsent(time, key -> new HashMap<>())
.put(metric, value.toString());
});
});
StringWriter writer = new StringWriter();
// header
writer.append("timestamp,");
writer.append(Stream.of(metricNames).collect(Collectors.joining(",")));
writer.append('\n');
// content, sorted map means we can simply iterate it's keys
map.entrySet().forEach(entry -> {
// time
writer.append(String.valueOf(entry.getKey()));
writer.append(',');
// fetch all possible metric names from the map so it prints empty ",,"
String line = Stream.of(metricNames)
.map(entry.getValue()::get)
.map(val -> val == null ? "" : val)
.collect(Collectors.joining(","));
writer.append(line);
writer.append('\n');
});
System.out.println(writer);
Prints
timestamp,m1,m2,m3
0,1,,2
1,,2,
2,1,3,6
3,5,5,
4,,,5
With sorted input lists, you can improve the algorithm by keeping 3 iterators, then advancing the one(s) that point to the earliest value. You can thereby iterate all series in parallel / side-by-side. That way you can save some memory because you don't have to build maps and process the lists one by one.
Using the following utility class
static class NamedKeeparator implements Iterator<DataPoint> {
private final Iterator<DataPoint> delegate;
private final String name;
private DataPoint current;
public NamedKeeparator(String name, Iterator<DataPoint> delegate) {
this.delegate = delegate;
this.name = name;
}
#Override
public boolean hasNext() {
return delegate.hasNext();
}
#Override
public DataPoint next() {
return current = delegate.next();
}
public DataPoint current() {
return current;
}
public void consume() {
current = null;
}
String getName() {
return name;
}
}
A potential implementation could be
StringWriter writer = new StringWriter();
// header
writer.append("timestamp,");
writer.append(Stream.of(metricNames).collect(Collectors.joining(",")));
writer.append('\n');
List<NamedKeeparator> iterators = metriDps.entrySet().stream()
.map(entry -> new NamedKeeparator(entry.getKey(), entry.getValue().iterator()))
.collect(Collectors.toList());
List<NamedKeeparator> leastIterators = new ArrayList<>();
for (;;) {
leastIterators.clear();
long leastValue = Long.MAX_VALUE;
for (NamedKeeparator iterator : iterators) {
// advance until there is some value
while (iterator.current() == null && iterator.hasNext()) {
iterator.next();
}
// build set of iterators pointing to least value
if (iterator.current() != null
&& iterator.current().getTimestamp() <= leastValue) {
if (iterator.current().getTimestamp() < leastValue) {
leastValue = iterator.current().getTimestamp();
leastIterators.clear();
}
leastIterators.add(iterator);
}
}
// nothing -> all iterators done
if (leastIterators.isEmpty())
break;
// least contains now iterators for the same timestamp
// get time from the first
long time = leastIterators.get(0).current().getTimestamp();
writer.append(String.valueOf(time)).append(',');
// format points
String points = Stream.of(metricNames)
.map(metric -> leastIterators.stream()
.filter(it -> it.getName().equals(metric)).findAny()
.map(it -> it.current()).orElse(null))
.map(point -> point != null ? String.valueOf(point.getValue()) : "")
.collect(Collectors.joining(","));
writer.append(points).append('\n');
leastIterators.forEach(it -> {
it.consume();
});
}
System.out.println(writer);
http://ideone.com/pVCfNB
My stacked bar chart in MPAndroidChart works very well but I'm trying to remove or edit the values inside the bars. But I can't find any code which makes sense to modify.
I don't think that my code is very helpful, but here it is...
private void initStackedBarChartStuff() {
mMonths = dfs.getShortMonths();
mChart = (BarChart) mContext.findViewById(R.id.chart1);
mChart.setOnChartValueSelectedListener(this);
mChart.setDescription("");
// if more than 60 entries are displayed in the chart, no values will be
// drawn
mChart.setMaxVisibleValueCount(30);
// scaling can now only be done on x- and y-axis separately
mChart.setPinchZoom(false);
mChart.setDrawGridBackground(false);
mChart.setDrawBarShadow(false);
mChart.setDrawValueAboveBar(false);
// change the position of the y-labels
YAxis yLabels = mChart.getAxisLeft();
yLabels.setValueFormatter(new MyYAxisValueFormatter());
mChart.getAxisRight().setEnabled(false);
mChart.getAxisLeft().setEnabled(false);
XAxis xLabels = mChart.getXAxis();
xLabels.setPosition(XAxis.XAxisPosition.TOP);
Legend l = mChart.getLegend();
l.setPosition(Legend.LegendPosition.BELOW_CHART_RIGHT);
l.setFormSize(8f);
l.setFormToTextSpace(4f);
l.setXEntrySpace(6f);
// mChart.setDrawLegend(false);
}
fill the stackedBarChart
private void fillStackedBarChart(Vector drawingData, Vector drawingIntervall) {
if (drawingData == null || drawingData == null)
return;
int anzBdata = dataSizes[1];
int intervall = globalIntervall;
ArrayList<String> xVals = new ArrayList<String>();
// Strings über die Blöcke schreiben ###########################################
{
long zeit = 0;
String[] months = new String[12];
String[] days = new String[7];
boolean einmal = true;
for (int i = 0; i < drawingIntervall.size(); i++)
zeit += ((Long) drawingIntervall.get(i)).longValue();
if (bigData) // > 2 Jahre
months = null;
else if (zeit > 31623000) // > 1 Jahre
months = dfs.getShortMonths();
else
months = dfs.getMonths();
days = dfs.getWeekdays();
for (int i = 0; i < drawingData.size(); i++) {
long[] pack = (long[]) drawingData.get(i);
String s = "";
// Sonderfall !! In Monatsansicht den Monat dazu schreiben
if ((einmal) && (intervall == 2)) {
if (etStart.getText().toString().trim().startsWith("01.")) {
Calendar calE = convStringToDate(etEnd.getText().toString().trim(), true, true);
int jahr = calE.get(Calendar.YEAR);
int monat = calE.get(Calendar.MONTH);
Calendar calX = myGetInstance();
calX.set(Calendar.YEAR, jahr);
calX.set(Calendar.MONTH, monat);
calX = getLastDayOfMonth(calX);
if (calE.getTimeInMillis() == calX.getTimeInMillis()) {
einmal = false;
s = months[calE.get(Calendar.MONTH)];
}
}
}
switch (intervall) {
case 0:
s += df.format(convMilliToDate(pack[0] * 1000, false, false).getTime());
break;
case 1:
s += convMilliToString(pack[0] * 1000);
break;
case 2:
s += "KW " + convMilliToDate(pack[0] * 1000, false, false).get(Calendar.WEEK_OF_YEAR);
break;
case 3:
if (bigData)
s += convMilliToDate(pack[0] * 1000, false, false).get(Calendar.YEAR) + "";
else
s += months[convMilliToDate(pack[0] * 1000, false, false).get(Calendar.MONTH)];
break;
}
xVals.add(s);
}
}
// nun alle Balken/Blöcke zeichnen ##########################################
{
// 1 Y-Wert entspricht z.B. 1 Tag, o. 1 Woche,... jeder Y-Wert hat so viele floats wie B-Daten vorhanden sind ###########################################
ArrayList<BarEntry> yVals1 = new ArrayList<BarEntry>();
for (int i = 0; i < drawingData.size(); i++) {
long[] pack = (long[]) drawingData.get(i);
long intervallSek = ((Long) drawingIntervall.get(i)).longValue() + 1;
long pastSek = 0;
float[] f = new float[anzBdata + 1];
int b = 0;
for (int j = 0; j < pack.length; j++) {
if ((j >= dataSizes[0]) && (j <= (anzBdata - 1 + dataSizes[0]))) {
f[b++] = pack[j];
pastSek += pack[j];
}
}
f[b++] = intervallSek - pastSek; // zeichnet einen Block indem "keine Daten" aufgezeichnet wurden. (wenn Maschine ohne Strom o.ä.)
yVals1.add(new BarEntry(f, i));
}
// BarDataSet set1 = new BarDataSet(yVals1, "Statistics Business Data");
BarDataSet set1 = new BarDataSet(yVals1, "");
set1.setColors(getColors());
set1.setStackLabels(barChartLegend);
ArrayList<BarDataSet> dataSets = new ArrayList<BarDataSet>();
dataSets.add(set1);
BarData data = new BarData(xVals, dataSets);
data.setValueFormatter(new MyValueFormatter());
mChart.setData(data);
mChart.invalidate();
}
}
This solution is not really pretty, may somone else find a better one...
The class BarChart extends from BarLineChartBase. There is a line in BarLineChartBase which can be annotated or removed to get the desired solution.
mRenderer.drawValues(canvas);
There are basically two ways:
Use the ValueFormatter to custom format your values (edit or remove)
Use dataSet.setDrawValues(false) to completely remove all values
I have problem on the Axis and the Tooltip display on JFreeChart they don't display all the values, I am trying to display the bytes based on daily use, here is an image to show exactly my problem:
There are missing some values and on the tallest red bar it doesn't show me the bytes on the tooltip. Here is my code:
final JFreeChart chart = createTrafficChart();
chartPanel = new ChartPanel(chart, true, true, true, true, true);
chartPanel.setPreferredSize(new java.awt.Dimension(750, 367));
a.gridx = 0;
a.gridy = 3;
jpContainer.add(chartPanel, a);
private JFreeChart createTrafficChart() {
// create plot ...
final IntervalXYDataset data1 = createDatasetDownload();
XYBarRenderer t= new XYBarRenderer(0.20);
t.setShadowVisible(false);
final XYItemRenderer renderer1 = t;
renderer1.setBaseToolTipGenerator(new MyTrafficToolTipGenerator());
final DateAxis domainAxis = new DateAxis("Date");
domainAxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
final NumberAxis rangeAxis = new NumberAxis("Bytes");
setupRangeAxis(rangeAxis);
final XYPlot plot = new XYPlot(data1, domainAxis, rangeAxis, renderer1);
// add a second dataset and renderer...
final XYDataset data2 = createDatasetUpload();
final XYItemRenderer renderer2 = new StandardXYItemRenderer();
renderer2.setBaseToolTipGenerator(new MyTrafficToolTipGenerator());
plot.setDataset(1, data2);
plot.setRenderer(1, renderer2);
plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
return new JFreeChart("Traffic", JFreeChart.DEFAULT_TITLE_FONT, plot, true);
}
And this code:
public void setupRangeAxis(NumberAxis rangeAxis) {
final TickUnits standardUnits = new TickUnits();
standardUnits.add(new MyNumberTickUnit(1));
standardUnits.add(new MyNumberTickUnit(10));
standardUnits.add(new MyNumberTickUnit(100));
standardUnits.add(new MyNumberTickUnit(1024)); // Kilo
standardUnits.add(new MyNumberTickUnit(10000));
standardUnits.add(new MyNumberTickUnit(100000));
standardUnits.add(new MyNumberTickUnit(1024*1024)); // Mega
standardUnits.add(new MyNumberTickUnit(10000000));
standardUnits.add(new MyNumberTickUnit(100000000));
standardUnits.add(new MyNumberTickUnit(1024*1024*1024)); // Giga
standardUnits.add(new MyNumberTickUnit(10000000000L));
standardUnits.add(new MyNumberTickUnit(100000000000L));
standardUnits.add(new MyNumberTickUnit(1024*1024*1024*1024)); // Tera
standardUnits.add(new MyNumberTickUnit(10000000000000L));
standardUnits.add(new MyNumberTickUnit(100000000000000L));
standardUnits.add(new MyNumberTickUnit(1000000000000000L)); // Peta
standardUnits.add(new MyNumberTickUnit(10000000000000000L));
standardUnits.add(new MyNumberTickUnit(100000000000000000L));
standardUnits.add(new MyNumberTickUnit(1000000000000000000L)); // Exa
rangeAxis.setStandardTickUnits(standardUnits);
}
Which i found here .
I also have this code:
public class MyNumberTickUnit extends NumberTickUnit{
private static final long serialVersionUID = 4281451255133640119L;
public MyNumberTickUnit(double size) {
super(size);
}
public String valueToString(double value){
return StringFormat.formatTheTraffic(value);
}
}
public class StringFormat {
public static String formatTheTraffic(double input) {
String result = "";
if (input < KILO_BYTES) {
result = input + " Byte";
} else if ((input < MEGA_BYTES) && (input >= KILO_BYTES)) {
result = new DecimalFormat("##.#").format(input / KILO_BYTES) + " KB";
} else if ((input < GIGA_BYTES) && (input >= MEGA_BYTES)) {
result = new DecimalFormat("##.#").format(input / MEGA_BYTES) + " MB";
} else if ((input < TERA_BYTES) && (input >= GIGA_BYTES)) {
result = new DecimalFormat("##.#").format(input / GIGA_BYTES) + " GB";
}
return result;
}
}
Thanks for your attention and time!
I found my problem. It was inside the formatTheTraffic method! I change it and works properly now!