Giter VIP home page Giter VIP logo

androidplot's Introduction

image Androidplot AndroidPlot Codix codecov Twitter URL

A library for creating dynamic and static charts in Android apps.

Androidplot is compatible with all versions of Android from 1.6 onward, works equally with Kotlin and Java codebases and is compatible with Jetpack compose.

If you enjoy the lib, please rate us on codix.io!

Features:

  • Line Charts
  • Scatter Charts
  • Bar Charts
  • Pie Charts
  • Step Charts
  • Candlestick Charts
  • Bubble Charts
  • Dynamic plots
  • Pan & Zoom

Usage

Links

Help

Technical questions should be posted using the androidplot tag on Stack Overflow. For everything else use the Google Groups forum.

License

Androidplot has been made available under the Apache 2.0 license:

Copyright 2021 Androidplot.com

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

androidplot's People

Contributors

akg339 avatar daberni avatar ened avatar farfromrefug avatar guycnicholas avatar halfhp avatar hannesa2 avatar jonathan727 avatar kelnage avatar lucaspalmer8 avatar mirakels avatar mithepner avatar mriveralee avatar mtjin avatar phisi avatar robertszymacha avatar sourcebits-splisson avatar starkca90 avatar topherbuckley avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

androidplot's Issues

Lots of Double objects eating up memory w/ fast plotting

Hey there,

Been using the library for a while to plot fast biosensor data and just interested in optimizing it now.

I notice that when the graph is running, the app keeps using more memory until it quickly hits the garbage collection limit, when it falls back down and keeps climbing. Memory monitor looks like a sawtooth pattern.

With some memory sleuthing, I identified the culprit as being a vast number of Double objects corresponding to the x and y dimensions of my plot. I believe the Doubles are being created by the many doubleValue() calls in the transform and length functions in Region.java

Is there anyway to cut down the number of calls here or convert these Double classes to primitives? I'll be taking a look myself here, but not too familiar with what this class does.

I think this fix could go a long way to making the library more applicable for fast, dynamic graphing

Graph doesn't resize when layout size changes

I set an onTouchListener on the XYPlot to hide my LinearLayout with buttons (let's call it controlPanel) so there would be more space for the graph, but once the controlPanel is gone, the plot fills the new available height and yet the graph stays at the same size. Please look at the screens and you'll know what my issue is. I tried calling plot.redraw() and plot.getGraph.refreshLayout() after changing controlPanel's visibility but to no effect. The graph resizes itself correctly when I make the controlPanel gone and change orientation and viceversa (of course I'm saving the controlPanel's state to keep the visibility status).
screenshot_20180221-115349
screenshot_20180221-115353

How to remove the space taken by Labels

Hi,

I'm migrating my project from AndroidPlot 0.9.8 to 1.2.2

At some point, I need to set the Y labels width to 0.
I used to it like this : this.plot.getGraph().setRangeTickLabelWidth(0);

How can I do the same with the last version of androidPlot ??

Thanks,
Regards
Mike

PanZoom doesn't mix well with ScrollView

If you have a PanZoom on a plot in a ScrollView, they don't play too nicely together. You can pan for half an inch or so, but once you reach the limit where the scrollview would normall scroll, it does so, and the plot stops panning. It kinda works, and it could be worse, but it'd be a lot nicer if the graph panned when you dragged on the plot itself (as opposed to the legend, perhaps), and it the graph couldn't pan further in that direction, the scrollview scrolled instead.

Can't add series after view creation

Once the view is created, I can no longer add series to the plot. This is problematic because I'm asynchronously loading data from a server, and can't add the series until the data gets back.

To be slightly more detailed, if I add series during view creation, they show up fine. If I add series afterwards, however, the plot shows no change.

Database

How to plot this graph from database instead of static data?

XYLegendWidget Suboptimal Sizing

Hello,

XYLegendWidget

Issue: If you have, say, 5 SeriesBundle with 2 legendenabled==false it
shows 3 legends and 2 empty cells, which is wasted space.

Row 191
int nWithoutLegend = plot.getRegistry().getSeriesList().size() -
plot.getRegistry().getLegendEnabledItems().size();
seriesCount -= nWithoutLegend;

as quick fix works for me.

Thanks

NumberFormatException in the View Inflation containing Android Plot

08-19 19:59:25.694 4505-4505/com.lightstreamer.simple_demo.android E/AndroidRuntime: FATAL EXCEPTION: main Process: com.lightstreamer.simple_demo.android, PID: 4505 android.view.InflateException: Binary XML file line #46: Binary XML file line #46: Error inflating class com.androidplot.xy.XYPlot Caused by: android.view.InflateException: Binary XML file line #46: Error inflating class com.androidplot.xy.XYPlot Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Constructor.newInstance0(Native Method) at java.lang.reflect.Constructor.newInstance(Constructor.java:430) at android.view.LayoutInflater.createView(LayoutInflater.java:645) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:787) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727) at android.view.LayoutInflater.rInflate(LayoutInflater.java:858) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821) at android.view.LayoutInflater.rInflate(LayoutInflater.java:861) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821) at android.view.LayoutInflater.inflate(LayoutInflater.java:518) at android.view.LayoutInflater.inflate(LayoutInflater.java:426) at com.lightstreamer.simple_demo.android.DetailsFragment.onCreateView(DetailsFragment.java:85) at android.support.v4.app.Fragment.performCreateView(Fragment.java:2343) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1419) at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1740) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1809) at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:799) at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2580) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2367) at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2322) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2229) at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:700) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6121) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779) Caused by: java.lang.NumberFormatException: For input string: "@2131034204" at java.lang.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1306) at java.lang.Float.parseFloat(Float.java:459) at com.androidplot.util.Configurator.parseFloatAttr(Configurator.java:150) at com.androidplot.util.Configurator.inflateParams(Configurator.java:236) at com.androidplot.util.Configurator.configure(Configurator.java:322) at com.androidplot.util.Configurator.configure(Configurator.java:286) at com.androidplot.Plot.loadAttrs(Plot.java:371) at com.androidplot.Plot.init(Plot.java:316) at com.androidplot.Plot.<init>(Plot.java:249) at com.androidplot.xy.XYPlot.<init>(XYPlot.java:150) at java.lang.reflect.Constructor.newInstance0(Native Method)  at java.lang.reflect.Constructor.newInstance(Constructor.java:430)  at android.view.LayoutInflater.createView(LayoutInflater.java:645)  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:787)  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727)  at android.view.LayoutInflater.rInflate(LayoutInflater.java:858)  at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821)  at android.view.LayoutInflater.rInflate(LayoutInflater.java:861)  at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821)  at android.view.LayoutInflater.inflate(LayoutInflater.java:518)  at android.view.LayoutInflater.inflate(LayoutInflater.java:426)  at com.lightstreamer.simple_demo.android.DetailsFragment.onCreateView(DetailsFragment.java:85)  at android.support.v4.app.Fragment.performCreateView(Fragment.java:2343)  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1419)  at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1740)  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1809)  at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:799)  at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2580)  at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2367)  at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2322)  at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2229)  at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:700)  at android.os.Handler.handleCallback(Handler.java:751)  at android.os.Handler.dispatchMessage(Handler.java:95)  at android.os.Looper.loop(Looper.java:154)  at android.app.ActivityThread.main(ActivityThread.java:6121)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779) 

com.lightstreamer.simple_demo.android.DetailsFragment.onCreateView(DetailsFragment.java:85)

this piece of code is a below:
View view = inflater.inflate(R.layout.details_view, container, false);

Please advise...
Thanks in Advance

Storing series data in onSaveInstanceState broken

This feature is broken and crashes the app (including the demo app). Try tapping out of the Zoom example.
As far as I can see the bundle.putSerializable("seriesRegistry", plot.getRegistry()); call tries to serialize stuff that is not serializeable like Paint objects.

Attributes conflict

Hello,
I used androidplot 0.6.0 before and I tried latest 1.4.1 today. I created an empty project and add compile "com.androidplot:androidplot-core:1.4.1". However, I got errors:
\Androidplot-test\app\build\intermediates\res\merged\debug\values\values.xml
Error:(305) Attribute "title" has already been defined
Error:(312) Attribute "titleTextColor" has already been defined
Error:Execution failed for task ':app:processDebugResources'.

com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command '\Local\Android\Sdk\build-tools\23.0.3\aapt.exe'' finished with non-zero exit value 1

Cannot resize a SimpleXYSeries if it's a Y values only format

Hello

Your library looks great !

I just noticed that calling the SimpleXYSeries.resize() throws a NullPointerException if the serie is using Y_VALS_ONLY format.

I would be neat if resize() would work also with Y_VALS_ONLY series.

Cheers
Mathias

How can I see all predefined androidplot styles

I'm using androidplot 1.4.1 and I'd like to check all available predefined styles. In the quick start, it uses style="@style/APDefacto.Dark". Where can I see other available styles? Thanks.

ArrayIndexOutOfBoundsException in FastLineAndPointRenderer during intensive plot rendering

I was delighted to find that the FastLineAndPointRenderer class had been added, as it increased the fps of a live sensor data plot in my app to a consistent 40-50fps.

However, I've been noticing occasional flickering of the graph, accompanied by index out of bounds exceptions thrown in FastLineAndPointRenderer. I took a look at the code myself and couldn't figure out how to fix it, though.

There's two cases I've noticed that will trigger the flickering:

  1. The thread that adds values to the data series rendered by the FastLineAndPointRenderer is set to run in background priority
  2. Two sensor data plots are displayed at the same time.

Here's the relevant part of the error code:

E/com.androidplot.Plot: Exception while rendering Plot.
java.lang.ArrayIndexOutOfBoundsException: length=428; index=428
at com.androidplot.xy.FastLineAndPointRenderer.onRender(FastLineAndPointRenderer.java:73)
at com.androidplot.xy.FastLineAndPointRenderer.onRender(FastLineAndPointRenderer.java:32)
at com.androidplot.ui.SeriesRenderer.render(SeriesRenderer.java:59)
at com.androidplot.xy.XYGraphWidget.drawData(XYGraphWidget.java:760)
at com.androidplot.xy.XYGraphWidget.doOnDraw(XYGraphWidget.java:461)

Auto range boundaries are not calculated correctly when using a fixed domain range and a FastXYSeries

When using a FastXYSeries on a plot with fixed domain boundaries but auto range boundaries, the bounds are incorrectly calculated in SeriesUtils.

screenshot

Below is a modified version of SimpleXYPlotActivity which demonstrates the issue.


package com.androidplot.demos;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;

import com.androidplot.xy.BoundaryMode;
import com.androidplot.xy.FastXYSeries;
import com.androidplot.xy.LineAndPointFormatter;
import com.androidplot.xy.RectRegion;
import com.androidplot.xy.XYGraphWidget;
import com.androidplot.xy.XYPlot;
import com.google.common.math.Stats;

import java.text.DecimalFormat;
import java.util.ArrayList;

/**
 * A simple XYPlot
 */
public class SimpleXYPlotActivity extends Activity {

    private XYPlot plot;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.simple_xy_plot_example);

        // initialize our XYPlot reference:
        plot = (XYPlot) findViewById(R.id.plot);

        // create a couple arrays of y-values to plot:
        final ArrayList<Integer> times = new ArrayList<>();
        final ArrayList<Integer> values = new ArrayList<>();


        for (int i = 0; i < 10; i++) {
            times.add(i);
            values.add(2 * i);
        }

        FastXYSeries fastXYSeries = new FastXYSeries(){

            @Override
            public int size() {
                return times.size();
            }

            @Override
            public Number getX(int index) {
                return times.get(index);
            }

            @Override
            public Number getY(int index) {
                return values.get(index);
            }

            @Override
            public String getTitle() {
                return "Isaac's crazy thing";
            }

            @Override
            public RectRegion minMax() {
                Stats yStats = Stats.of(values);
                return new RectRegion(
                        times.get(0),
                        times.get(times.size() - 1),
                        yStats.min(),
                        yStats.max()
                );
            }
        };

        // add a new series' to the xyplot:
        plot.addSeries(fastXYSeries, new LineAndPointFormatter(Color.RED, Color.BLUE, null, null));

        plot.setDomainLowerBoundary(5, BoundaryMode.FIXED);
        plot.setDomainUpperBoundary(9, BoundaryMode.FIXED);
        plot.getGraph().getLineLabelStyle(XYGraphWidget.Edge.BOTTOM).setFormat(new DecimalFormat());
    }
}

SeriesUtils.minMax will return bounds with a minimum Y and maximum Y both set to the maxY or the series.

public static RectRegion minMax(XYConstraints constraints, XYSeries... seriesArray) {

    final RectRegion bounds = new RectRegion();

    // make sure there is series data to iterate over:
    if (seriesArray != null && seriesArray.length > 0) {

        // iterate over each series
        for (XYSeries series : seriesArray) {

            // if this is an advanced xy series then minMax have already been calculated for us:
            if(series instanceof FastXYSeries) {
                final RectRegion seriesBounds = ((FastXYSeries) series).minMax();
                if (seriesBounds == null) {
                    continue;
                }
                if(constraints == null) {
                    bounds.union(seriesBounds);
                } else {
                    //the following condition will be false
                    if (constraints.contains(seriesBounds.getMinX(), seriesBounds.getMinY())) {
                        bounds.union(seriesBounds.getMinX(), seriesBounds.getMinY());
                    }
                    //the following condition will be true
                    if (constraints.contains(seriesBounds.getMaxX(), seriesBounds.getMaxY())) {
                        bounds.union(seriesBounds.getMaxX(), seriesBounds.getMaxY());
                    }
                }

            } else if (series.size() > 0) {
                for (int i = 0; i < series.size(); i++) {
                    final Number xi = series.getX(i);
                    final Number yi = series.getY(i);

                    // if constraints have been set, make sure this xy coordinate exists within them:
                    if (constraints == null || constraints.contains(xi, yi)) {
                        bounds.union(xi, yi);
                    }
                }
            }
        }
    }
    return bounds;
}

I've fixed it by writing a method which constrains the seriesBounds in my fork's branch. I'm not sure this is the right fix though, so I didn't make a pull request. My linked change puts data back on the screen but the y range still includes the full extents of the FastXYSeries instead of the constrained FastXYSeries. I wondered if there shouldn't be a method like Region yMinMax(Number xMin, Number xMax) to better calculate that or if I should just tell my implementations of FastXYSeries to consider the current boundary settings while calculating minmax. Thoughts?

Method Canvas.save(int) has been removed from Android SDK (API 28)

My app uses Android Plot for a simple XY plot (lines).

Just updated to API 28 (targetSdkVersion and compileSdkVersion)

It does not build anymore, see the output:

Warning: com.androidplot.pie.PieRenderer: can't find referenced method 'int save(int)' in library class android.graphics.Canvas
Warning: com.androidplot.ui.LayoutManager: can't find referenced method 'int save(int)' in library class android.graphics.Canvas
Warning: com.androidplot.ui.SeriesRenderer: can't find referenced method 'int save(int)' in library class android.graphics.Canvas
Warning: com.androidplot.ui.widget.TextLabelWidget: can't find referenced method 'int save(int)' in library class android.graphics.Canvas
Warning: com.androidplot.xy.LineAndPointRenderer: can't find referenced method 'int save(int)' in library class android.graphics.Canvas
Warning: com.androidplot.xy.XYGraphWidget: can't find referenced method 'int save(int)' in library class android.graphics.Canvas

In fact Canvas.save(int) has been removed from the SDK in API 28. In was deprecated since 28, now it is fully removed and you should call Canvas.save() instead

Duplicated attributes from AppCompat

Antroidplot uses two attributes: title and titleTextColor which are already defined in AppCompat library.
This means that you simply cannot use Antroidplot >=1.0 in projects where AppCompat is required.

Could you please make a release tag?

Thank you for making a very useful library. It really helps. There is a favor to ask. I'd like you to create a release tag of version 1.4.1 Thank you.

CatmullRomInterpolator fails with null Pointer Exception

At codeLine 146 and 147 in CatmullRomInterpolator.java

int n = series.size() -1; dx = series.getX(n).doubleValue() - series.getX(n-1).doubleValue();

CodeLine 102:
public int size() { return series.size() + 2; }

You override the size of the Series by +2 and then try to access thnull e index at n-1 which is 1 past the end of its bounds. This throws a nullPointer Exception and fails.
This originally was working in my application but now as started failing.
Breakingpoint right before it fails shows Size is 21 but series only has 19 elements. then Element 20 is accessed which fails.

Graph is finnicky about size

I've been struggling to get the graph to show up consistently. wrap_content doesn't work, which I guess makes some sense. When I use a scrollview, for when my other views take up too much space, match_parent shrinks the graph to nothing, which also makes some sense. Less sensical is that when I set the graph to be 1138dp wide or wider, the graph doesn't show up at all - there's just a big white empty space the same size as the graph ought to be. Similar things appear to happen for height. I think the specific thresholds may be specific to screen, device, or layout.

In an attempt to get a consistently non-weird size, I've wrapped the graph in a PercentRelativeLayout. Which...I think wasn't working but now apparently is? Not sure I trust it, yet, but it's working for now.

Android resource compilation failed

When I do :
implementation 'com.androidplot:androidplot-core:1.5.6'

With:
Android Studio 3.3 Canary 6
Build #AI-182.3684.101.33.4954005, built on August 15, 2018
JRE: 1.8.0_152-release-1136-b06 amd64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Windows 10 10.0

I can't compile :
Android resource compilation failed
C:\Users\Pascal\Desktop\PalIrri\palIrri\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:4758: error: duplicate value for resource 'attr/backgroundColor' with config ''.
C:\Users\Pascal\Desktop\PalIrri\palIrri\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:4758: error: resource previously defined here.

Should check if canvas is null before drawing the chart

The canvas parameter of the onDraw method can be null therefore it should be checked before attempting to draw the chart. In the case below, the app is crashing when the background rendering task that is printing charts in PDF is canceled before views are fully rendered and the cause of that crash is traced to the onDraw method.

06-12 12:39:43.814 18988-19253/my.domain.myapp E/com.androidplot.Plot: Exception while rendering Plot.
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawColor(int, android.graphics.PorterDuff$Mode)' on a null object reference
at com.androidplot.Plot.renderOnCanvas(Plot.java:817)
at com.androidplot.Plot$1.run(Plot.java:390)
at java.lang.Thread.run(Thread.java:818)
06-12 12:39:43.817 18988-19252/my.domain.myapp E/com.androidplot.Plot: Exception while rendering Plot.
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawColor(int, android.graphics.PorterDuff$Mode)' on a null object reference
at com.androidplot.Plot.renderOnCanvas(Plot.java:817)
at com.androidplot.Plot$1.run(Plot.java:390)
at java.lang.Thread.run(Thread.java:818)
06-12 12:39:43.836 18988-19254/my.domain.myapp E/com.androidplot.Plot: Exception while rendering Plot.
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawColor(int, android.graphics.PorterDuff$Mode)' on a null object reference
at com.androidplot.Plot.renderOnCanvas(Plot.java:817)
at com.androidplot.Plot$1.run(Plot.java:390)
at java.lang.Thread.run(Thread.java:818)
'

Number Exception with fillPaintColor

In Androidplot 1.5.1, I got a NumberException with the fillPaintColor set to #00000000 in the code below. It works when the fillPaintColor is set to #000000. A work around is to manually call the setFillPaint method.

LineAndPointFormatter averageFormat = new LineAndPointFormatter(); averageFormat.setPointLabelFormatter(new PointLabelFormatter()); averageFormat.configure(context, R.xml.plot_average_line);
plot_average_line
<?xml version="1.0" encoding="utf-8"?> <config linePaint.strokeWidth="2dp" linePaint.color="@color/IndianRed" vertexPaint.color="@color/IndianRed" vertexPaint.strokeWidth="2dp" fillPaint.color="#00000000"/>

Problem with skipping points in XYPlot

As suggested here I used null values in yVals for generating a new series:

XYSeries series1 = new SimpleXYSeries(xVals, yVals, "f(x) = tan(x)");

This seems to throw an NullPointerException in LineAndPointRenderer.java, but the app does not crash (caught somewhere?).

java.lang.NullPointerException: Attempt to read from field 'float android.graphics.PointF.x' on a null object reference
at com.androidplot.xy.LineAndPointRenderer.renderPoints(LineAndPointRenderer.java:252)
at com.androidplot.xy.LineAndPointRenderer.drawSeries(LineAndPointRenderer.java:218)
at com.androidplot.xy.LineAndPointRenderer.onRender(LineAndPointRenderer.java:67)
at com.androidplot.xy.LineAndPointRenderer.onRender(LineAndPointRenderer.java:40)
at com.androidplot.ui.SeriesRenderer.render(SeriesRenderer.java:59)
at com.androidplot.xy.XYGraphWidget.drawData(XYGraphWidget.java:814)
at com.androidplot.xy.XYGraphWidget.doOnDraw(XYGraphWidget.java:505)
at com.androidplot.ui.widget.Widget.draw(Widget.java:357)
at com.androidplot.ui.LayoutManager.draw(LayoutManager.java:108)
at com.androidplot.Plot.renderOnCanvas(Plot.java:822)
at com.androidplot.Plot.onDraw(Plot.java:794)
at android.view.View.draw(View.java:16435)
at android.view.View.buildDrawingCacheImpl(View.java:15700)
at android.view.View.buildDrawingCache(View.java:15554)
at android.view.View.draw(View.java:16182)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.updateDisplayListIfDirty(View.java:15380)
at android.view.View.draw(View.java:16189)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.updateDisplayListIfDirty(View.java:15380)
at android.view.View.draw(View.java:16189)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.updateDisplayListIfDirty(View.java:15380)
at android.view.View.draw(View.java:16189)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at com.android.internal.policy.PhoneWindow$DecorView.dispatchDraw(PhoneWindow.java:2754)
at android.view.View.draw(View.java:16447)
at com.android.internal.policy.PhoneWindow$DecorView.draw(PhoneWindow.java:2740)
at android.view.View.updateDisplayListIfDirty(View.java:15388)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:286)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:292)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:327)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:3040)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2844)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2456)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1341)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6818)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:894)
at android.view.Choreographer.doCallbacks(Choreographer.java:696)
at android.view.Choreographer.doFrame(Choreographer.java:631)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:880)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5728)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)

When rendering just one series, this seems to be no problem at all. But when trying to render a second after such error, the second series is not drawn (even the label of the first one isn't drawn).

For my application I need a plotting library that can plot mathematical functions, so I tried the FXPlotExample from your demoapp folder and modified it to display tan(x).

This is my complete code (modification to the example start at bottom, indicated by comment):

package com.androidplot.demos;

import android.app.*;
import android.graphics.*;
import android.os.*;

import com.androidplot.util.*;
import com.androidplot.xy.*;

import java.text.*;
import java.util.*;

/**
 * A simple XYPlot
 */
public class FXPlotExampleActivity extends Activity {

    private XYPlot plot;

    /**
     * Custom line label renderer that highlights origin labels
     */
    class MyLineLabelRenderer extends XYGraphWidget.LineLabelRenderer {

        @Override
        protected void drawLabel(Canvas canvas, String text, Paint paint,
                float x, float y, boolean isOrigin) {
            if(isOrigin) {
                // make the origin labels red:
                final Paint originPaint = new Paint(paint);
                originPaint.setColor(Color.RED);
                super.drawLabel(canvas, text, originPaint, x, y , isOrigin);
            } else {
                super.drawLabel(canvas, text, paint, x, y , isOrigin);
            }
        }
    }

    /**
     * Draws every other tick label and renders text in gray instead of white.
     */
    class MySecondaryLabelRenderer extends MyLineLabelRenderer {


        @Override
        public void drawLabel(Canvas canvas, XYGraphWidget.LineLabelStyle style,
                Number val, float x, float y, boolean isOrigin) {
            if(val.doubleValue() % 2 == 0) {
                final Paint paint = style.getPaint();
                if(!isOrigin) {
                    paint.setColor(Color.GRAY);
                }
                super.drawLabel(canvas, style, val, x, y, isOrigin);
            }
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fx_plot_example);

        // initialize our XYPlot reference:
        plot = (XYPlot) findViewById(R.id.plot);

        plot.setDomainStep(StepMode.INCREMENT_BY_VAL, 1);
        plot.setRangeStep(StepMode.INCREMENT_BY_VAL, 1);

        plot.centerOnDomainOrigin(0);
        plot.centerOnRangeOrigin(0);

        // create formatters to use for drawing a series using LineAndPointRenderer
        // and configure them from xml:
        LineAndPointFormatter series1Format =
                new LineAndPointFormatter(this, R.xml.line_point_formatter);

        // use our custom renderer to make origin labels red
        plot.getGraph().setLineLabelRenderer(XYGraphWidget.Edge.BOTTOM, new MyLineLabelRenderer());
        plot.getGraph().setLineLabelRenderer(XYGraphWidget.Edge.LEFT, new MyLineLabelRenderer());

        // skip every other line for top and right edge labels
        plot.getGraph().setLineLabelRenderer(XYGraphWidget.Edge.RIGHT, new MySecondaryLabelRenderer());
        plot.getGraph().setLineLabelRenderer(XYGraphWidget.Edge.TOP, new MySecondaryLabelRenderer());

        // don't show decimal places for top and right edge labels
        plot.getGraph().getLineLabelStyle(XYGraphWidget.Edge.TOP).setFormat(new DecimalFormat("0"));
        plot.getGraph().getLineLabelStyle(XYGraphWidget.Edge.RIGHT).setFormat(new DecimalFormat("0"));

        // create a dash effect for domain and range grid lines:
        DashPathEffect dashFx = new DashPathEffect(
                new float[] {PixelUtils.dpToPix(3), PixelUtils.dpToPix(3)}, 0);
        plot.getGraph().getDomainGridLinePaint().setPathEffect(dashFx);
        plot.getGraph().getRangeGridLinePaint().setPathEffect(dashFx);

        //----------------------------------------------------------------------------------------------------------
        /// modifications starting here:
        //----------------------------------------------------------------------------------------------------------
        // add a new series' to the xyplot:
        plot.setRangeBoundaries(-10, 10, BoundaryMode.FIXED);
        plot.addSeries(generateSeries(-5, 5, 300), series1Format);
        plot.addSeries(generateSeries1(-5, 5, 10), series1Format);
    }

    protected XYSeries generateSeries(double minX, double maxX, double resolution) {
        final double range = maxX - minX;
        final double step = range / resolution;
        List<Number> xVals = new ArrayList<>();
        List<Number> yVals = new ArrayList<>();

        double x = minX;
        while (x <= maxX) {
            xVals.add(x);
            double value = fx(x);
            if (value >= -15 && value <= 15)
                yVals.add(value);
            else
                yVals.add(null);
            x +=step;
        }

        return new SimpleXYSeries(xVals, yVals, "f(x) = tan(x)");
    }

    protected XYSeries generateSeries1(double minX, double maxX, double resolution) {
        final double range = maxX - minX;
        final double step = range / resolution;
        List<Number> xVals = new ArrayList<>();
        List<Number> yVals = new ArrayList<>();

        double x = minX;
        while (x <= maxX) {
            xVals.add(x);
            yVals.add(x);
            x +=step;
        }

        return new SimpleXYSeries(xVals, yVals, "g(x) = x");
    }


    protected double fx(double x) {
        return Math.tan(x);
    }
}

For a quick fix I changed the rendering order, so that the "problematic" series is second:

plot.addSeries(generateSeries1(-5, 5, 10), series1Format);
plot.addSeries(generateSeries(-5, 5, 300), series1Format);

Now they are both plotted, but the labels are still missing.

The proper fix would be to check for null in LineAndPointRenderer.java:

@@ -246,6 +246,8 @@ public class LineAndPointRenderer<FormatterType extends LineAndPointFormatter> e
             final PointLabeler pointLabeler = hasPointLabelFormatter ? formatter.getPointLabeler() : null;
             for(int i = iStart; i < iEnd; i++) {
                 PointF p = points.get(i);
+                if (p == null)
+                    continue;
 
                 // if vertexPaint is available, draw vertex:
                 if (vertexPaint != null) {

This way it seems to work as expected.
If this fix does not conflict with any other use cases, please consider to add it to the project!

QuickStart App error

I'm trying to adapt the example to my app but so far I'm getting this error:
Error inflating XML (class com.androidplot.xy.XYPlot): Setter requires param of unsupported type: class com.androidplot.ui.widget.TextLabelWidget
which apparently is a problem with the setContentView( R.layout.activity_graph ); statement in my onCreate() method. I've created the line_point_formatter_with_labels.xml resource as described in QuickStart, but can't find any documentation addressing my problem.

R.id.plot

This might be a dumb question but I am looking at the demo code for the ecg example, and was wondering where the line "R.id.plot" came from, and what it means to the broader code. Thank you in advance.

NaNs not supported

The following code results in an plot that only shows vertices, but no lines or shading:

plot.addSeries(new SimpleXYSeries(
		Arrays.asList(new Float[]{0f, 1f, 2f, 3f, 4f}),
		Arrays.asList(new Float[]{5f, 6f, Float.NaN, 4f, 2f}),
		"Data"
), new LineAndPointFormatter());

Replacing Float.NaN with any finite value fixes the problem. Ideally, NaNs should cause a break in the rendered line. For this dataset, I would expect to see two line segments with a break in between.

I'll see if I can implement my own renderer that does this, but I'm also not clear on the expected behavior of FastXYSeries interface when there are NaNs in the data. If all Y values are NaN, should the RectRegion Y min/max be NaN or null? The latter would simplify some of the code, but I don't know if it's acceptable to have an undefined min/max with a series size() > 0.

NullPointerException at com.androidplot.Plot$BufferedCanvas.recycle(Plot.java:240)

One of my users encountered a crash that was caused by androidplot attempting to recycle a null Bitmap, bgBuffer. The version of androidplot was 1.5.5.

--------- beginning of crash
E/AndroidRuntime(28933): FATAL EXCEPTION: Androidplot renderThread
E/AndroidRuntime(28933): Process: biz.innomatix.bluefontz, PID: 28933
E/AndroidRuntime(28933): java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Bitmap.
recycle()' on a null object reference
E/AndroidRuntime(28933):        at com.androidplot.Plot$BufferedCanvas.recycle(Plot.java:240)
E/AndroidRuntime(28933):        at com.androidplot.Plot$1.run(Plot.java:422)
E/AndroidRuntime(28933):        at java.lang.Thread.run(Thread.java:818)

I haven't looked into the precise conditions that could cause this yet. An easy solution would be to just check for null:

public void recycle() {
    if (bgBuffer != null) {
        bgBuffer.recycle();
        bgBuffer = null;
    }

    if (fgBuffer != null) {
        fgBuffer.recycle();
        fgBuffer = null;
    }
    System.gc();
}

This crash is probably pretty rare, I've never seen it myself while developing and testing.

How to disable the domain numbering ?

How to disable the domain numbering in android plot ?

    heartPulseRateMonitor.setDomainBoundaries(0, 4000, BoundaryMode.FIXED);
    heartPulseRateMonitor.getGraph().setDomainCursorPaint(null);
    heartPulseRateMonitor.getGraph().setDomainOriginLinePaint(null);
    heartPulseRateMonitor.getGraph().setDomainGridLinePaint(null);

I tried all these methods and still the domain boundaries are numbered from 0 to 4000. I am using the latest version of the library. These methods doesn't resolve as well.

 heartPulseRateMonitor.getGraphWidget().getDomainTickLabelPaint().setColor(Color.TRANSPARENT);
        heartPulseRateMonitor.getGraphWidget().getDomainOriginTickLabelPaint().setColor(Color.TRANSPARENT);

What is the option that I have ?

Layout Anchoring Issue (difference between v0.9.8 and v1.4.3)

I noticed a differenced with how the graph widget is being anchored (not sure if that's the right word to use) within it's layout. In version 0.9.8 of the library, the graph seems to take up all amount of reasonable space within the layout. However, in version 1.4.3 (which I believe is the latest), there is a giant margin below the graph.

Version 0.9.8:

v0 9 8

Version 1.4.3:

v1 4 3

I even tested this with a completely stripped down project which just has the XML layout setup:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
	     xmlns:tools="http://schemas.android.com/tools"
	     android:layout_width="match_parent"
	     android:layout_height="match_parent"
	     xmlns:ap="http://schemas.android.com/apk/res-auto"
	     android:background="#0099cc">

  <!-- The primary full-screen view. This can be replaced with whatever view
         is needed to present your content, e.g. VideoView, SurfaceView,
         TextureView, etc. -->
  <com.androidplot.xy.XYPlot
	  style="@style/APDefacto.Light"
	  android:id="@+id/fullscreen_content"
	  android:layout_width="match_parent"
	  android:layout_height="match_parent"
	  ap:title="A Simple XY Plot"/>

  <!-- This FrameLayout insets its children based on system windows using
         android:fitsSystemWindows. -->
  <FrameLayout
	  android:layout_width="match_parent"
	  android:layout_height="match_parent"
	  android:fitsSystemWindows="true">

    <LinearLayout
	    android:id="@+id/fullscreen_content_controls"
	    style="?metaButtonBarStyle"
	    android:layout_width="match_parent"
	    android:layout_height="wrap_content"
	    android:layout_gravity="bottom|center_horizontal"
	    android:background="@color/black_overlay"
	    android:orientation="horizontal"
	    tools:ignore="UselessParent">

      <Button
	      android:id="@+id/dummy_button"
	      style="?metaButtonBarButtonStyle"
	      android:layout_width="0dp"
	      android:layout_height="wrap_content"
	      android:layout_weight="1"
	      android:text="@string/dummy_button"/>

    </LinearLayout>
  </FrameLayout>

</FrameLayout>

What can I do to get rid of this margin below the graph or to otherwise make the graph layout behave in the same manner as it did in the earlier version?

This is a full-screen application, if that helps.

PanZoom errors with series of different sizes

When I have series with differing numbers of points, I get null pointer exceptions (and correspondingly glitchy graphics) when I try to zoom in.

E/com.androidplot.Plot: Exception while rendering Plot.
java.lang.NullPointerException: Attempt to read from field 'float android.graphics.PointF.x' on a null object reference
at com.androidplot.xy.LineAndPointRenderer.renderPoints(LineAndPointRenderer.java:225)
at com.androidplot.xy.LineAndPointRenderer.drawSeries(LineAndPointRenderer.java:190)
at com.androidplot.xy.LineAndPointRenderer.onRender(LineAndPointRenderer.java:50)
at com.androidplot.xy.LineAndPointRenderer.onRender(LineAndPointRenderer.java:37)
at com.androidplot.ui.SeriesRenderer.render(SeriesRenderer.java:59)
at com.androidplot.xy.XYGraphWidget.drawData(XYGraphWidget.java:769)
at com.androidplot.xy.XYGraphWidget.doOnDraw(XYGraphWidget.java:458)
at com.androidplot.ui.widget.Widget.draw(Widget.java:347)
at com.androidplot.ui.LayoutManager.draw(LayoutManager.java:109)
at com.androidplot.Plot.renderOnCanvas(Plot.java:822)
at com.androidplot.Plot$1.run(Plot.java:390)
at java.lang.Thread.run(Thread.java:818)

Note that when I put a breakpoint there, conditional on p == null, inspecting points shows no nulls, which leads me to suspect threading issues. On the other hand, I've put a breakpoint before the loop, and even inspecting points each time it stops there (each time showing no nulls) somehow I still get null pointer exceptions, which leads me to suspect debugger inconsistencies.

PanZoom doesnt support scroll without zoom

There are actually two issues to resolve here:
#1 If the plot starts out with a constrained boundary, PanZoom will not be able to extend beyond that boundary.
#2 There is no way to completely disable either Pan or Zoom modes. Need to add a NONE value for both.

Changing grid insets after the plot has been drawn once do not have effect

  • Description of the problem

Changing grid insets after the plot has been drawn once do not have effect.

  • Steps to reproduce the issue

After drawing the plot once
// kotlin
plot.clear()
plot.graph.gridInsets.bottom = PixelUtils.dpToPix(40f)
plot.redraw()

This is because XYGraphWidget onResize is the only place where gridInsets have an effect.
This is called by Widget checkSize which guards calling resize with size of the widget rect. CheckSize is called on widget.draw() But the widget rect does not change due to gridInset being changed.

One quick fix could be to call onResize whenever gridInsets is set.

  • Version(s) of Androidplot being used

1.5.4

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.