使用"androidPlot"库绘制数学函数

3
我希望使用androidPlot库绘制像y=x^2+1这样的数学函数。我有"SimpleXYPlot"。它可以工作,但我不知道如何将其从sin更改为我的函数。
以下是代码:
   public class DynamicXYPlotActivity extends Activity {

// redraws a plot whenever an update is received:
private class MyPlotUpdater implements Observer {
    Plot plot;

    public MyPlotUpdater(Plot plot) {
        this.plot = plot;
    }

    @Override
    public void update(Observable o, Object arg) {
        plot.redraw();
    }
}

private XYPlot dynamicPlot;
private MyPlotUpdater plotUpdater;
SampleDynamicXYDatasource data;
private Thread myThread;

@Override
public void onCreate(Bundle savedInstanceState) {

    // android boilerplate stuff
    super.onCreate(savedInstanceState);
    setContentView(R.layout.dynamicxyplot_example);

    // get handles to our View defined in layout.xml:
    dynamicPlot = (XYPlot) findViewById(R.id.dynamicXYPlot);

    plotUpdater = new MyPlotUpdater(dynamicPlot);

    // only display whole numbers in domain labels
    dynamicPlot.getGraphWidget().setDomainValueFormat(new DecimalFormat("0"));

    // getInstance and position datasets:
    data = new SampleDynamicXYDatasource();
    SampleDynamicSeries sine1Series = new SampleDynamicSeries(data, 0, "Sine 1");
    SampleDynamicSeries sine2Series = new SampleDynamicSeries(data, 1, "Sine 2");

    LineAndPointFormatter formatter1 = new LineAndPointFormatter( Color.rgb(0, 0, 0), null, null, null );
    formatter1.getLinePaint().setStrokeJoin(Paint.Join.ROUND);
    formatter1.getLinePaint().setStrokeWidth(10);
    dynamicPlot.addSeries( sine1Series,formatter1 );

    LineAndPointFormatter formatter2 = new LineAndPointFormatter(Color.rgb(0, 0, 200), null, null, null);
    formatter2.getLinePaint().setStrokeWidth(10);
    formatter2.getLinePaint().setStrokeJoin(Paint.Join.ROUND);

    //formatter2.getFillPaint().setAlpha(220);
    dynamicPlot.addSeries(sine2Series, formatter2);

    // hook up the plotUpdater to the data model:
    data.addObserver(plotUpdater);

    // thin out domain tick labels so they dont overlap each other:
    dynamicPlot.setDomainStepMode(XYStepMode.INCREMENT_BY_VAL);
    dynamicPlot.setDomainStepValue(5);

    dynamicPlot.setRangeStepMode(XYStepMode.INCREMENT_BY_VAL);
    dynamicPlot.setRangeStepValue(10);

    dynamicPlot.setRangeValueFormat(new DecimalFormat("###.#"));

    // uncomment this line to freeze the range boundaries:
    dynamicPlot.setRangeBoundaries(-100, 100, BoundaryMode.FIXED);

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

@Override
public void onResume() {
    // kick off the data generating thread:
    myThread = new Thread(data);
    myThread.start();
    super.onResume();
}

@Override
public void onPause() {
    data.stopThread();
    super.onPause();
}

class SampleDynamicXYDatasource implements Runnable {

    // encapsulates management of the observers watching this datasource for update events:
    class MyObservable extends Observable {
        @Override
        public void notifyObservers() {
            setChanged();
            super.notifyObservers();
        }
    }

    private static final double FREQUENCY = 5; // larger is lower frequency
    private static final int MAX_AMP_SEED = 100; //100
    private static final int MIN_AMP_SEED = 10;  //10
    private static final int AMP_STEP = 1;
    public static final int SINE1 = 0;
    public static final int SINE2 = 1;
    private static final int SAMPLE_SIZE = 30;
    private int phase = 0;
    private int sinAmp = 1;
    private MyObservable notifier;
    private boolean keepRunning = false;

    {
        notifier = new MyObservable();
    }

    public void stopThread() {
        keepRunning = false;
    }

    //@Override
    public void run() {
        try {
            keepRunning = true; 
            boolean isRising = true; 
            while (keepRunning) {

                Thread.sleep(100); // decrease or remove to speed up the refresh rate.

                phase++;
                if (sinAmp >= MAX_AMP_SEED) {
                    isRising = false;
                } else if (sinAmp <= MIN_AMP_SEED) {
                    isRising = true;
                }

                if (isRising) {
                    sinAmp += AMP_STEP;
                } else {
                    sinAmp -= AMP_STEP;
                }
                notifier.notifyObservers();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public int getItemCount(int series) {
        return SAMPLE_SIZE;
    }

    public Number getX(int series, int index) {
        if (index >= SAMPLE_SIZE) {
            throw new IllegalArgumentException();
        }
        return index;
    }

    public Number getY(int series, int index) {
        if (index >= SAMPLE_SIZE) {
            throw new IllegalArgumentException();
        }
        double angle = (index + (phase))/FREQUENCY;
        double amp = sinAmp * Math.sin(angle);
        switch (series) {
            case SINE1:
                return amp;
            case SINE2:
                return -amp;
            default:
                throw new IllegalArgumentException();
        }
    }

    public void addObserver(Observer observer) {
        notifier.addObserver(observer);
    }

    public void removeObserver(Observer observer) {
        notifier.deleteObserver(observer);
    }

}

class SampleDynamicSeries implements XYSeries {
    private SampleDynamicXYDatasource datasource;
    private int seriesIndex;
    private String title;

    public SampleDynamicSeries(SampleDynamicXYDatasource datasource, int seriesIndex, String title) {
        this.datasource = datasource;
        this.seriesIndex = seriesIndex;
        this.title = title;
    }

    @Override
    public String getTitle() {
        return title;
    }

    @Override
    public int size() {
        return datasource.getItemCount(seriesIndex);
    }

    @Override
    public Number getX(int index) {
        return datasource.getX(seriesIndex, index);
    }

    @Override
    public Number getY(int index) {
        return datasource.getY(seriesIndex, index);
    }
    }
    }

=======================================================

在“Nick”说了些什么和其他小的补充之后,我得到了这个结果:

Result

但如我们所知:

https://www.google.com/search?q=y%3Dx%5E2%2B1&oq=y%3Dx%5E2%2B1&aqs=chrome..69i57j0l5.7056j0j7&sourceid=chrome&es_sm=93&ie=UTF-8

现在如何制作左侧?

我也在寻找如何冻结它。 - SDG69
你只看到抛物线的一半,因为现在你只有正x值。 - Nick
哈哈,我知道那个,但是我无法生成负的x值...我的意思是我不能给函数y正负两个值...实际上我已经尝试过使用“系列”、“索引”、“getX”函数,但是没有得到结果... (-_-) - SDG69
2个回答

1
使用上述代码可以修改SampleDynamicXYDatasource以实现您想要的功能。所有这些代码都是按正弦模式生成一些数据。我不知道您的x值将如何生成,因此这里修改了SampleDynamicXYDatasource.getY(...),仅使用原始代码,其中x=index以上,并使用您的函数生成y值:
        public Number getY(int series, int index) {
            if (index >= SAMPLE_SIZE) {
                throw new IllegalArgumentException();
            }
            Number x = getX(series, index);
            double y = Math.pow(x.doubleValue(), 2) + 1;
            switch (series) {
                case SINE1:
                    return y;
                case SINE2:
                    return -y;
                default:
                    throw new IllegalArgumentException();
            }
        }

当你进行这个更改时,你会发现绘图似乎不再是动画的了。(实际上它仍然是动画,但这并不重要)这是因为y现在完全是x的函数,而x值永远不会改变。
至于如何停止动画,当plot.redraw()被调用时,图形会重新绘制,这在上面的例子中是响应由Runnable实例SampleDynamicXYDatasource运行的线程生成的事件。使用上述示例,停止动画的最简单方法是将以下内容替换:
@Override
public void onResume() {
    // kick off the data generating thread:
    myThread = new Thread(data);
    myThread.start();
    super.onResume();
}

使用:

@Override
public void onResume() {
    dynamicPlot.redraw();
    super.onResume();
}

非常感谢,但我不知道如何定义/设置域(x轴)和范围(y轴)。我的意思是,例如值的范围在-20到20之间;好的。但我希望x/y轴都有-30到30的范围。再次感谢您之前的回答! - SDG69
它是 setRangeBoundaries(myVal, myOtherval, BoundaryMode.FIXED) 吗? - SDG69
没错:setRangeBoundaries(...) 和 setDomainBounaries(...) 是控制此项的方法。确保您生成的 x 值在定义的窗口内,否则您将看到一个空图。 - Nick

0
尝试替换此>>
public Number getX(int series, int index) {
    if (index >= SAMPLE_SIZE) {
        throw new IllegalArgumentException();
    }
    return index;
}

转换为>>

public Number getX(int series, int index) {
    if (index >= SAMPLE_SIZE) {
        throw new IllegalArgumentException();
    }
    return index - 15;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接