Horizontal Label problem with GraphView while scrolling - android

I am facing some weird problems with my (Line) GraphView!
To explain it a bit better I'll add a pic that shows what happens when I start scrolling horizontal (vertical scrolling is not needed).
The thing is:
The DataPoints are displayed correctly, but not my labels! I wrote the correct label in red color into the pictures above!
Whenever I start scrolling the labels start to "jump" around weirdly.
The DataPoints are received from a SharedPreference file with String/Integer pairs [Strings are always MMMyyyy (f.e. "Mar2020")]
I get the pairs out of my SP-file, put the Strings as static labels into my graph use the DataPoints in this way "logical" way (not the actual code!)
DataPoint[0] = (0, valueOfKey0)
DataPoint[1] = (1, valueOfKey1)
Here is the code how the graph is called for / drawn in the Activity
private void setupGraph(final GraphView graph, String subName){
GraphDataHelper graphDataHelper = new GraphDataHelper(mContext);
LineGraphSeries<DataPoint> series;
/*Have to call .removeAllSeries to draw each graph individually
* Otherwise they will be drawn over another!*/
graph.removeAllSeries();
/*Gets Values from each Sub
* --> Gets values form each key/value pair of specific SharedPreference-file
* --> sets values in order (0, 1, 2,... n)*/
series = new LineGraphSeries<DataPoint>(graphDataHelper.generateGraphData(subName));
series.setDrawDataPoints(true);
series.setColor(getResources().getColor(R.color.casualWhite));
series.setAnimated(true);
graph.addSeries(series);
/*Fill Labels for X-Axis:
* Get the specific Monthly-Keys for the choosen Sub
* In special cases extra rules are declared in .getSpecificSubMonthKeys() method
* Put all entries of ArrayList in Array (StaticLabelsFormatter only works with "normal" Array)*/
ArrayList<String> array_paths = graphDataHelper.getSpecificSubMonthKeys(subName);
int size = array_paths.size();
String[] paths = new String[size];
for (int i=0; i<size; i++){
paths[i] = array_paths.get(i);
}
StaticLabelsFormatter staticLabelsFormatter = new StaticLabelsFormatter(graph);
staticLabelsFormatter.setHorizontalLabels(paths);
graph.getGridLabelRenderer().setLabelFormatter(staticLabelsFormatter);
graph.getViewport().setXAxisBoundsManual(true);
if(size == 5 || size > 5){
graph.getViewport().setMinX(0.0);
graph.getViewport().setMaxX(4.0);
graph.getGridLabelRenderer().setNumHorizontalLabels(5);
} else if(size == 4){
graph.getViewport().setMinX(0.0);
graph.getViewport().setMaxX(3.0);
graph.getGridLabelRenderer().setNumHorizontalLabels(4);
} else if(size == 3){
graph.getViewport().setMinX(0.0);
graph.getViewport().setMaxX(2.0);
graph.getGridLabelRenderer().setNumHorizontalLabels(3);
} else if(size == 2){
graph.getViewport().setMinX(0.0);
graph.getViewport().setMaxX(1.0);
graph.getGridLabelRenderer().setNumHorizontalLabels(2);
}
graph.getViewport().setScrollable(true);
graph.getGridLabelRenderer().setHorizontalLabelsColor(getResources().getColor(R.color.midBlue));
graph.getGridLabelRenderer().setVerticalLabelsColor(getResources().getColor(R.color.midBlue));
graph.getGridLabelRenderer().setGridColor(getResources().getColor(R.color.darkBlue));
graph.getGridLabelRenderer().setPadding(50);
graph.getGridLabelRenderer().setLabelsSpace(30);
I call for .removeAllSeries because the User is able to call for another graph via a dropdown-Spinner.
Also I set different MinX & MaxX Points because there can be the case that an entry doesn't have 5 DataPoints yet and so I change the Viewport in regard of that (didn't find a better solution for that so I am also open for some better code here, but it does work this way). My SharedPreference-file always has a minimun of 2 key/value pairs
Also little extra question: Is there a way to give ONLY the horizontal labels some extra labelspace. If I use setLabelSpace it will also apply on the vertical labels and I do not want that. But the horizontal labels are just so close to the axis.
Also sorry for ugly code. It was my first time using GraphView!
Thanks ahead!

Related

Graphview not showing all x axis values

See picture below, trying to figure out why they it is skipping the '1', '3', and so forth.
Where i set the series and graph:
DataPoint[] dataPoints = new DataPoint[rankList.size()]; // declare an array of DataPoint objects with the same size as your list
for (int i = 0; i < rankList.size(); i++) {
dataPoints[i] = new DataPoint(i, Double.parseDouble(rankList.get(i))); // not sure but I think the second argument should be of type double
}
BarGraphSeries<DataPoint> series2 = new BarGraphSeries<DataPoint>(dataPoints); // This one should be obvious right? :)
series2.setAnimated(true);
series2.setTitle("Random Curve 1");
series2.setColor(Color.GREEN);
series2.setSpacing(30);
series2.setDataWidth(1);
graph2.getViewport().setMinX(-1);
graph2.getViewport().setMaxX(12);
graph2.addSeries(series2);
The right info is being plotted, but i've tried a bunch of stuff from the docs and get get it to work.
Sorry I misunderstood your question...
This will help:
yourGraph.getGridLabelRenderer().setNumHorizontalLabels(numberOfBars);
It actually shows all bars. You've set series2.setSpacing(30);.
Instead do series2.setSpacing(0);.

TeeChart is drawing lines from different axes in different speeds

I'm using TeeChart for drawing incoming data points that are received via BLE.
I created an TeeChart that has three costum axes to divide the Y-Axis in three equally sized parts. In addition, I initialized three FastLines and assigned each line to one custom axis.
//LINES
line1 = new Line(chart1.getChart());
line1.setColor(Color.black);
line1.getLinePen().setWidth(3);
line2 = new Line(chart1.getChart());
line2.setColor(Color.black);
line2.getLinePen().setWidth(3);
line3 = new Line(chart1.getChart());
line3.setColor(Color.black);
line3.getLinePen().setWidth(3);
//AXES
Axis axis0 = new Axis(false, false, chart1.getChart());
axis0.setVisible(true);
axis0.getLabels().setVisible(false);
axis0.getMinorTicks().setVisible(true);
axis0.getTicksInner().setVisible(false);
axis0.getTicks().setVisible(true);
chart1.getAxes().getCustom().add(axis0);
line1.setCustomVertAxis(axis0);
axis0.getTitle().getFont().setSize(textSizeY);
axis0.getTitle().getFont().setBold(true);
axis0.getTitle().setText("1 mV");
axis0.getTitle().setAngle(90);
axis0.setStartPosition(0);
axis0.setEndPosition(33);
axis0.setRelativePosition(0);
axis0.setAutomatic(false);
axis0.setIncrement(100);
axis0.setMinimum(-350);
axis0.setMaximum(+350);
Axis axis1 = new Axis(false, false, chart1.getChart());
axis1.setVisible(true);
axis1.getLabels().setVisible(false);
axis1.getMinorTicks().setVisible(true);
axis1.getTicksInner().setVisible(false);
axis1.getTicks().setVisible(true);
chart1.getAxes().getCustom().add(axis1);
line2.setCustomVertAxis(axis1);
axis1.getTitle().getFont().setSize(textSizeY);
axis1.getTitle().getFont().setBold(true);
axis1.getTitle().setText("1 mV");
axis1.getTitle().setAngle(90);
axis1.setStartPosition(33);
axis1.setEndPosition(66);
axis1.setRelativePosition(0);
axis1.setAutomatic(false);
axis1.setIncrement(100);
axis1.setMinimum(-350);
axis1.setMaximum(+350);
Axis axis2 = new Axis(false, false, chart1.getChart());
axis2.setVisible(true);
axis2.getLabels().setVisible(false);
axis2.getMinorTicks().setVisible(true);
axis2.getTicksInner().setVisible(false);
axis2.getTicks().setVisible(true);
chart1.getAxes().getCustom().add(axis2);
line3.setCustomVertAxis(axis2);
axis2.getTitle().getFont().setSize(textSizeY);
axis2.getTitle().getFont().setBold(true);
axis2.getTitle().setText("1 mV");
axis2.getTitle().setAngle(90);
axis2.setStartPosition(66);
axis2.setEndPosition(100);
axis2.setRelativePosition(0);
axis2.setAutomatic(false);
axis2.setIncrement(100);
axis2.setMinimum(-350);
axis2.setMaximum(+350);
As soon as there is data coming via BLE, the data points are plotted in the TeeChart as follows:
public static void addDataToTeeChart(short i){
if(numberOfPlottablePoints >= 3*MAX_X_POINTS) {
numberOfPlottablePoints = 0;
line1.clear();
line2.clear();
line3.clear();
}
if (numberOfPlottablePoints < MAX_X_POINTS){
line1.add(i);
}
else if (numberOfPlottablePoints < 2*MAX_X_POINTS){
line2.add(i);
}
else if (numberOfPlottablePoints < 3*MAX_X_POINTS){
line3.add(i);
}
numberOfPlottablePoints++;
}
The problem now is that while adding data to line1, everything is working just fine. But adding data to line2 becomes slower and the drawing gets some kind of juddery. And it's even worse for line3.
After clearing and back to adding points to line1, the plotting is fine again.
I was thinking that maybe there is too much data coming in.
To rule that out, I added all incoming data to line1 (leaving line2 and line3 empty). That worked fine again!
I then tried to plot all data in line2 (leaving Line1 and Line3 empty) but there was no data plotted at all!
Also reducing MAX_X_POINTS to reduce the amout of plotted points, didn't do it for me.
For me it seems that the problem is with toggling between line1, line2 and line3 because when I just use one line (independet of which custom axis was used) the drawing is smooth!
I have no idea what else to try.
I hope that maybe someone can even tell me what exactly might be the problem or even has an suggestion what to do.
Thank you in advance!
I did a rapid test with your code (with a few changes), and it seems to work fine for me here:
The changes I did are basically:
Disable manual configuration of the 3 custom axes scales.
Set the chart to 2D.
Fill the series with sample values instead of using your addDataToTeeChart function.
Find the code here:
//LINES
Line line1 = new Line(tChart1.getChart());
line1.setColor(Color.black);
line1.getLinePen().setWidth(3);
Line line2 = new Line(tChart1.getChart());
line2.setColor(Color.black);
line2.getLinePen().setWidth(3);
Line line3 = new Line(tChart1.getChart());
line3.setColor(Color.black);
line3.getLinePen().setWidth(3);
//AXES
Axis axis0 = new Axis(false, false, tChart1.getChart());
axis0.setVisible(true);
axis0.getLabels().setVisible(false);
axis0.getMinorTicks().setVisible(true);
axis0.getTicksInner().setVisible(false);
axis0.getTicks().setVisible(true);
tChart1.getAxes().getCustom().add(axis0);
line1.setCustomVertAxis(axis0);
//axis0.getTitle().getFont().setSize(textSizeY);
axis0.getTitle().getFont().setBold(true);
axis0.getTitle().setText("1 mV");
axis0.getTitle().setAngle(90);
axis0.setStartPosition(0);
axis0.setEndPosition(33);
axis0.setRelativePosition(0);
/*axis0.setAutomatic(false);
axis0.setIncrement(100);
axis0.setMinimum(-350);
axis0.setMaximum(+350);*/
Axis axis1 = new Axis(false, false, tChart1.getChart());
axis1.setVisible(true);
axis1.getLabels().setVisible(false);
axis1.getMinorTicks().setVisible(true);
axis1.getTicksInner().setVisible(false);
axis1.getTicks().setVisible(true);
tChart1.getAxes().getCustom().add(axis1);
line2.setCustomVertAxis(axis1);
//axis1.getTitle().getFont().setSize(textSizeY);
axis1.getTitle().getFont().setBold(true);
axis1.getTitle().setText("1 mV");
axis1.getTitle().setAngle(90);
axis1.setStartPosition(33);
axis1.setEndPosition(66);
axis1.setRelativePosition(0);
/*axis1.setAutomatic(false);
axis1.setIncrement(100);
axis1.setMinimum(-350);
axis1.setMaximum(+350);*/
Axis axis2 = new Axis(false, false, tChart1.getChart());
axis2.setVisible(true);
axis2.getLabels().setVisible(false);
axis2.getMinorTicks().setVisible(true);
axis2.getTicksInner().setVisible(false);
axis2.getTicks().setVisible(true);
tChart1.getAxes().getCustom().add(axis2);
line3.setCustomVertAxis(axis2);
//axis2.getTitle().getFont().setSize(textSizeY);
axis2.getTitle().getFont().setBold(true);
axis2.getTitle().setText("1 mV");
axis2.getTitle().setAngle(90);
axis2.setStartPosition(66);
axis2.setEndPosition(100);
axis2.setRelativePosition(0);
/*axis2.setAutomatic(false);
axis2.setIncrement(100);
axis2.setMinimum(-350);
axis2.setMaximum(+350);*/
tChart1.getAspect().setView3D(false);
line1.fillSampleValues(100);
line2.fillSampleValues(100);
line3.fillSampleValues(100);
To increment the fonts depending on the screen resolution I also use this:
private void proportionalFonts() {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
float myDensity = metrics.density;
tChart1.getAspect().setFontZoom(tChart1.getAspect().getFontZoom()*myDensity*1.5);
}
If you still find problems with it, please try to arrange an sscce.

Animating 3 parts of a view

I am trying to make an app view that, when presented with a subtraction problem, will show an animation of a growing rectangle (or fat line) that crawls up the number line to that integer.
I already have things set up so that I click "show me!" and bars are drawn along the number line showing the minuend, the subtrahend and the difference, but I'd like to be able to have a positive number's rectangle crawl up in a positive direction, negative from zero in the negative direction.
In looking through the documentation there seem to be several different ways to go about this. I am hoping somebody can suggest a way that's reasonably simple for this novice to implement. Here are the different approaches I've found:
This seems very much like this person's desire to have a bar graph where the bars "pop up," but it doesn't have an answer. Android Animated Bar Chart (invalidate())
I've perused http://developer.android.com/guide/topics/resources/drawable-resource.html -- but I don't have a "drawable" because it's being drawn in the View. I'm thinking of making the rest of the number line a background bitmap per Android View.getDrawingCache returns null, only null but I want three rectangles (for the minuend, subtrahend and difference).
I have thought of making a series of rectangle drawables and showing them frame-by-frame to show the growth.
I have looked at Animation at a specified rate using canvas / Ondraw but cannot discern just what code to wrap in that "if" statement, if in fact my problem is re-drawing...
I looked at using Paths -- and put the following code together. If direction matters, then it seems I should be able to slow things down and watch the path going in that direction, but it's instantaneous. I found I saw an example at http://www.curious-creature.org/2013/12/21/android-recipe-4-path-tracing/
if (minuendLength > 0) // start at 0 and go to the minuend length
{
path.addRect(interpX(0), yPosition(40), interpX(minuendLength), yPosition(43) , Path.Direction.CW);
// interpX lets me say what number on the number line it should align with;
//yPosition is percent of the way down the screen.
canvas.drawPath(path,minuendPaint);
// Seems same as drawRect -- instantaneous.
}
(The number line in the 'background' code is as follows, with different options for different sized integers entered:
if ( (minuendLength <10 && subtrahendLength <10 ) && (minuendLength >-10 && subtrahendLength >-10 ) )
{
this.setLineDimension(10); // default
super.onDraw(canvas);
canvas.drawLine(interpX(-this.getLineDimension()), yPosition(52 ),
interpX(this.getLineDimension()), yPosition(52), axisPaint);
int step = this.getLineDimension()/5; // so you're not writing *all* the numbers
// when they enter numbers and you make your own number line.
// paints the little hatch marks
for (int x = -this.getLineDimension(); x <= this.getLineDimension(); x+=step/2)
canvas.drawLine(interpX(x), yPosition(52), interpX(x), yPosition(53) , littleAxisPaint);
// draw the numbers on the hatch marks
textPaint.setTextAlign(Paint.Align.CENTER);
for (int x = -this.getLineDimension() + step; x < this.getLineDimension(); x += step)
{
canvas.drawText(Integer.toString(x), interpX(x), yPosition(56), textPaint);
}
}
I ended up doing this using Runnables.
animate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if ( ((addend1 > 0) && (addend2 < 0)) )
{
tempNum1 =addend1 ;
tempNum2 = addend2;
h.post(shrink1bigger);
}
else if (addend1 < 0 && addend2 > 0)
{
tempNum1 =addend1 ;
tempNum2 = addend2;
h.post(shrink2bigger);
}
}
});
private Runnable shrink2bigger = new Runnable(){
#Override
public void run() {
tempNum1+=1;
tempNum2-=1;
shrinkDraw();
Log.i("WatchAnimActivity", "tempNum1 is " + tempNum1);
h.postDelayed(shrink2bigger, 500);
checkTemp(shrink2bigger);
}};
private void shrinkDraw()
{
numLine.setFirstNum(tempNum1);
numLine.setNextNum(tempNum2);
numLine.invalidate();
}
public void checkTemp(Runnable shrink)
{
Log.i("WatchAnimActivity", "tempNum1 in CHeckTemp is " + tempNum1);
if (tempNum1 ==0 || tempNum2==0)
h.removeCallbacks(shrink);
}

Does AChartEngine support real-time values adding and x-scrolling

In order to display real-time digital input/output value like oscilloscope
There is no method to do x-scrolling, but you can create your own to do this. This is an example.
for (int i = values.getItemCount() - 2; i >= 0; i--) {
values.add(i + 1, value.getY(i));
}
values.add(0, y);
"values" is a TimeSeries.
Basically I swap penultimate value to the last value, and so on. I add, finally, the new value in position 0.
mSeries.add(++xCounter, aData);
if (mChartView != null) {
if (mSeries.getItemCount() >= 200) {
mSeries.remove(0);
}
mhartView.repaint();
}
can help here to draw dynamic view. 200 is your view buffer size, so once it get filled it start to remove from top and add new value at tail.

Integer Array Handling

I have a 2D game that uses two integer arrays to track x and y coordinates as shown below:
private int gridX[] = { 0,0,0,0,0 }
private int gridY[] = { 0,0,0,0,0 }
The problem is I can have a LOT of objects on the screen that needs to be tracked. Is there a way to add integers / create new blocks as needed? IE in a loop, do something like
gridX[].add(); or something like that. I'm relatively new to java and droid development and I'm having trouble finding a good tutorial or example that shows how to do this without having to initialize the gridX and gridY to sizes of 100 or so.
This is important, as I am about 90% sure that all those unused 0's are causing androids garbage cleanup to lag my application.
Why dont you use an array list instead of an Integer array?
that way you can dynamically add items to the list
ArrayList<Integer> myList = new ArrayList<Integer>();
myList.add(1);
myList.add(2);
Why not also use the Point class?
List<Point> points = new ArrayList<Point>();
points.add(new Point(0, 0));
points.add(new Point(50, 70));
Point point = points.get(1);
Log.d("MyApp", String.format("The point is: (%d, %d)", point.x, point.y);
This way you are keeping track of your x and y coordinates together and there is less opportunity for error.

Categories

Resources