0

这就是我目前在图表中添加线条的方式。这是我要显示的任意函数的抽象类:

public abstract class ArbitraryFunction implements
    ValueProvider<ArbitraryFunctionData, Double> {

  private String field;

  public abstract Double f(Double x);

  /**
   * Constructor
   */
  public ArbitraryFunction(String field) {
    this.field = field;
  }

  @Override
  public Double getValue(ArbitraryFunctionData object) {
    return object.get(field);
  }

  @Override
  public void setValue(ArbitraryFunctionData object, Double value) {
    object.put(field, value);
  }

  @Override
  public String getPath() {
    return field;
  }
}

这是创建图表的方式:

ArbitraryFunction f1 = new ArbitraryFunction("f1") {
      @Override
      public Double f(Double x) {
        return Math.sin(x);
      }
    };

functionMap.put(f1.getPath(), f1);

// collects the data of the functions and adds them to the store
for (Double x = 0.0; x <= 2 * Math.PI; x = x + 0.1) {
  ArbitraryFunctionData d = new ArbitraryFunctionData();
  d.setName("" + x);
  for (Map.Entry<String, ArbitraryFunction> entry : functionMap.entrySet()) {
    ArbitraryFunction tmp = entry.getValue();
    d.put(tmp.getPath(), tmp.f(x));
  }
  store.add(d);
}

chart.setStore(store);

verticalAxis.setPosition(Position.LEFT);
verticalAxis.addField(f1);
verticalAxis.setSteps(2);
verticalAxis.setMinorTickSteps(5);
chart.addAxis(verticalAxis);

这可以按预期工作。该图显示了我应该做的线条,并且垂直轴也是正确的。但是我在绘制水平轴时遇到了问题,因为我不知道我需要给出什么horizontalAxis.addField( ??? )。我尝试了几件事,但没有任何效果。

有谁知道我需要如何设置水平轴?

4

1 回答 1

1

您希望水平轴值是多少?它是另一个 NumericAxis - 每个数据点是否都有一个x应该绘制的值?循环中的每个d都有一个字符串name和一些值——也许你想要一个CategoryAxis<ArbitraryFunctionData, String>只绘制这些name值的?


看起来我之前误解了 - 您的 Function 对象仅用于设置,而不是更改您绘制数据的方式

我仍然不确定你在追求什么,但听起来你最想绘制一些线条。每个数据点 (ArbitraryFunctionData?) 似乎对每个正在使用的函数都有 Y 值,还有一个标题,但没有 X 值,所以没有办法用两个数字轴将每个点绘制为 (X,Y),就像 ( name, Y) 使用 CategoryAxis 和 NumericAxis。这或多或少会像这个示例一样结束:http ://www.sencha.com/examples/#ExamplePlace:linechart - 底部为字符串,侧面为数字。

这是一个,主要建立在你已经拥有的想法/结构之上:

public class FunctionPlotter implements EntryPoint {
  public static class ArbitraryFunctionData {
    private double xValue;
    private Map<String, Double> yValues = new HashMap<String, Double>();
    public double get(String key) {
      return yValues.get(key);
    }
    public void put(String key, double yValue) {
      yValues.put(key, yValue);
    }
    public double getXValue() {
      return xValue;
    }
    public void setxValue(double xValue) {
      this.xValue = xValue;
    }
  }
  public interface AFDProperties extends PropertyAccess<ArbitraryFunctionData> {
    //xvalue is unique, key off of that
    @Path("xValue")
    ModelKeyProvider<ArbitraryFunctionData> key();

    //automatic ValueProvider generation for the get/setXValue methods
    ValueProvider<ArbitraryFunctionData, Double> xValue();
  }

  /** 
   * This is really doing two different jobs at once - wasn't quite was I was trying to suggest in 
   * that other question. See the second version of this for clarification...
   */
  public static abstract class ArbitraryFunction implements ValueProvider<ArbitraryFunctionData, Double> {
    private final String field;

    public ArbitraryFunction(String field) {
      this.field = field;
    }

    public abstract Double f(Double x);

    @Override
    public Double getValue(ArbitraryFunctionData object) {
      return object.get(field);
    }

    @Override
    public void setValue(ArbitraryFunctionData object, Double value) {
      object.put(field, value);
    }

    @Override
    public String getPath() {
      return field;
    }
  }

  @Override
  public void onModuleLoad() {
    Viewport vp = new Viewport();

    Set<ArbitraryFunction> functions = new HashSet<ArbitraryFunction>();
    ArbitraryFunction f1 = new ArbitraryFunction("f1") {
      @Override
      public Double f(Double x) {
        return Math.sin(x);
      }
    };
    functions.add(f1);

    AFDProperties props = GWT.create(AFDProperties.class);
    ListStore<ArbitraryFunctionData> store = new ListStore<ArbitraryFunctionData>(props.key());
    // collects the data of the functions and adds them to the store
    for (Double x = 0.0; x <= 2 * Math.PI; x = x + 0.1) {
      // Create one data object, and set the X value, since that is the same for all Y values
      ArbitraryFunctionData d = new ArbitraryFunctionData();
      d.setxValue(x);

      // For each function, set the corresponding Y value
      for (ArbitraryFunction func : functions) {
        d.put(func.getPath(), func.f(x));
      }
      store.add(d);
    }

    Chart<ArbitraryFunctionData> chart = new Chart<ArbitraryFunctionData>();
    chart.setStore(store);

    //Y-axis
    NumericAxis<ArbitraryFunctionData> verticalAxis = new NumericAxis<ArbitraryFunctionData>();
    verticalAxis.setPosition(Position.LEFT);
    verticalAxis.addField(f1);//needs to know this field to properly set the range of values
    //f2, f3, etc
    verticalAxis.setSteps(2);
    verticalAxis.setMinorTickSteps(5);
    chart.addAxis(verticalAxis);

    // X-Axis, this time reading from the xValue, not the series of ValueProviders
    NumericAxis<ArbitraryFunctionData> horizAxis = new NumericAxis<ArbitraryFunctionData>();
    horizAxis.setPosition(Position.BOTTOM);
    horizAxis.addField(props.xValue());//same value for all
    horizAxis.setSteps(2);
    horizAxis.setMinorTickSteps(5);
    chart.addAxis(horizAxis);

    for (ArbitraryFunction func : functions) {
      LineSeries<ArbitraryFunctionData> line = new LineSeries<ArbitraryFunctionData>();
      // configure x axis
      line.setXAxisPosition(Position.BOTTOM);//where is it
      line.setXField(props.xValue());//what value do i use
      // configure y axis
      line.setYAxisPosition(Position.LEFT);//where is it
      line.setYField(func);//what value do i use

      //probably want to customized per func
      line.setStroke(RGB.GRAY);
      line.setStrokeWidth(2);

      chart.addSeries(line);
    }

    vp.setWidget(chart);
    RootPanel.get().add(vp);
  }
}

这里有两个,这次使用更简单的数据,实际上使函数成为自己的 ValueProvider,并保持数据简单 - 只是一个两倍!请注意,ValueProvider函数,我们从不自己调用 getValue,我们让轴/系列为我们做这件事!在此处添加了第二个函数以证明它确实有效。

public class FunctionPlotter implements EntryPoint {

  /**
   * Where did everything go? We're just making a ValueProvider now that can handle 
   * each number as a value, and working out the details from there
   *
   * For fun, added per-function coloring too
   */
  public abstract static class Function implements ValueProvider<Double, Double> {
    private final String name;
    private final Color color;
    public Function(String name, Color color) {
      this.name = name;
      this.color = color;
    }
    @Override
    public abstract Double getValue(Double object);

    @Override
    public String getPath() {
      return name;
    }
    @Override
    public void setValue(Double object, Double value) {
      //no-op
    }
    public Color getColor() {
      return color;
    }
  }

  @Override
  public void onModuleLoad() {
    Viewport vp = new Viewport();

    Set<Function> functions = new HashSet<Function>();
    Function f1 = new Function("f1", RGB.RED) {
      @Override
      public Double getValue(Double x) {
        return Math.sin(x);
      }
    };
    functions.add(f1);
    Function f2 = new Function("f2", RGB.BLACK) {
      @Override
      public Double getValue(Double x) {
        return Math.cos(x);
      }
    };
    functions.add(f2);

    //Turns out Stores can hold any objects - should probably factor out this key provider for reuse...
    ListStore<Double> store = new ListStore<Double>(new ModelKeyProvider<Double>() {
      @Override
      public String getKey(Double item) {
        return item.toString();
      }
    });
    // collects the data of the functions and adds them to the store
    for (Double x = 0.0; x <= 2 * Math.PI; x = x + 0.1) {
      store.add(x);
    }

    Chart<Double> chart = new Chart<Double>();
    chart.setStore(store);

    //Y-axis
    NumericAxis<Double> verticalAxis = new NumericAxis<Double>();
    verticalAxis.setPosition(Position.LEFT);
    for (Function func : functions) {
      verticalAxis.addField(func);//needs to know this field to properly set the range of values
    }
    verticalAxis.setSteps(2);
    verticalAxis.setMinorTickSteps(5);
    chart.addAxis(verticalAxis);

    // X-Axis, this time reading from the xValue, not the series of ValueProviders
    NumericAxis<Double> horizAxis = new NumericAxis<Double>();
    horizAxis.setPosition(Position.BOTTOM);
    horizAxis.addField(new IdentityValueProvider<Double>());//magic value provider that returns the same string
    horizAxis.setSteps(2);
    horizAxis.setMinorTickSteps(5);
    chart.addAxis(horizAxis);

    for (Function func : functions) {
      LineSeries<Double> line = new LineSeries<Double>();
      // configure x axis
      line.setXAxisPosition(Position.BOTTOM);//where is it
      line.setXField(new IdentityValueProvider<Double>());//what value do i use
      // configure y axis
      line.setYAxisPosition(Position.LEFT);//where is it
      line.setYField(func);//what value do i use

      //probably want to customized per func
      line.setStroke(func.getColor());
      line.setStrokeWidth(2);

      chart.addSeries(line);
    }

    vp.setWidget(chart);
    RootPanel.get().add(vp);
  }
}
于 2013-03-29T16:25:09.323 回答