Frequently Asked Questions
FAQs
- Is the QCChart2D for Android software backward compatible with
the QCChart2D for Java
?
- How do you create a chart with multiple coordinate systems and axes?
- Can I add new axes, text objects, plot objects, and images to a chart
after it is already displayed; or must I create a new chart from scratch
taking into account the additional objects?
- How do you zoom charts that use multiple coordinate systems?
- How do you select a chart object and create a dialog panel that permits
editing of that objects properties?
- How do you handle missing data points in a chart?
- How do you update a chart in real-time?
- How do I prevent flicker when updating my charts on real-time?
- How do you implement drill down, or data tool tips in a chart?
- I do not want to my graph to auto-scale. How do I setup the graph axes
for a specific range?
- How do I update my data, and auto-rescale the chart scales and axes to
reflect the new data, after it has already been drawn?
- When I use the auto-scale and auto-axis routines my semi-log chart has
the logarithmic axis scaled using powers of 10 (1, 10,100, 1000, etc.) as
the starting and ending values, or as the major tick interval for labeling.
How do I make my log graphs start at 20 and end at 50,000, with major tick
marks at 20, 200, 2000 and 20000?
- How do I create and use custom, multi-line string labels as the axis
labels for my graph?
- How do I place more than one graph in a view?
- How do I use your software to generate JPEG files?
- Sometimes the major tick marks of an axis are missing the associated
tick mark label ?
- How do I change the order the chart objects are drawn? For example, I
want one of my grid objects to be drawn under the charts line plot objects,
and another grid object to be drawn top of the charts line plot objects.
-
How do I implement a scroll-bar like touch
area to control horizontal scrolling of the data in my chart?
- I am trying to plot 100,000,000 data points and it takes too long to
draw the graph. What is wrong with the software and what can I do to make it
faster?
-
How do I get data from my database into a
chart?
-
Do you plan to also have QCRTGraph and
QCSPCChart for Android?
-
Are you going to write a 3D charting package
(QCChart3D) for Android based on OpenGL.
- Is the QCChart2D for Android software compatible with
QCChart2D for Java. ?
The charting part of programs written using the
Java versus Android versions will be similar, since they both use Java as the
programming language. Android uses completely different logic for the setup of
an application program however. You don't use Frames and JPanels, or Swing
components (buttons, scroll bars, dialogs, etc.). Also, the Android versions
use a graphics library different than the Java graphics and graphics2d
libraries and this necessitated significant changes to the software. See
Chapter 1 for a list of the major programming differences between the two
versions.
- How do you create a chart with multiple coordinate systems and axes?
A chart can have as many coordinate systems and
axes as you want. A single coordinate system can have one or more x- and/or
y-axes. The most common use for multiple axes in a single coordinate system is
to place y-axes on both the left and the right sides of a chart, and x-axes
above and below. The left and bottom axes usually have numeric or date labels,
and the top and right axes just tick marks. This does not have to be the case
though; every axis can have axis labels if you want. In general, the axis
position in the chart is determined by its intercept. The default value of the
intercept is set to the minimums of the coordinate system that the axis is
placed in. Adjusting the intercept using the setAxisIntercept method
changes the position of the axis in the chart. The axis intercept value is set
using units of the coordinate system at right angles to the axis. The example
below, extracted from the simplelineplots.LineFill example, places y-axes on
both the left and right of the chart.
pTransform1 = new TimeCoordinates();
pTransform1.autoScale(DatasetArray, ChartConstants.AUTOAXES_FAR,
ChartConstants.AUTOAXES_FAR);
pTransform1.setGraphBorderDiagonal(0.125, .08, .92, 0.85) ;
.
.
.
TimeAxis xAxis = new TimeAxis(pTransform1);
xAxis.setColor(ChartColor.WHITE);
gWG.addChartObject(xAxis);
LinearAxis yAxis = new LinearAxis(pTransform1, ChartConstants.Y_AXIS);
yAxis.setColor(ChartColor.WHITE);
gWG.addChartObject(yAxis);
LinearAxis yAxis2 = new LinearAxis(pTransform1, ChartConstants.Y_AXIS);
yAxis2.setAxisIntercept(xAxis.getAxisMax());
yAxis2.setAxisTickDir(ChartConstants.AXIS_MAX);
yAxis2.setColor(ChartColor.WHITE);
gWG.addChartObject(yAxis2);
TimeAxisLabels xAxisLab = new TimeAxisLabels(xAxis );
xAxisLab.setAxisLabelsFormat(ChartConstants.TIMEDATEFORMAT_Y2000);
xAxisLab.setColor(ChartColor.WHITE);
gWG.addChartObject(xAxisLab);
NumericAxisLabels yAxisLab = new NumericAxisLabels(yAxis);
yAxisLab.setColor(ChartColor.WHITE);
yAxisLab.setAxisLabelsFormat(ChartConstants.CURRENCYFORMAT);
gWG.addChartObject(yAxisLab);
The other common reason to have multiple axes
in a chart is to delineate the simultaneous use of different coordinate
systems in the chart. In this case each coordinate system has an x- and/or
y-axis to differentiate it from the other coordinate systems. When the
different coordinate systems are created, they usually overlay the same area
of the chart. The default positioning of the axes for each coordinate system
will all overlay one another, making the axes unreadable. In the y-axis case
you will want to offset additional axes to the left, or to the right of the
default axis position, using the setAxisIntecept method. When using the
setAxisIntercept method, make sure you specify the position using the
units of the coordinate system scale at right angles to the axis. Specify an
intercept value outside of the normal scale range to offset the axes so that
they do not overlap. The example below, extracted from the
multipleaxes.MultiAxesChart example, creates one x-axis, common to all of the
charts because the x-scaling for all of the coordinate systems match, and five
y-axes, one for each of the five different coordinate systems.
CartesianCoordinates pTransform1 =
new CartesianCoordinates( ChartConstants.LINEAR_SCALE,
ChartConstants.LINEAR_SCALE);
CartesianCoordinates pTransform2 =
new CartesianCoordinates( ChartConstants.LINEAR_SCALE,
ChartConstants.LINEAR_SCALE);
CartesianCoordinates pTransform3 =
new CartesianCoordinates( ChartConstants.LINEAR_SCALE,
ChartConstants.LINEAR_SCALE);
CartesianCoordinates pTransform4 =
new CartesianCoordinates( ChartConstants.LINEAR_SCALE,
ChartConstants.LINEAR_SCALE);
CartesianCoordinates pTransform5 =
new CartesianCoordinates( ChartConstants.LINEAR_SCALE,
ChartConstants.LINEAR_SCALE);
LinearAxis xAxis;
LinearAxis yAxis1;
LinearAxis yAxis2;
LinearAxis yAxis3;
LinearAxis yAxis4;
LinearAxis yAxis5;
.
. // Initialize datasets, coordinate system ranges
.
// The x-scale range for pTransform1 to pTransform5 are all the same, 0 - 100
// The y-scale range for pTransform1 to pTransform5 are all different
// The plotting area for each pTransform is indentical, leaving a large open
// to the left for extra axes.
pTransform1.setGraphBorderDiagonal(0.35, .15, .9, 0.75) ;
pTransform2.setGraphBorderDiagonal(0.35, .15, .9, 0.75) ;
pTransform3.setGraphBorderDiagonal(0.35, .15, .9, 0.75) ;
pTransform4.setGraphBorderDiagonal(0.35, .15, .9, 0.75) ;
pTransform5.setGraphBorderDiagonal(0.35, .15, .9, 0.75) ;
ChartAttribute attrib1 = new ChartAttribute (ChartColor.BLUE,
2,ChartConstants.LS_SOLID);
ChartAttribute attrib2 = new ChartAttribute (ChartColor.RED,
2,ChartConstants.LS_SOLID);
ChartAttribute attrib3 = new ChartAttribute (ChartColor.GREEN,
2,ChartConstants.LS_SOLID);
ChartAttribute attrib4 = new ChartAttribute (ChartColor.ORANGE,
2,ChartConstants.LS_SOLID);
ChartAttribute attrib5 = new ChartAttribute (ChartColor.MAGENTA,
2,ChartConstants.LS_SOLID);
ChartAttribute attrib1 = new ChartAttribute (ChartColor.BLUE,
2,ChartConstants.LS_SOLID);
ChartAttribute attrib2 = new ChartAttribute (ChartColor.RED,
2,ChartConstants.LS_SOLID);
ChartAttribute attrib3 = new ChartAttribute (ChartColor.GREEN,
2,ChartConstants.LS_SOLID);
ChartAttribute attrib4 = new ChartAttribute (ChartColor.ORANGE,
2,ChartConstants.LS_SOLID);
ChartAttribute attrib5 = new ChartAttribute (ChartColor.MAGENTA,
2,ChartConstants.LS_SOLID);
xAxis = new LinearAxis(pTransform1, ChartConstants.X_AXIS);
xAxis.setLineWidth(2);
gWG.addChartObject(xAxis);
yAxis1 = new LinearAxis(pTransform1, ChartConstants.Y_AXIS);
yAxis1.setAxisIntercept(0.0);
yAxis1.setChartObjAttributes(attrib1); // axis color matches line color
gWG.addChartObject(yAxis1);
yAxis2 = new LinearAxis(pTransform2, ChartConstants.Y_AXIS);
yAxis2.setAxisIntercept(-18);
yAxis2.setChartObjAttributes(attrib2); // axis color matches line color
gWG.addChartObject(yAxis2);
yAxis3 = new LinearAxis(pTransform3, ChartConstants.Y_AXIS);
yAxis3.setAxisIntercept(-35);
yAxis3.setChartObjAttributes(attrib3); // axis color matches line color
gWG.addChartObject(yAxis3);
yAxis4 = new LinearAxis(pTransform4, ChartConstants.Y_AXIS);
yAxis4.setAxisIntercept(-52);
yAxis4.setChartObjAttributes(attrib4); // axis color matches line color
gWG.addChartObject(yAxis4);
yAxis5 = new LinearAxis(pTransform5, ChartConstants.Y_AXIS);
yAxis5.setAxisIntercept(xAxis.getAxisMax());
yAxis5.setAxisTickDir(ChartConstants.AXIS_MAX);
yAxis5.setChartObjAttributes(attrib5); // axis color matches line color
gWG.addChartObject(yAxis5);
NumericAxisLabels xAxisLab = new NumericAxisLabels(xAxis);
xAxisLab.setTextFont(theFont);
gWG.addChartObject(xAxisLab);
NumericAxisLabels yAxisLab1 = new NumericAxisLabels(yAxis1);
yAxisLab1.setTextFont(theFont);
yAxisLab1.setAxisLabelsFormat(ChartConstants.BUSINESSFORMAT);
gWG.addChartObject(yAxisLab1);
NumericAxisLabels yAxisLab2 = new NumericAxisLabels(yAxis2);
yAxisLab2.setTextFont(theFont);
gWG.addChartObject(yAxisLab2);
NumericAxisLabels yAxisLab3 = new NumericAxisLabels(yAxis3);
yAxisLab3.setTextFont(theFont);
gWG.addChartObject(yAxisLab3);
NumericAxisLabels yAxisLab4 = new NumericAxisLabels(yAxis4);
yAxisLab4.setTextFont(theFont);
gWG.addChartObject(yAxisLab4);
NumericAxisLabels yAxisLab5 = new NumericAxisLabels(yAxis5);
yAxisLab5.setTextFont(theFont);
gWG.addChartObject(yAxisLab5);
ChartFont axisTitleFont = new ChartFont("SansSerif", ChartFont.BOLD,12);
AxisTitle xaxistitle = new AxisTitle( xAxis, axisTitleFont, "Event
Partition");
gWG.addChartObject(xaxistitle);
Grid xgrid = new Grid(xAxis, yAxis1,ChartConstants.X_AXIS,
ChartConstants.GRID_MAJOR);
gWG.addChartObject(xgrid);
SimpleLinePlot thePlot1 = new SimpleLinePlot(pTransform1, Dataset1, attrib1);
gWG.addChartObject(thePlot1);
SimpleLinePlot thePlot2 = new SimpleLinePlot(pTransform2, Dataset2, attrib2);
gWG.addChartObject(thePlot2);
SimpleLinePlot thePlot3 = new SimpleLinePlot(pTransform3, Dataset3, attrib3);
gWG.addChartObject(thePlot3);
SimpleLinePlot thePlot4 = new SimpleLinePlot(pTransform4, Dataset4, attrib4);
gWG.addChartObject(thePlot4);
SimpleLinePlot thePlot5 = new SimpleLinePlot(pTransform5, Dataset5, attrib5);
gWG.addChartObject(thePlot5);
- Can I add new axes, text objects, plot objects, and images to a chart
after it is already displayed; or must I create a new chart from scratch
taking into account the additional objects?
There are two ways to add new objects to a
chart. The first way is to create all objects when the chart is initially
created, but disable the ones that you do not want to show up when the chart
is initially rendered. Enable the objects when you want them to show up. Use
the chart objects setChartObjEnable method to enable/disable the
object. This is useful if you are creating an animated chart where you want
the chart to sequence through a predefined series of steps. The second way you
add new chart objects to the ChartView using the
ChartView.addChartObject method. In both cases you need to call the
ChartView.updateDraw() method after any changes are made.
The example below, extracted from the
datacursorsandmarkers.DataCursorChart2.CustomChartDataCursor class,
creates a new Marker object and NumericLabel object each time
you touch a plot.
// create marker object at place it at the nearest point
Marker amarker = new
Marker(getChartObjScale(), MARKER_BOX, nearestPoint.getX(), nearestPoint.getY(),
15.0, PHYS_POS);
chartview.addChartObject(amarker);
rNumericLabelCntr += 1.0;
// Add a numeric label the identifies the marker
pointLabel = new NumericLabel(getChartObjScale(), textCoordsFont,
rNumericLabelCntr,
nearestPoint.getX(), nearestPoint.getY(), PHYS_POS, DECIMALFORMAT, 0);
// Nudge text to the right and up so that it does not write over marker
pointLabel.setTextNudge(5,-5);
chartview.addChartObject(pointLabel);
chartview.updateDraw();
- How do you zoom charts that use multiple coordinate systems?
The ChartZoom class will zoom one or
more simultaneous coordinate systems. The example program
zoomexamples.SuperZoom zooms a chart that has one x-axis and five y-axes. Use
the ChartZoom constructor that accepts an array of coordinate system
objects.
- How do you select a chart object and create a dialog panel that
permits editing of that objects properties?
The QCChart2D for Android library does
not include predefined dialogs for editing chart object properties. The look,
feel and details of such dialogs are application specific and it is up to the
application programmer to provide these. The property editor tables common to
many packages are designed to be used by developers, not end users.
You can add your own dialogs that edit the
characteristics important to your end users. If you want to select the chart
object by touching it, use the FindObj class. Override the
touchClicked method and invoke the appropriate dialog panel there. The
following example is extracted from the TouchListeners.FindObjectChart example
program.
class CustomFindObj extends FindObj {
CustomFindObj (ChartView component)
{
super( component);
}
public void touchClicked (MotionEvent event)
{
super.touchClicked(event);
GraphObj selectedObj = getSelectedObject();
ChartText selectedtext = null;
if (selectedObj == text1)
selectedtext = (ChartText) selectedObj;
else if (selectedObj == text2)
selectedtext = (ChartText) selectedObj;
else if (selectedObj == text3)
selectedtext = (ChartText) selectedObj;
if (selectedtext != null)
{
SimpleEditDialog editdialog = new SimpleEditDialog(getChartObjComponent(),
selectedtext, "Edit Dialog");
editdialog.showEditDialog();
}
}
}
CustomFindObj editObject = new CustomFindObj(gWG);
The SimpleEditDialog class is made using
the Android Dialog class, and the Android EditText class and need to be
further customized by the programmer. A layout for the SimpleEditDialog (edittextobjlayout.xml)
class is found in the projects res/layout folder.
- How do you handle missing data points in a chart?
There are two ways to handle missing, or bad
data. The first is to mark the data point in the dataset invalid, using the
datasets setValidData method. The second is to set the x- and/or y-
value of the bad data point to the designated bad data value,
ChartConstants.rBadDataValue. Currently this value is set equal to the
value of Double.MAX_VALUE. Either method will prevent the data point from
being displayed in a chart. If the bad data value is part of a line plot, a
gap will appear in the line plot at that point. Bad data points are not
deleted from a dataset.
- How do you update a chart in real-time?
In general, real-time updates involve adding
new objects to a chart, or modifying existing objects that are already in the
chart. Once the object is added or changed, call the ChartView.updateDraw()
method to force the chart to update using the new values. Objects can be added
or modified based on some external event, or in response to a timer event.
In order to simplify the use of timers,
we added a couple of timers (java.util.Timer.Timer) to the ChartView class.
You can enable either timer using the ChartView startTimer or startTimer2
methods. The code below is extracted from our DynamicCharts.MixedPlotDynamic
example.
public void InitializeChart()
{
.
.
.
int delay = 1000;
int period = 2000;
startTimer(delay, period);
}
Override the ChartView
onTimerEvent
event and call your update routine from there.
@Override
public void onTimerEvent()
{
updateDynGraph();
timerCount++;
}
Make all changes for a given event and call the
ChartView.updateDraw method once. The position of most GraphObj
derived objects is set or modified using one of the objects setLocation
methods. New data points can be added to an existing dataset using one of the
datasets addDataPoint, addTimeDataPoint, addGroupDataPoints
or addTimeGroupDataPoints methods. ChartPlot derived objects
that use datasets will update to reflect the new values when the
ChartView.updateDraw method is called. If the coordinates of the new data
points are outside of the x- and y-limits of the current coordinate system it
may be necessary to rescale the coordinate system so that the new points show
up; otherwise the new data points will be clipped. The new scale values can be
set explicitly, or calculated using one of the auto-scale methods. The example
programs SpectrumAnalyzer, DataLogger, DynPieChart and ScrollingMixedPlot all
demonstrate various ways to update charts in real-time.
If you want to change points in an existing
dataset, but not the size of the dataset, call the datasets appropriate
setXDataValue, setYDataValue, or setDataPoint methods. The
dataset has its own copy of the data so you must change these values, not the
original values you used to initialize the dataset. If you plan to change
every value in the dataset, you can do that point by point, or create a new
dataset and swap that in for the old dataset using the plot objects
setDataset or setGroupDataset method. Call the
ChartView.updateDraw method to force the chart to update using the new
values.
- How do I prevent flicker when updating my charts on real-time?
Flicker is the result of erasing and redrawing
all or part of a chart in the current display buffer. Double buffering of
screen images can minimize any flicker. The ChartView class does the
actual work of rendering a chart image to the underlying SurfaceView
display buffer. The SurfaceView class uses double buffering for the
display of all screen images. When a chart is updated it is automatically
rendered to an off-screen bitmap. When drawing is complete the off-screen
bitmap is copied to the screen display buffer, minimizing the effect of
flicker.
- How do you implement drill down, or data tool tips in a chart?
Implementing drill down or tool tips consists
of three major parts:
 | Trapping a touch event and determining the touch position in device
and physical coordinates. |
 | Identifying the chart object that intersects the touch event. |
 | Displaying appropriate information about the chart object. |
There are many classes that aid in one or more
of these functions. The ChartTouchListener class will trap a touch
event in the chart view. The FindObj class will filter and return the
chart object, if any, that intersects the touch. The MoveObj class will
filter, select and move a chart object as the touch is dragged across the
chart. The DataToolTip class will find the data point in a chart
nearest the touch and display xy information about the data point as a pop-up
ChartText display. The DataToolTip can also be customized for
the display of custom information about the selected data point. It only takes
one lines to add a simple y-value tool tip to an existing chart. In a slight
difference between this, and other versions of the QCChart2D software, when
you instantiate the tooltip, it is automatically enabled and added as a touch
listener to the view.
DataToolTip datatooltip = new DataToolTip(chartVu);
Some of the example programs that include tool
tips include simplelineplots.LineFill, multiline.Multiline,
simplelineplots.LinePlotSegments, multiline.StackedLineChart,
logplots.FinLogPlot, bargraphs.SimpleBarChart, bargraphs.GroupBarPlotChart,
bargraphs.DoubleBarPlot, financialexamples.OpeningScreen,
financialexamples.OHLCFinPlot and piechart.LabeledPieChart.
- I do not want to my graph to auto-scale. How do I setup the graph
axes for a specific range?
Auto-scaling has two parts. The first is the
auto-scaling of the coordinate system based on one or more datasets. The
second part is the auto-scaling of the axes that reside in the coordinate
system. Manually scale the coordinate system and axes by calling the
appropriate constructors. For example:
GregorianCalendar xMin = new GregorianCalendar(1996, ChartConstants.FEBRUARY,
5);
GregorianCalendar xMax = new GregorianCalendar(2002, ChartConstants.JANUARY,
5);
double yMin = 0;
double yMax = 105;
TimeCoordinates simpleTimeScale;
simpleTimeScale = new TimeCoordinates(xMin, yMin, xMax, yMax);
// Create the time axis (x-axis is assumed)
TimeAxis xAxis = new TimeAxis(simpleTimeScale);
// Create the linear y-axis
LinearAxis yAxis = new LinearAxis(simpleTimeScale, ChartConstants.Y_AXIS);
// Create the ChartView object to place graph objects in.
ChartView chartVu = new ChartView();
// Add the x- and y-axes to the chartVu object
chartVu.addChartObject(xAxis);
chartVu.addChartObject(yAxis);
The documentation for the various coordinate
system and axis classes includes examples of manual scaling.
- How do I update my data, and auto-rescale the chart scales and axes
to reflect the new data, after it has already been drawn?
Updating data was discussed in FAQ # 6. If you
want the chart to rescale based on the new data, call the appropriate
coordinate systems auto-scale method, followed by the auto-axis methods of all
related axes. Then call the ChartView.updateDraw method. For example:
// Create the ChartView object to place graph objects in.
TimeSimpleDataset Dataset1 = new TimeSimpleDataset("Sales",x1,y1);
TimeCoordinates simpleTimeCoordinates = new TimeCoordinates();
simpleTimeCoordinates.autoScale(Dataset1,
ChartConstants.AUTOAXES_FAR , ChartConstants.AUTOAXES_FAR);
ChartView chartVu = new ChartView();
// Create the time axis (x-axis is assumed)
TimeAxis xAxis = new TimeAxis(simpleTimeCoordinates);
// Create the linear y-axis
LinearAxis yAxis = new LinearAxis( simpleTimeCoordinates,
ChartConstants.Y_AXIS);
.
.
.
// The following code would be in the code handling the rescale event
// Rescale chart based on a modified Dataset1 datset
simpleTimeCoordinates.autoScale(Dataset1,
ChartConstants.AUTOAXES_FAR , ChartConstants.AUTOAXES_FAR);
xAxis.calcAutoAxis();
yAxis.calcAutoAxis();
// Redraw the chart using the rescaled coordinate system and axes
chartVu.updateDraw();
- When I use the auto-scale and auto-axis routines my semi-log chart
has the log axis scaled using powers of 10 (1, 10,100, 1000, etc.) as the
starting and ending values, or as the major tick interval for labeling. How
do I make my log graphs start at 20 and end at 50,000, with major tick marks
at 20, 200, 2000 and 20000?
The auto-scale routines for logarithmic
coordinate systems will always select a power of 10 for the minimum and
maximum value of the scale. You can use the auto-scale routine and then
override the minimum and/or maximum values for the logarithmic scale. The
default LogAxis constructor will pick up on the minimum of the
coordinate system and use that as the axis tick mark origin. Or you can leave
the coordinate system unchanged, and change the starting point of the axis
tick marks using the axis setAxisTickOrigin method. The example below
is derived from the logplots.SpeakerSPL example code.
CartesianCoordinates pTransform1 =
new CartesianCoordinates( ChartConstants.LOG_SCALE,
ChartConstants.LINEAR_SCALE);
pTransform1.autoScale(Dataset1, ChartConstants.AUTOAXES_FAR,
ChartConstants.AUTOAXES_FAR);
pTransform1.setScaleStartX(20); // Force start of scale at 20, AutoScale will
// always choose a power of 10 decade.
Background background = new Background( pTransform1,
ChartConstants.GRAPH_BACKGROUND,
new ChartColor(255,255,255));
gWG.addChartObject(background);
pTransform1.setGraphBorderDiagonal(0.15, .15, .90, 0.8) ;
LogAxis xAxis = new LogAxis(pTransform1, ChartConstants.X_AXIS);
xAxis.setAxisTickOrigin(20);
gWG.addChartObject(xAxis);
- How do I create and use custom, multi-line string labels as the axis
labels for my graph?
The StringAxisLabels class should be
used to create multi-line axis labels. Insert the “\n” new line character to
add additional lines to each string used to define the string axis labels. The
example below is from the chartaxes.AxisLabelsChart example program.
String xstringlabels[] = {"",
"Western"+"\n"+"Sales"+"\n"+"Region",
"Eastern"+"\n"+"Sales"+"\n"+"Region",
"Southern"+"\n"+"Sales"+"\n"+"Region",
"Northern"+"\n"+"Sales"+"\n"+"Region"};
StringAxisLabels xAxisLab5 = new StringAxisLabels(xAxis5);
xAxisLab5.setAxisLabelsStrings(xstringlabels,5);
xAxisLab5.setTextFont(graph5Font);
gWG.addChartObject(xAxisLab5);
- How do I place more than one graph in a view?
One way to create multiple charts is to create
multiple instances of the ChartView class and add each ChartView
object to a container object such as a SurfaceView. A layout manager
manages the position and size of each ChartView. Another way is to
place multiple charts in the same ChartView object. This makes it
easier to guarantee alignment between the axes of separate graphs. The trick
to doing this is to create separate coordinate system objects (CartesianCoordinates,
TimeCoordinates or PolarCoordinates) for each chart, and to
position the plot area of each coordinate system so that they do not overlap.
Use one of the coordinate systems setGraphBorder… methods. Many of the
examples use this technique, including bargraphs.GroupBarPlotChart,
bargraphs.DoubleBarPlot, financialexamples.OHLFinPlot,
financialexamples.FinOptions, piecharts.DynPieChart, piecharts.PieAndLineChart
and piecharts.PieAndBarChart. The example below was extracted from the
financialexamples.OHLCFinPlot class.
pTransform1 = new TimeCoordinates();
pTransform1.setWeekType(weekmode);
pTransform1.autoScale(Dataset1, ChartConstants.AUTOAXES_NEAR,
ChartConstants.AUTOAXES_NEAR);
pTransform1.setGraphBorderDiagonal(0.1, .15, .90, 0.6);
.
.
.
pTransform2.setGraphBorderDiagonal(0.1, .7, .90, 0.875) ;
pTransform2 = new TimeCoordinates();
pTransform2.setWeekType(weekmode);
pTransform2.autoScale(Dataset2, ChartConstants.AUTOAXES_NEAR,
ChartConstants.AUTOAXES_NEAR);
pTransform2.setGraphBorderDiagonal(0.1, .7, .90, 0.875);
- How do I use your software to generate JPEG files?
The software can grab the image of a
ChartView graph as an Android Bitmap object using the
ChartBufferedImage class (Chapter 23) You can convert the Android Bitmap
object into any format that you want. If you want the ubiquitous jpeg format
use the ChartBufferedImage saveImageAsJPEG method.
- Sometimes the major tick marks of an axis are missing the associated
tick mark label ?
The axis labeling routines are quite intelligent. Before the label is drawn
at its calculated position, the software does a check to see if the bounding
box of the new axis label intersects the bounding box of the previous axis
label. If the new label is going to overlap the previous label, the label is
skipped. You can override this default behavior by calling the objects setOverlapLabelMode
method.
setOverlapLabelMode (ChartConstants.OVERLAP_LABEL_DRAW);
Another option, for horizontal axes only, is to
stagger the tick mark labels. A stagger automatically alternates the line on
which the tick mark label is placed.
setOverlapLabelMode (ChartConstants.OVERLAP_LABEL_STAGGER);
- How do I change the order the chart objects are drawn? For example, I
want one of my grid objects to be drawn under the charts line plot objects,
and another grid object to be drawn top of the charts line plot objects.
There are two ordering methods used to render
chart objects. The first method renders the objects in order, as added to the
ChartView object. Objects added to the view last are drawn on top of
objects added first. The second method renders the objects according to their
z-order. Objects with the lowest z-order values are rendered first. Objects
with equal z-order values are rendered in the ordered they are added to the
ChartView object. The second method (z-order rendering) is the default
method of object rendering used by the ChartView class. This default
behavior can be changed by call the ChartView.setZOrderSortEnable(false)
method.
You can change the default z-order value on an
object-by-object basis. Call the GraphObj.setZOrder method to change
the z-order for any given object.
See the section in the manual titled
Rendering Order of GraphObj Objects for information about the default
z-values for all chart objects
The example below sets the z-order value of
grid1 to something less than the default value (50) of ChartPlot
objects, and the z-order value of grid2 to something greater than the default
value.
.
.
.
Grid grid1 = new Grid(xAxis, yAxis, ChartConstants.Y_AXIS,
ChartConstants.GRID_MAJOR);
grid1.setZOrder(40); // This is actually the default value for the grid
z-order
chartVu.addChartObject(grid1);
Grid grid2 = new Grid(xAxis, yAxis, ChartConstants.Y_AXIS,
ChartConstants.GRID_MINOR);
grid2.setZOder(150); // Grid is drawn after ChartPlot objects
// which have default z-value of 50
chartVu.addChartObject(grid2);
- How do I implement a scroll-bar like touch area to control horizontal
scrolling of the data in my chart?
The ChartView class contains horizontal and vertical scroll touch areas.
Normally these scroll touch areas are not shown; but you can enable one or
both, and process scroll events, if you want. The vertical scroll touch area
is on the right by default, and the horizonal scroll touch area is at the
bottom. The example program TouchExamples.LinePlotScrollBar uses two scroll
touch areas, a horizontal scrolling area to control scrolling of the x-axis,
and a vertical scroll area that controls the magnitude of the y-axis. You need
to implement the ScrollTouchAreaEventListener interface for the derived
ChartView in order to process the ScrollTouchEvent method invoked when the
scrollbars are moved.
ScrollTouchArea hScrollTouch = null;
ScrollTouchArea vScrollTouch = null;
public void updateXScaleAndAxes(int index)
{
int startindex = 0;
startindex = (int) hScrollTouch.getValue();
pTransform1.setScaleStartX( (double) startindex);
pTransform1.setScaleStopX( (double) (startindex + 100));
xAxis.calcAutoAxis();
yAxis.calcAutoAxis();
xAxisLab.calcAutoAxisLabels();
yAxisLab.calcAutoAxisLabels();
this.updateDraw();
}
public void updateYScaleAndAxes(int index)
{
int startindex = 0;
startindex = (int) vScrollTouch.getValue();
pTransform1.setScaleStartY( (double) -startindex);
pTransform1.setScaleStopY( (double) startindex);
xAxis.calcAutoAxis();
yAxis.calcAutoAxis();
xAxisLab.calcAutoAxisLabels();
yAxisLab.calcAutoAxisLabels();
this.updateDraw();
}
/** The dummy mouseReleased event method for this object.
* @param event The mouse event contains status information about the mouse.
*/
public void ScrollTouchEvent(ScrollTouchAreaEventArgs args)
{ int startindex = 0;
MotionEvent me = args.getMotionEvent();
Object eventobject = args.getScrollTouchArea();
if (eventobject == (Object) hScrollTouch)
{
startindex = (int) hScrollTouch.getValue();
updateXScaleAndAxes(startindex);
} else if (eventobject == (Object) vScrollTouch)
{
startindex = (int) vScrollTouch.getValue();
updateYScaleAndAxes(startindex);
}
}
- I am trying to plot 100,000,000 data points and it takes too long to
draw the graph. What is wrong with the software and what can I do to make it
faster?
The software runs as fast as we can make it. We
do not have any hidden switches that will speed up the software. What you need
to do is to step back and think about the best way to display your data.
A fundamental issue that many programmers fail
to consider is the relationship between the resolution of the rasterized
screen image of the plot and the resolution of the data. A typical chart image
will have 500-1000 pixels as the horizontal resolution of the plotting area.
This would imply that in the 100M data point example above, every horizontal
pixel would represent 50K to 100K data points. Obviously this is a terrible
mismatch. In fact it is a bad match for datasets that have more than a couple
of thousands points.
So what you do is compress the data before it
is displayed. Take the 100M data points and compress them down to 2K data
points. The data compression can take several forms. You can take an average
of every N points. The resulting dataset will be reduced by a factor of N. You
can also find the sum for every N points, the minimum value of every N points,
the maximum of every N points, or both the minimum and maximum of every 2N
points. The last compression method, minimum and maximum, will always capture
any minimums and maximum in the data. The result is that a 2000 point
compressed dataset, where there are at least two data points per pixel of
horizontal resolution, will look just like the 100,000,000 point dataset, only
display hundreds of times faster. The Datset classes all include
compression methods (SimpleDataset.compressSimpleDataset,
GroupDataset.compressGroupDataset,
TimeSimpleDataset.compressTimeSimpleDataset and
TimeGroupDataset.compressTimeGroupDataset,
TimeGroupDataset.compressTimeFieldSimpleDataset,
TimeGroupDataset.compressTimeFieldGroupDataset) that operate on the
existing dataset and return a new, compressed dataset. The compressTimeFieldSimpleData
and compressTimeFieldGroupDataset are particular useful because they do
not use a fixed sample size of N, instead they compress data so that adjacent
time values are an increment of a specific time field (ChartConstants.DAY_OF_YEAR,
ChartConstants.WEEK_OF_YEAR, ChartConstants.MONTH, ChartConstants.Year).
Compressing data by month and year obviously requires a varying sample size.
Once created, connect the compressed dataset to
the ChartPlot object used to display the dataset.
nNumPnts = 1000000;
TimeSimpleDataset RawDataset = new
TimeSimpleDataset("Raw", xtimedata, ydata,nNumPnts);
int compressXmode = ChartConstants.DATACOMRESS_AVERAGE;
int compressYmode = ChartConstants.DATACOMRESS_MINMAX;
int compressTimeField = Calendar.MONTH;
TimeSimpleDataset CompressedDataset =
RawDataset.compressTimeFileSimpleData( compressXmode,
compressYmode,
compressTimeField,
0, nNumPnts,”Compressed”);
- How do I get data from my database into a chart?
The real question is: How do you get data from
your database into a simple program, storing sequential data values in data
array variables. This is up to you and is independent of the charting
software. We recommend that you use the SQLite database classes that are part
of Android and study the documentation provide by Google and other Android
programming books. Once you can read individual data elements of your data
base it is a trivial matter to place the numeric and calendar data into simple
Java array variables and from there plot the data.
- Do you plan to also have QCRTGraph and QCSPCChart for Android?
Yes. They will be out by Aug. 2011.
- Are you going to write a 3D charting package (QCChart3D) for Android
based on OpenGL.
Maybe.