I'm currently working on a project using MPAndroidChart and i want to make a LineChart to represent data per hour. I need this chart to have gradient line depending on values on yAxis.
eg. In the graph above i want the line to change the color when yAxis values are >50.
I didn't find any solution to my problem, so any suggestions or examples are welcome
I've recently had to face the exact same problem, and the solution was to define a linear gradient and apply it as a shader, like this:
(Warning: You'll notice that the code looks funny, and that is because it is xamarin code (i.e: C#, not java nor kotlin), but you'll be able to translate it easily, mostly you have to change the PascalCase for camelCase, and change some properties into setters and getter or vice versa, just use your IDE's intellisense)
[set your line chart, add the dataset, etc]
...
var gradient = new LinearGradient(0f, 0f, 0f, 100f,
[your first color], [your second color],
Shader.TileMode.Clamp);
var paint = vh.Chart.Renderer.PaintRender;
paint.SetShader(gradient);
...
[set axis, labels, grid, etc]
...
lineChart.Invalidate(); //this is to refresh the chart on the screen, you may need it or not depending on your code
In the code above you just have to add your colors, and you may want to change the gradient direction (I'm using a vertical gradient here) by changing the 4 first floats when creating the linearGradient. One typical change is to set the y0 = 0 and y1 = the height of your chart, for example. You have to play with the values according to your layout.
The result for this code is something like:
Of course, I'm showing it with a repeated sample dataset, that's why you are seeing two cards with the same line.
UPDATE:
I understand what you want to achieve, and with the code above you can do it. You will need some calculations, of course, but you can set the "trigger" where the color starts to change at any Y coordinate you want.
For example, in this first picture, I've used the coordinates 0,0,0,100
(Please keep in mind that I'm showing you the last value in dp, but in the real code I am translating it to the equivalent in pixels according to the device's resolution. It is roughly the height of my chart)
And in the following image, I've changed it to 0,0,0,50:
As you can see, you have full control over how the gradient is shown just by changing the 4 values. (or, in my case, just one of them)
(You may notice that I've changed the colors as per my design, it has nothing to do with the threshold)
Lets say you are using for-loop to populate your data. In list you need to populate a list of colors for every value and then use lineDataSet.setColors(listOfColors).
List<Integer> listOfColors = new List<>();
for(i= 0; i<dataEntries.size(); i++){
//Logic for colors
if(i<= dataEntries.size()-1){ //Otherwise app will crash on last index
if(dataEntries.get(i+1).y > 50)
listOfColors.add(Color.GREEN);
else
listOfColors.add(Color.RED);
}
Then in the last
lineDataSet.setColors(listOfColors)
Hope, this will help you.
Related
I am developing an app, for which I am using androidplot library.
My requirement is to draw a curved graph - very similar to what is shown here
I am able to draw the smooth graph fine, but I want to remove the X and Y axes that are shown along with the graph. I need to display ONLY the waveform graph and not the X and Y co-ordinates. Is this possible? If so, how I can I achieve this?
Thanks in advance.
It would be helpful to see what you currently have, but going from the image you provided it sounds like you want to:
Remove domain and range grid lines
Remove vertices from the plotted line.
To remove domain & range grid lines, add this to your plot's xml:
ap:domainLineColor="#color/ap_transparent"
ap:rangeLineColor="#color/ap_transparent"
ap:domainOriginLineColor="#color/ap_transparent"
ap:rangeOriginLineColor="#color/ap_transparent"
To remove vertices from your plotted line, just pass in a null value for the vertex param of your LineAndPointFormatter's constructor. For example, this would draw a read line with no fill or vertices:
LineAndPointFormatter myLineFormat = new LineAndPointFormatter(Color.RED, null, null, null);
Using the android plot library and am struggling with how to get the bars on the plot to the same size. For some reason the first one of the series appears wider than the rest. See image for example.
As you can see the domain labels are position correctly and read the correct values. Here is the code that customises the format of the XYPlot.
BarFormatter series1Format = new BarFormatter();
plot.addSeries(series, series1Format);
BarRenderer renderer = (BarRenderer) plot.getRenderer( BarRenderer.class );
renderer.setBarRenderStyle(BarRenderer.BarRenderStyle.SIDE_BY_SIDE);
renderer.setBarWidthStyle(BarRenderer.BarWidthStyle.VARIABLE_WIDTH);
renderer.setBarGap(2.0f);
Paint series1Fill = new Paint();
series1Fill.setColor(plot.getContext().getResources().getColor(R.color.accent));
series1Format.setFillPaint(series1Fill);
plot.setTicksPerRangeLabel(2);
plot.getGraphWidget().setDomainGridLinePaint(null);
plot.setDomainStep(XYStepMode.INCREMENT_BY_VAL, 1);
plot.setRangeLowerBoundary(0,BoundaryMode.FIXED);
plot.setUserDomainOrigin(1);
plot.setDomainLowerBoundary(0.5, BoundaryMode.FIXED);
plot.setDomainUpperBoundary(series.size() + 0.5, BoundaryMode.FIXED);
plot.setBorderStyle(XYPlot.BorderStyle.NONE, null, null);
plot.setDomainValueFormat(new DecimalFormat("0"));
plot.setRangeValueFormat(new DecimalFormat("0"));
Obviously this is more noticeable with small data series like the example above. Appreciate any help on this.
At least part of the issue is due to your use of VARIABLE_WIDTH. In this mode, Androidplot calculates the width of each bar evenly subdividing the plot graph space. When you have data on the edge (as you do with bar #3 above) it gets cutoff because the calculated width of the bar bleeds past the border.
I'd suggest applying some border paint to your bar formatted so it's easier to see when your bars are getting cutoff. To resolve the issue, you have at least 3 options:
Use FIXED_WIDTH bars. Should be self explanatory.
Set fixed domain boundaries and show an extra value on both ends of the scale:
plot.setDomainBoundaries(-1, 3, BoundaryMode.FIXED);
Add grid padding to allow the edges to be drawn
fully. In the latest version of Androidplot you'd do something like
this:
plot.getGraphWidget().getGridBox().setPaddingLeft(PixelUtils.dpToPix(70));
plot.getGraphWidget().getGridBox().setPaddingRight(PixelUtils.dpToPix(70));
You'll likely have to play with it to get the right setting though. Also keep in mind that as the screen gets wider, so do the bars; what looks good in portrait mode might look bad in landscape.
On a side note, I'm stumped as to why in the graphic above the first bar actually appears wider than the middle bar. Without seeing more of the code though, I couldn't say what's causing that.
I am using Achartengine to generate TimeChart graph. The data set consists of dates form 1/15/2003 to 12/4/2040 (x-axis) with respective random values for Y-axis. I am displaying the graph dynamically where I keeps reading the values on background thread (AsyncTask) and repaints the graphview. I have 2 questions:
The view starts from Jan, 2, 1970(I dono why) and I have to scroll to 1/15/2003 to see the graph. What should I change to make it start from 1/15/2003 ?
Also I take 2 date values FROM and TO (Eg: FROM:2/17/2004 TO:6/23/2006) and I want to display the graph only in this range. Is there any way to do this?
I could solve the 1st one using mRenderer.setYAxisMin(new Date("1/15/2003 11:16:00 AM").getTime()) Although this is a deprecated method, but it did the work for me. Now when I display the graph its starts from given data not Jan, 2, 1970.
You can dynamically set Y axis min and max with values desired values, just before repainting.
And for the 1. question, maybe better option is to set pan limits, so you can't scroll to empty parts of your chart.
You can do it like this
mRenderer.setPanLimits(new double[]{xMin, xMax, yMin, yMax});
where you calculate limits like this
double xMin = minDate.getTime();
double xMax = maxDate.getTime();
I am working on a custom View that includes frequently updated text that I want to anchor to the bottom of the canvas.
The text length changes as well, and I'd like it to wrap, moving up the screen as more lines are needed. (DynamicLayout thus seems like a solid choice for automating this)
However, I don't see any options in the docs about specifying where on my canvas the text is drawn or in which direction it should "grow".
Here is my initialization:
TextPaint subtleTextPaint = new TextPaint();
DynamicLayout dl = new DynamicLayout(text,subtleTextPaint,getWidth()
,Layout.Alignment.ALIGN_CENTER,1,0,true);
And in onDraw(), I simply pass the canvas to the DynamicLayout object like so:
dl.draw(c);
Right now, the text is drawn at the very top of the screen and word-wraps downwards as the text gets longer.
After quite a bit of searching, I found nothing that did what I wanted. So, in true hacker style, I created my own solution. By extending the DynamicLayout class and overwriting the getLineTop() function, I was able to achieve the functionality I was looking for.
I've posted the source code here.
What i think 1st you get the Width of the screen and then set the Text with the X y according to your screen dimension
that will work
snippet is following
width=canvas.getWidth();
if(width==720)
{
canvas.drawText(String, x , y, drawText);
}
else if(width==480)
{
canvas.drawText(String, x , (y, drawText);
}
else
{
canvas.drawText(String, x , (y, drawText);
}
Still having a great time fiddling with aChartEngine, but I have come to a point where I could some help.
I'm looking to change the depth or z-index of the grid of a chart. But so far I haven't found any options in both the regular documentation as in the source to set the this.
Does anyone has a tip or solution regarding the grids in aChartEngine?
Thanks for your help!
I guess nobody has this issue, but just in case you might wonder how to change the depth of the grids in aChartEngine, I'll write it down here.
By default all the grids of aChartEngine are drawn on top of the graph itself. This happens in the public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) of the XYChart.java class.
Both the labels and grids are drawn in the same conditional, which checks whether (showLabels == true || showGrid == true)
First thing you might want to do is split the drawing of the labels and grid. Here's what I did:
Copy the whole conditional which checks for labels and grid, including the declaration of the 3 booleans showLabels, showGrid and showCustomTextGrid.
Paste it below boolean hasValues = false; (set this to true)
You'll have some errors in the class now, because of double declarations. Fix that later.
In the conditional you just pasted, remove the code to draw the labels. It's easy to find, since it starts with if (showLabels). Below the conditional set hasValues = false;
In the original conditional, remove the code to draw the grid. It's easy to find, since it starts with if (showGrid)
Now get rid of the double declarations, by setting the booleans showLabels, showGrid and showCustomTextGrid, or just use the old ones.
All the errors should be gone now, test your app. The labels and grid are now separated and the grid is shown behind your graph instead on top of it.
Hope it helps you.
Cheers!