No announcement yet.
  • Filter
  • Time
Clear All
new posts

  • Chart X Axis Date


    I am using Smart GWT 3.0, fantastic product!

    I am doing some graphing. I can now get a graph to appear, but the XAxis does not see it as a date, instead as just a string value. So not spaced over time, but over intervals values. How can I get the XAxis to recognize the type. And even though my data source has the date field as type "date" I am getting a datetime back, while I just wanted the date.

    Here is code that generates a graph, ugly perhaps, but seems to work ... Sorry just learning the API.

    You guys rock! Really fun product.


    private FacetChart createChart () {
    FacetChart raviChart = new FacetChart();
    Facet dateFacet = new Facet("rdate");
    Facet legendFacet = new Facet("type");
    new FacetValue("ravi1", "Ravi 1")

    raviChart.setFacets(dateFacet, legendFacet);
    return raviChart;

    private RecordList GetRecordList () {
    RecordList myRecList = new RecordList();
    Record[] recArray = listGridHRAVI.getRecordList().toArray();
    for(int i = 0; i < recArray.length; i++) {
    Record record = recArray[i];
    Record entryRecord = new Record();
    Date valueDate = record.getAttributeAsDate("rdate");
    entryRecord.setAttribute("rdate", valueDate);
    entryRecord.setAttribute("type", "ravi1");
    entryRecord.setAttribute("ravi", record.getAttribute("ravi"));
    System.out.println("Date and RAVI " + record.getAttributeAsDate("rdate") + ", " +

    return myRecList;

  • #2
    If you want any particular String format for that date, just use DateTimeFormat to produce it and put it into "entryRecord" as a String.


    • #3
      private RecordList GetRecordList () {
      RecordList myRecList = new RecordList();
      Record[] recArray = listGridHRAVI.getRecordList().toArray();
      DateTimeFormat dtf = DateTimeFormat.getFormat("yyyy-MM-dd");
      for(int i = 0; i < recArray.length; i++) {
      Record record = recArray[i];
      Record entryRecord = new Record();
      Date valueDate = record.getAttributeAsDate("rdate");
      String strDate = dtf.format(valueDate);
      String strValue = record.getAttribute("ravi");
      entryRecord.setAttribute("rdate", strDate);
      entryRecord.setAttribute("type", "ravi1");
      entryRecord.setAttribute("ravi", strValue);
      System.out.println("Date is " + strDate + ", value is " + record.getAttribute("ravi"));
      return myRecList;

      Which gives me
      Date is 1986-05-31, value is 7
      Date is 1986-07-23, value is 23
      Date is 1986-10-07, value is 23
      Date is 1993-02-01, value is 13
      Date is 1996-03-05, value is 13
      Date is 2011-08-31, value is 13

      However when I graph this the xaxis, the dates, are all evenly spaced.

      Howe do I get the xaxis to see it as a graph and to space stuff out over time?



      • #4
        If the spacing should reflect the date, you're basically looking for a scatter plot, which isn't a built-in chart type. You could:

        1. pad out the data with blank values to get the spacing right

        2. sponsor an officially supported scatter plot mode

        3. build your own scatter plot based on DrawPane


        • #5

          Ok I dropped in the Annotate graph from google

          This draws a line graph that I wanted. But the resizing does not seem to work. I have tried several things. It does work the window is first drawn, but when resizes occur it does not figure it out.

          How does one get the Resize event/method for a VLayout>

          public GoogleLineGraph(ListGrid lg, VLayout tempChartLayout) {
          listGrid = lg;
          chartLayout = tempChartLayout;
          Runnable onLoadCallback = new Runnable() {
          public void run() {
          DataTable data = createHistoryTable(listGrid);
          AnnotatedTimeLine.Options options = AnnotatedTimeLine.Options.create();
          // options.setOption("Title", CHART_TITLE);
          // getting height / width is tricky ...
          myGraph = new AnnotatedTimeLine(data, options, listGrid.getWidthAsString(), chartLayout.getHeightAsString());

          // Load the visualization api, passing the onLoadCallback to be called
          // when loading is done.
          VisualizationUtils.loadVisualizationApi(onLoadCallback, AnnotatedTimeLine.PACKAGE);


          • #6

            Originally posted by Isomorphic View Post
            If the spacing should reflect the date, you're basically looking for a scatter plot, which isn't a built-in chart type. You could:

            1. pad out the data with blank values to get the spacing right

            2. sponsor an officially supported scatter plot mode

            3. build your own scatter plot based on DrawPane
            In the meantime, SmartGWT 3.1 does have a Scatter plot type, with the blogpost about v4.0 mentioning even more cooler things for the Scatter plot.

            Does it now also recognize dates (/with time) as values so irregular data points will be spaced according to its true 'place' time? Or would we need to map all dates to a [0,1] float interval first and use these to get the spacing right? (Question for current v3.1p or coming up in v4?)


            • #7
              Neither 3.1 nor 4.0 would currently automatically recognize Date instances as axis values on a Scatter plot.

              Mapping dates to [0,1] would only sort of work or might require hacks to work. You would need an AxisValueFormatter to format the [0,1] values into legible dates, but the AxisValueFormatter is used for both axes without any parameter to tell it which axis it's being used for.

              If the other axis displays values in the [0,1] range you'll have ambiguity; regardless you've have ambiguity for 0. You might be able to put together a hack based on knowing which axis draws first. For a supported solution, consider sponsoring official support for axes with date values.


              • #8
                Ok thanks, we'll keep it mind.
                I'm just creating a quick POC to include a chart with a bunch of points & lines for a lot of data. The requirements might change, but I feel the X is going to be datetime based.

                I do get good results already:
                I reformat a date "yyyy-mm-dd hh:mm:ss" to parse as float as "yyyymmdd.hhmmss" and that looks great in the chart and thought indeed of using a formatter to make the labels pretty again. I don't immediately understand why there's 1 and the same formatter used for all axes (I assume it's for X and all Ys)? Is that for switching facets?
                Is this also something possible to enhance?

                I do see something weird:
                * you can have a tooltip formatter which has (value, record) as arguments. But my record is inside an attribute named "record" in the incoming record there.
                * the graph doesn't reset its 'X & Y scale' when I do setData a few times on the same graph.


                • #9
                  We do plan to add axis-specific formatters.

                  You should automatically see axes update, but make sure you have the latest nightly build of 4.0d as there was a bug affecting this, fixed several weeks ago.

                  Also note again that currently, axes will always include 0. So if you're expecting auto-scaling to eliminate zero since all your points have numeric values in the 10s of millions, that won't currently happen.


                  • #10
                    APIs for defining axis-specific formatters will appear in tomorrow's 4.0d builds.


                    • #11
                      Here's some sample code showing how you could use Dates as axis values using the new axis formatter APIs.

                      Note, that the purpose of dividing the millisecond times of the Date values by 1 day (1000 * 60 * 60 * 24) is so that FacetChart will pick a multiple of 1 day for the gradation interval and therefore the formatted x-axis values will be more accurate.

                          import com.smartgwt.client.types.ChartType;
                          import com.smartgwt.client.widgets.chart.FacetChart;
                          import com.smartgwt.client.widgets.chart.ValueFormatter;
                          import com.smartgwt.client.widgets.cube.Facet;
                          import com.smartgwt.client.widgets.cube.FacetValue;
                          import java.util.Date;
                          final DateTimeFormat dtf = DateTimeFormat.getFormat("yyyy-MM-dd");
                          FacetChart chart = new FacetChart();
                          Facet metricFacet = new Facet("metric");
                          metricFacet.setValues(new FacetValue("value"), new FacetValue("date"));
                          chart.setFacets(metricFacet, new Facet("label"));
                          final String[] labels = new String[] { "A", "B", "C" };
                          int numLabels = labels.length;
                          int dataPointsPerLabel = 10;
                          float minValue = -10.0f, maxValue = 10.0f;
                          Date now = new Date();
                          Date thirtyDaysAgo = new Date(now.getYear(), now.getMonth(), now.getDate() - 30);
                          final long maxTime = now.getTime(), minTime = thirtyDaysAgo.getTime();
                          final float day = 1000f * 60 * 60 * 24;
                          Record[] data = new Record[numLabels * dataPointsPerLabel];
                          for (int l = 0; l < numLabels; ++l) {
                              String label = labels[l];
                              for (int j = 0; j < dataPointsPerLabel; ++j) {
                                  int i = dataPointsPerLabel * l + j;
                                  long time = minTime + (long) Math.floor((maxTime - minTime + 1) * Math.random());
                                  Record record = data[i] = new Record();
                                  record.setAttribute("date", (time - minTime) / day);
                                  record.setAttribute("value", minValue + (maxValue - minValue) * Math.random());
                                  record.setAttribute("label", label);
                          chart.setXAxisValueFormatter(new ValueFormatter() {
                                  public String format(Object value) {
                                      int dateValue = ((Integer) value).intValue();
                                      long time = minTime + (long) (day * dateValue);
                                      return dtf.format(new Date(time));


                      • #12
                        Cool thanks!
                        I'll take this up again when we're using a 4.0 build.


                        • #13


                          So are sparse points now support in a graph?

                          If so that might be a reason to upgrade to 4.0 for us. I think I could make a case this way.



                          • #14
                            Using XAxisValueFormatter

                            Hi Isomorphic,

                            I'm looking at using the new setXAxisValueFormatter feature in my application for the Scatter chart type. Specifically, I'm looking at using a Date metric formatted in hours:minutes on the XAxis.

                            I have some questions regarding proper use of setXAxisValueFormatter:

                            * I have observed that that ValueFormatter.format method passes an integer value of the ordinal of the XAxis label. i.e. The first label has a value of 0, the second = 1, the third = 2, etc.

                            * To format the value correctly, I need to calculate where along the XAxis the label with the given ordinal will appear. (i.e. The nth label intersects at which point along the x-axis).

                            * To calculate this value, it is unclear how to determine the total number of labels will be drawn on the XAxis. Obviously I need to divide the ordinal of the label by the total number of labels.

                            * The example code you posted above uses hard coded values, so this is of limited benefit.

                            * I believe that either, a getNumValueLabels() or similar function is required, or alternatively the ValueFormatter interface be altered to return the XAxis intersect position rather than an ordinal.

                            Any help or suggestions would be appreciated.



                            • #15
                              I've worked it out. :-)

                              Hi Everyone,

                              I think I've worked it out; and have created some nice example code for everyone. There isn't much documentation (at the moment), so this should be helpful.

                              Some notes:
                              * The format method is passed an argument of type 'Object'. It appears that this Object may in fact be any primitive wrapper class (i.e. Integer, Long, Double, etc)... so the best way to deal with this is to call the toString() method and parse the result. Maybe Isomorphic can tidy this up in a future release to consistently pass the same object type.
                              * The value passed represents each graduation from the 0-based left-side side, up to your maximum X-Axis data value. You can use this to format the X-Axis value.
                              * There is no way to pre-determine what the graduations will be. But behind the scenes it tries to pick nice rounded values that are passed into the format() method. This might not be ideal, depending on your final formatting.

                              My test code:
                              * The attached test code will create a FacetChart of type ScatterType.
                              * The Y-Axis will be formatted as percentages (i.e. 0%, 5%, 10%, etc).
                              * The X-Axis will be formatted as time values, formatted as 23:59 ("HH:mm").
                              * The raw data is CPU utilization measured every 5 minutes, represented as an epoch long timestamp for the time, and a float for the value.

                              I have attached a screenshot which demonstrates the final output.

                              Attached Files