Am using AndroidPlot on my project and it's just great so far. This is what i got.
Now am trying to remove one of the series indicators from the legend. Actually i want to keep only the first one (the blue one) cause the others are self explanatory.
Am not asking how to remove the legend it self (see https://stackoverflow.com/a/13413758/665823 for that issue).
If someone can help me i'll be great. Thanks in advance.
I finally found a tweek that allows me to do what i need. To achieve this the series that i need to be shown must be added to the plot first over the ones i need to hide :
// I add the blue serie first
LineAndPointFormatter mFormat = new LineAndPointFormatter();
mFormat.configure(context, R.xml.plot_blue);
graphView.addSeries(serieMesures, mFormat);
// I add the other colors after
for (XYSeries serie : seriesSeuils) {
LineAndPointFormatter sFormat = new LineAndPointFormatter();
if (serie.getTitle().equals("RED") {
sFormat.configure(context, R.xml.plot_red);
}
else if (serie.getTitle().equals("ORANGE")) {
sFormat.configure(context, R.xml.plot_orange);
}
else if (serie.getTitle().equals("YELLOW")) {
sFormat.configure(context, R.xml.plot_yellow);
}
graphView.addSeries(serie, sFormat);
}
Then i just created a legend where there is only enough space to show the series i need (in my case just the first one).
// This is what does the trick! A Table with 1 line and 1 column
// so the other series can't be rendered in the LegendWidget
graphView.getLegendWidget().setTableModel(new DynamicTableModel(1, 1));
// Other customizations (size and position)
graphView.getLegendWidget().setSize(new SizeMetrics(55, SizeLayoutType.ABSOLUTE, legendWith, SizeLayoutType.ABSOLUTE));
graphView.getLegendWidget().setPositionMetrics(
new PositionMetrics(20,
XLayoutStyle.ABSOLUTE_FROM_RIGHT,
20,
YLayoutStyle.ABSOLUTE_FROM_TOP,
AnchorPosition.RIGHT_TOP));
graphView.getLegendWidget().setBackgroundPaint(bgPaint);
graphView.getLegendWidget().setTextPaint(txPaint);
graphView.getLegendWidget().setBorderPaint(brPaint);
graphView.getLegendWidget().setPadding(10, 1, 10, 1);
And voila!
Related
I have created an android application similar to Not Tetris 2 using Libgdx with Box2d.
It can successfully remove a slice from the world, which obviously involves duplicating several bodies and destroying/creating fixtures. However, seemingly at random, a body with a 2x2 fixture will appear. The body and fixture are displayed using information related to the objects around it when it is created, so I narrowed its creation down to the following function:
Body duplicateBody(Body original){
BodyDef d = new BodyDef();
d.position.set(original.getPosition());
d.angle = original.getAngle();
d.linearVelocity.set(original.getLinearVelocity());
d.angularVelocity = original.getAngularVelocity();
Body dup = world.createBody(d);
dup.setType(BodyDef.BodyType.DynamicBody);
return dup;
}
I use this function in 2 different contexts:
Making a copy of the body if a "slice" cuts one in two -- I then transfer the fixtures which are below to it.
When a fixture is below the line then it is added to a body created for ones below
Making a copy of the body when groups of fixtures are separated
I commented out the code responsible for the third instance and still had the 2x2 boxes spawning, so here are the functions relevant to the others:
...
if (below && !above) {
//copy fixture, add copy to lower body and remove original
Body top = fixture.getBody();
FixtureDef n = new FixtureDef();
PolygonShape s = new PolygonShape();
s.set(getLocalVerticesOfFixture(fixture));
n.shape = s;
n.density = fixture.getDensity();
//create lower body if a lower one doesn't already exist
if (!topBottomPairs.containsKey(top)) {
Body dup = duplicateBody(top);
topBottomPairs.put(top, dup);
}
//delete fixture
remove.add(fixture);
Fixture f = topBottomPairs.get(top).createFixture(n);
s.dispose();
}
...
if (below && above) {
//copy fixture, add copy to lower body, but keep original on upper as it needs to split
FixtureDef n = new FixtureDef();
PolygonShape s = new PolygonShape();
s.set(getLocalVerticesOfFixture(fixture));
n.shape = s;
n.density = fixture.getDensity();
Body top = fixture.getBody();
//create lower body if a lower one doesn't already exist
if (!topBottomPairs.containsKey(top)) {
Body dup = duplicateBody(top);
topBottomPairs.put(top, dup);
}
Fixture second = topBottomPairs.get(top).createFixture(n);
s.dispose();
}
....
private Vector2[] getLocalVerticesOfFixture(Fixture fixture) {
PolygonShape shape = ((PolygonShape) fixture.getShape());
Vector2[] localVertices = new Vector2[shape.getVertexCount()];
for (int i = 0; i < shape.getVertexCount(); i++) {
localVertices[i] = new Vector2();
shape.getVertex(i, localVertices[i]);
}
return localVertices;
}
I also have this remove fixture function which runs on all fixtures I want to remove:
private void smartDeleteFixture(Fixture f){
f.getBody().destroyFixture(f);
if(f.getBody().getFixtureList().size == 0){
world.destroyBody(f.getBody());
}
}
Nowhere do I create vertices, let alone a fixture of a 2x2 shape. I was wondering if this duplication function has any flaws, or if I stumbled upon some "default shape" that box2d uses.
Edit: I have removed anything not related to the manipulation of box2d bodies. Hope that helps
Deleted this question as I decided to perform a major recode and hoped that would fix my problem. It did not, but I figured out the cause.
I looked through box2d and found a couple instances of code similar to this in the polygon shape class:
if (n < 3)
{
// Polygon is degenerate.
b2Assert(false);
SetAsBox(1.0f, 1.0f);
return;
}
These instances check the number of vertices after various operations and turn the shape into a 2x2 box if there are fewer than 3. One of these operations makes the shape convex. Another checks if vertices are close together (closer than 0.0025f), deleting one if so.
In my case, the problem was simple. Some of my vertices were less than 0.0025f from each other, resulting in them being deleted, the vert count dropping below 3, an assertion being ignored, and then my shape being turned into a 2x2 box. I hope this helps someone out.
I am trying to create a custom XYPlot with Androidplot but can't seem to fully configure it.
This is my code:
XYSeries series = new SimpleXYSeries(Arrays.asList(dates), Arrays.asList(times), "Time on level");
// Create a formatter to use for drawing a series using LineAndPointRenderer:
LineAndPointFormatter formatter = new LineAndPointFormatter(Color.rgb(0, 100, 0), Color.rgb(0, 100, 0), null, new PointLabelFormatter(Color.BLUE));
totalTimePlot.setRangeValueFormat(new DecimalFormat("#.#"));
totalTimePlot.setGridPadding(0, 0, 0, 200);
totalTimePlot.setBackgroundColor(Color.WHITE);
totalTimePlot.getGraphWidget().getBackgroundPaint().setColor(Color.WHITE);
totalTimePlot.getGraphWidget().getGridBackgroundPaint().setColor(Color.WHITE);
totalTimePlot.getGraphWidget().getDomainOriginLinePaint().setColor(Color.BLACK);
totalTimePlot.getGraphWidget().getRangeOriginLinePaint().setColor(Color.BLACK);
totalTimePlot.setTicksPerDomainLabel(1);
totalTimePlot.setRangeStepValue(10);
totalTimePlot.getGraphWidget().setDomainLabelOrientation(-90);
totalTimePlot.setMarkupEnabled(false);
totalTimePlot.setBorderStyle(Plot.BorderStyle.SQUARE, null, null);
totalTimePlot.setDomainValueFormat(new Format() {
SimpleDateFormat sdf = new SimpleDateFormat("EEE(MM.dd)-HH:mm:ss");
#Override
public StringBuffer format(Object object, StringBuffer buffer, FieldPosition field) {
long timestamp = ((Number) object).longValue();
Date date = new Date(timestamp);
return sdf.format(date, buffer, field);
}
#Override
public Object parseObject(String string, ParsePosition position) {
return null;
}
});
totalTimePlot.getGraphWidget().setPaddingLeft(4);
totalTimePlot.addSeries(series, formatter);
And this is the end result:
As you can see this is very ugly. Can you help me at least configure it so that the Range labels are displayed. I would also like to know how to make the background white as well as have the first and last "ticks" visible.
Thank you.
EDIT:
I managed to include the first and last value by setting the boundaries. But the other problems remain.
Agreed it's pretty ugly :-) It would be easier to give you suggestions if you list a few specific items you'd like to improve. Having said that, here's a few things I would start with:
Use the DemoApp's SimpleXYPlotActivity xml style as a starting point. This should fix your margin issues and improve the overall appearance.
Simplify your date/time format for your domain labels. Maybe something like day/month hour:minute. I don't know your exact use case so maybe you require the format you're using.
Get rid of the dark background that frames your plot.
Consider using the CatmullRomInterpolator to draw a smooth line.
I am using jjoe64 Graph View in my android application.
and I am trying to show dynamic values in graph but first time it contains no values but graph is not appearing.
give me solution.
http://www.android-graphview.org/
https://github.com/jjoe64/GraphView
Can you show us your code?
Have you tried something like
graph = (GraphView) findViewById(R.id.graph);
LineGraphSeries<DataPoint> series = new LineGraphSeries<DataPoint>();
graph.addSeries(series);
graph.getViewport().setXAxisBoundsManual(true);
graph.getViewport().setYAxisBoundsManual(true);
graph.getViewport().setMinX(0);
graph.getViewport().setMaxX(0);
graph.getViewport().setMinY(0);
graph.getViewport().setMaxY(4);
graph.onDataChanged(true, true);
There's a bug report logged for this one, and it appears the issue will be fixed in the next release (4.0.1).Anyway I simply coded around the issue, by displaying some text, indicating there's no data at that point eg.
// If there is no data, let the user know, else blank the textBox.
TextView fragmentText = (TextView) v.findViewById(R.id.history_text);
if ( xLabels.size() < 2 ){
fragmentText.setTextSize(24);
fragmentText.setText(getString(R.string.history_graph_no_data));
} else {
// Remove the "No Data" text
fragmentText.setText("");
LinearLayout layout = (LinearLayout) v.findViewById(R.id.history_graph);
addGraphToLayout(layout);
}
[also posted on MPAndroidChart's Github]
I need realtime graph with a rolling windows, that's when I ran into 'problems'. Adding data is no problem, but after adding data with an Xvalue(index) that's higher than the current width of the graph the graph doesn't autoscroll because it don't seem to be able to always display [X] Xvalues.
Example of issue:
The result in graph 3 is not what I want for displaying realtime data. A scrollingwindow is much more usefull. So I tried to archieve this..
My working 'solution' was to remove the first Xvalue, add a new one and move all Xindexes of all Entries on screen one to the left. The result is some code like this:
int GRAPH_WIDTH = 10;
LineData lineData = chart.getData();
LineDataSet lineDataSet = lineData.getDataSetByIndex(0);
int count = lineDataSet.getEntryCount();
// Make rolling window
if (lineData.getXValCount() <= count) {
// Remove/Add XVal
lineData.getXVals().add("" + count);
lineData.getXVals().remove(0);
// Move all entries 1 to the left..
for (int i=0; i < count; i++) {
Entry e = lineDataSet.getEntryForXIndex(i);
if (e==null) continue;
e.setXIndex(e.getXIndex() - 1);
}
// Set correct index to add value
count = GRAPH_WIDTH;
}
// Add new value
lineData.addEntry(new Entry([random value], count), 0);
// Make sure to draw
chart.notifyDataSetChanged();
chart.invalidate();
This works quite well actually (as seen in this video here ), but I feel like there must be an easier way to do this. Maybe I overlooked some API window/scrolling..
But if this is the 'right' way to archieve this result then it would be an enhancement to add support for this kind of graphs in your library.
Thank you for the video.
I am surprised you found a workaround that is rather complicated but works quite well.
Unfortunately this is currently the only way to achieve what you want. I will work on making this easier soon probably reusing some of your code.
Also take a look at these two methods:
setScaleMinima(...)
centerViewPort(...)
I took your code and changed it a bit. It will only show up to GRAPH_WIDTH number of points at a time. Then it scrolls along deleting the older data. Useful if you're only interested in relatively recent data. Is that what you were going for?
public void addTimeEntry() {
String entry_date_time = new SimpleDateFormat("MMM d - HH:mm:ss").format(new Date());
LineData lineData = mChart.getData();
int GRAPH_WIDTH = 15;
if (lineData != null) {
LineDataSet set = lineData.getDataSetByIndex(0);
if (set == null) {
set = createSet();
lineData.addDataSet(set);
}
// Make rolling window
if (lineData.getXValCount() > GRAPH_WIDTH) {
lineData.getXVals().remove(0);
set.removeEntry(0);
lineData.getXVals().add(entry_date_time);
lineData.addEntry(new Entry((float) (Math.random() * 40) + 30f, GRAPH_WIDTH), 0);
// lineData.getXVals().add(entry_date_time);
// Move all entries 1 to the left..
for (int i=0; i < set.getEntryCount(); i++) {
Entry e = set.getEntryForXIndex(i);
if (e==null) continue;
e.setXIndex(e.getXIndex() - 1);
}
}
else{
lineData.getXVals().add(entry_date_time);
lineData.addEntry(new Entry((float) (Math.random() * 40) + 30f, lineData.getXValCount()-1), 0);
}
// let the chart know it's data has changed
mChart.notifyDataSetChanged();
mChart.invalidate();
}
}
Cannot find any documentation on how to config ShowcaseView.
This is from ShowcaseView GitHub pages:
Usage
To use ShowcaseView, use one of the insertShowcaseView(..) calls. These take:
A Target which represents what should be showcased. See the wiki for more details.
An Activity
Optional title and detail strings (or resource ids) which show on the ShowcaseView
Optional a ConfigOptions which can alter the behaviour of ShowcaseView. See the wiki for more details
The only working link is the wiki one, where i cannot find anything about ConfigOptions and how to use it, other links are broken.
I'm trying to write down a little tutorial for my app, here's what I deduced by studying the source code:
ShowcaseView.ConfigOptions co = new ShowcaseView.ConfigOptions();
co.hideOnClickOutside = false;
//show only first one once?!
co.shotType = ShowcaseView.TYPE_ONE_SHOT;
co.showcaseId=1;
co.centerText=true;
co.noButton=false;
co.block = true;
RelativeLayout.LayoutParams lps = new RelativeLayout.LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_PARENT, android.view.ViewGroup.LayoutParams.MATCH_PARENT);
lps.addRule(RelativeLayout.CENTER_IN_PARENT);
lps.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
int margin = 10;
lps.setMargins(margin, margin, margin, margin);
co.buttonLayoutParams = lps;
ShowcaseViews svs = new ShowcaseViews(this);
ShowcaseViews.ItemViewProperties ivp;
ivp= new ItemViewProperties(
R.id.target1,
R.string.target1_tit,
R.string.target1_desc,
0.4f,
co
);
svs.addView(ivp);
co.showcaseId=2;
ivp= new ItemViewProperties(
R.id.target2,
R.string.target2_tit,
R.string.target2_desc,
0.4f,
co
);
svs.addView(ivp);
co.showcaseId=3;
ivp= new ItemViewProperties(
R.id.target3,
R.string.target3_tit,
R.string.target3_desc,
0.4f,
co
);
svs.addView(ivp);
svs.show();
but i cannot figure out many things:
how to place title and message strings at the center of the screen (ConfigOption.centerText has no effect?)
how to resize text (i would like it bigger)
how to place the OK button elsewhere (ConfigOption.buttonLayoutParams has no effect)
how to dismiss showcase (or display next one) when user touches the target view
thanx.
how to place the OK button elsewhere (ConfigOption.buttonLayoutParams has no effect)
This is the only thing I know of:
svs.setButtonPosition( LAYOUTPARAMS OBJECT HERE );