I work for my school project on MPAndroidChart especially a realtime graph, i would like to display Time of the value.
I set a IndexAxisValueFormatter with a "getFormattedValue", it work but refresh every label and not just the last, I try to have for each entry in my graph a XLabel who show the time, I really don't know how to do that you're help would be welcome.
Code for create an entry and display it :
void creaGraph() {
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
if (boxCO2.isChecked()) {
A_CO2.add(new Entry(indice, listData.recup_data(indice - 1).getCO2()));
LineDataSet setCO2 = new LineDataSet(A_CO2, "CO2");
setCO2.setAxisDependency(YAxis.AxisDependency.LEFT);
paramSet(setCO2);
setCO2.setColor(Color.RED);
setCO2.setCircleColor(Color.RED);
dataSets.add(setCO2);
}
LineData data = new LineData(dataSets);
graph.setData(data);
data.notifyDataChanged();
graph.notifyDataSetChanged();
graph.invalidate();
}
The override of getFormattedValue
#Override
public String getFormattedValue(float value) {
return listData.recup_data(GraphPage.indice - 1).getTemps();
}
And a picture of my issue
Every label are refresh when a new entry come
Also, I see after the 7th values entry no longer have a time values
You never use value in getFormattedValue. The string you construct there should be based on value or it will show the same thing for every axis entry.
Something like this:
#Override
public String getFormattedValue(float value) {
return makeDateStringAt(value);
}
For example, if you have a chart with axis values at 0, 1, 2, 3 then getFormattedValue will be called 4 times with 0f, 1f, 1f, and 3f as its arguments and you should use those inputs to create the appropriate string to show at those positions on the axis.
Related
I am currently creating a map which updates based on users selection and displays 5 location closest to them. This works however when the user changes their selection the map updates and displays the 5 NEW locations as well as the 5 OLD locations.
I am not sure how to remove the old symbols.
public void displayResults(ArrayList allLocation) {
SymbolManager sm = new SymbolManager(mapView,map,styleMap);
sm.deleteAll();
SymList.clear();
sm.setIconAllowOverlap(true);
sm.setIconIgnorePlacement(true);
int count = 1;
for (LocationDetails a : allLocation
) {
// gets the distance from user to Location
double LocationLat = Double.parseDouble(a.getLatitude());
double LocationLng = Double.parseDouble(a.getLongitude());
float[] disResult = new float[1];
Location.distanceBetween(lat, lng, LocationLat, LocationLng, disResult);
results.append(count + ": " + a.getName() + " " + "\n");
distanceResults.append(Math.round(disResult[0]) + "m" + "\n");
SymbolOptions symbolOptions = new SymbolOptions()
.withLatLng(new LatLng(LocationLat, LocationLng))
.withIconImage("marker-11")
.withTextField(""+count)
.withIconColor("black")
.withIconSize(2.5f);
SymList.add(symbolOptions);
count++;
}
LatLngBounds latLngBounds = new LatLngBounds.Builder()
.include(SymList.get(0).getLatLng())
.include(SymList.get(1).getLatLng())
.include(SymList.get(2).getLatLng())
.include(SymList.get(3).getLatLng())
.include(SymList.get(4).getLatLng())
.build();
map.animateCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds, 50), 2000);
for(SymbolOptions a : SymList){
sm.create(a);
}
SymList.clear();
}
I have been using mapbox for 3 months. After hours of research I discovered that on Android the only way to remove a Symbol or any element on the map was to reload all the elements from scratch. Unfortunately, there is currently no method to remove a single element.
So I suggest you create a container class in which to save your items.
If your use case only requires showing about five markers on the map at a time, it might be easier to use native sources and SymbolLayers rather than relying on the abstraction provided by the SymbolManager.
For example, this icon updates based on API response Android demo shows how to add a GeoJSON source and corresponding layer to the map, then update said source to get a different visual result. Basically all of the logic you will need is encapsulated here, but your GeoJSON will be a FeatureCollection of multiple (namely, 5) features rather than just one point.
So, you can set up your symbols similarly to how it's done in the linked example:
private void initSpaceStationSymbolLayer(#NonNull Style style) {
style.addImage("space-station-icon-id",
BitmapFactory.decodeResource(
this.getResources(), R.drawable.iss));
style.addSource(new GeoJsonSource("source-id"));
style.addLayer(new SymbolLayer("layer-id", "source-id").withProperties(
iconImage("space-station-icon-id"),
iconIgnorePlacement(true),
iconAllowOverlap(true),
iconSize(.7f)
));
}
, and then update the source's GeoJSON to the new locations closest to the user's position, similar to the updateMarkerPostion method:
private void updateMarkerPosition(LatLng position) {
// This method is where we update the marker position once we have new coordinates. First we
// check if this is the first time we are executing this handler, the best way to do this is
// check if marker is null;
if (map.getStyle() != null) {
GeoJsonSource spaceStationSource = map.getStyle().getSourceAs("source-id");
if (spaceStationSource != null) {
spaceStationSource.setGeoJson(FeatureCollection.fromFeature(
Feature.fromGeometry(Point.fromLngLat(position.getLongitude(), position.getLatitude()))));
}
}
// Lastly, animate the camera to the new position so the user
// wont have to search for the marker and then return.
map.animateCamera(CameraUpdateFactory.newLatLng(position));
}
A few modifications will need to be made, of course, but this option might be more direct for your implementation specifically.
I got 78 labels in a pie chart like this picture.
And I want to show only top 3 labels in descending order.
How can I do this?
Create a custom PieSectionLabelGenerator and return null when you do not like to display the label.
Example
public class PieMaximumLabelsGenerator extends StandardPieSectionLabelGenerator {
private static final long serialVersionUID = 1385777973353453096L;
private int nrLabels;
private boolean showFirst;
/**
* A custom label generator to show only limited numbers of labels
* #param nrLabels, number of labels to show
* #param showFirst, if true, show first labels otherwise show the last
*/
public PieMaximumLabelsGenerator(int nrLabels, boolean showFirst){
this.nrLabels = nrLabels;
this.showFirst = showFirst;
}
#Override
public String generateSectionLabel(PieDataset dataset, Comparable key) {
int index = dataset.getIndex(key);
if (showFirst){
if (index>=nrLabels){
return null; //no more lables if index is above
}
}else{
if (index<dataset.getItemCount()-nrLabels){
return null; //no labels if index is not enough
}
}
return super.generateSectionLabel(dataset, key);
}
}
Then set this to your plot
((PiePlot) chart.getPlot()).setLabelGenerator(new PieMaximumLabelsGenerator(3, false));
Output, similar example but displaying first 5 values instead of last 3, hence ((PiePlot) chart.getPlot()).setLabelGenerator(new PieMaximumLabelsGenerator(5, true));
My preference however is to display label if the arc angle of slice is large enough. This can be done by collecting totale values of items in the chart and then calculating the angle using Number value = dataset.getValue(key); in generateSectionLabel to get the current angle (dimension) of slice.
I would like to use column percentage sizing to force the table to take on the width of the parent.
This does not work when I hide column(s) by default because the setColumnPercentageSizing() method does not seem to exclude hidden columns and does not correctly calculate the width.
Is there an easy way to adjust this in my code?
Example:
public void example(){
createGlazedListsGridLayer();
autoResizeColumns();
nattable.configure();
}
public GlazedListsGridLayer createGlazedListsGridLayer(){
SortedList<T> sortedList = new SortedList<>(eventList, null);
this.bodyDataProvider = new ListDataProvider<>(sortedList,
columnPropertyAccessor);
this.bodyDataLayer = new DataLayer(this.bodyDataProvider);
ColumnHideShowLayer columnHideShowLayer = new
ColumnHideShowLayer(bodyDataLayer);
// In this example, hide the first column
columnHideShowLayer.hideColumnPositions(Lists.newArrayList(0));
this.bodyLayerStack = new DefaultBodyLayerStack(new
GlazedListsEventLayer<>(columnHideShowLayer, eventList));
//...etc
}
protected void autoResizeColumns() {
glazedListsGridLayer.getBodyDataLayer().setColumnPercentageSizing(true);
nattable.addConfiguration(new DefaultNatTableStyleConfiguration() {
{
cellPainter = new LineBorderDecorator(new TextPainter(false,
true, 5, true));
}
});
}
UPDATE
It's not ideal but this is the closest I could get to it
public void adjustColumnWidth() {
getBodyDataLayer().setColumnPercentageSizing(false);
// Avoid the first column since it's hidden
for (int x = 1; x <= numColumns; x++) {
getBodyDataLayer().setColumnWidthByPosition(x,
getParent().getSize().x / numColumns, true);
}
}
UPDATE 2
Here are a couple of different things I tried in various combinations. None of them seem to keep the column hidden after a table is dynamically populated with data.
protected void enableAutoResizeColumns() {
getBodyDataLayer().setColumnPercentageSizing(true);
getBodyDataLayer().setDefaultColumnWidthByPosition(0, 0);
getBodyDataLayer().setColumnWidthByPosition(0, 0);
getBodyDataLayer().setColumnWidthPercentageByPosition(0, 0);
getNatTable().addConfiguration(new
DefaultNatTableStyleConfiguration() {
{
cellPainter = new LineBorderDecorator(new TextPainter
(false, true, 5, true));
}
});
}
Currently there is no solution for that. The reason for this is that the column widths are calculated in the DataLayer. The ColumnHideShowLayer sits on top of it and simply hides columns. It doesn't communicate back to the DataLayer that something is hidden.
In the end the ColumnHideShowLayer would need to re-trigger percentage size calculation based on the hidden state. But there is currently no API for that.
Feel free to create an enhancement ticket and provide a patch if you have an idea how to solve it.
I am trying out the GraphView Library for creating charts on Android. It looks quite decent, but I am wondering if there is a way to add some space between the tick labels and the graph itself. As you can see, there is basically none:
I use the following code to set up the graph (very similar to the example):
GraphView graph = (GraphView)view.findViewById(R.id.graph);
LineGraphSeries<DataPoint> series = new LineGraphSeries<DataPoint>(new DataPoint[] {
new DataPoint(0, 1),
new DataPoint(1, 5),
new DataPoint(2, 3)
});
graph.addSeries(series);
I tried using graph.getGridLabelRenderer().setPadding(), but that just added padding around the whole graph.
So, is there a way to put some padding around those labels?
yes it is possible in the current version in github (will be released in 4.0.1).
There is the method:
graph.getGridLabelRenderer().setLabelsSpace(x)
Follow this example to give your graph a custom label formatter. By doing so, you can at least add space padding to your y-axis labels (if not newline spacing to your x-axis labels).
// GraphView 4.x
graph.getGridLabelRenderer().setLabelFormatter(
new DefaultLabelFormatter() {
#Override
public String formatLabel(double value, boolean isValueX) {
if (isValueX) {
// show normal x values
return super.formatLabel(value, isValueX);
} else {
// show currency for y values
return super.formatLabel(value, isValueX) + " €";
}
}
}
);
I pulled this example from the GraphView documentation.
Otherwise, I found it interesting that someone chose this answer as the best response for a similar question.
I'm writing an application where I show markers on a map using the library Unfolding Maps.
The application lets the user choose a year and depending on that value other markers are shown. This works perfect, but when the user selects another year I can't seem to get the other markers shown.
I've tried to completely renew the map but after that first time it doesn't redraw a map.
Besides that I've tried to add a MarkerManager to the map but then I get errors of OpenGL.
setup function:
public void setup() {
/*
* Provincies, set zoom to 10
*/
size(1000, 800, OPENGL);
this.map = new UnfoldingMap(this, new Microsoft.RoadProvider());
map.zoomAndPanTo(belgie, 8);
map.setPanningRestriction(belgie, 1);
map.setZoomRange(8, 8);
drawOtherMarker();
//map.getMarkerManager(markerRemarck.get(keyM)).enableDrawing();
MapUtils.createDefaultEventDispatcher(this, map);
}
function that creates the MarkerManager and adds it to the map
private void createMarkers(ArrayList<double[]> dataMarker) {
float size = 0;
int i = 0;
ListIterator<double[]> dataIt = dataMarker.listIterator();
ArrayList<SimplePointMarker> markList = new ArrayList<SimplePointMarker>();
while (dataIt.hasNext()) {
double[] element = dataIt.next();
SimplePointMarker point = new SimplePointMarker(new Location(
element[0], element[1]));
if (element[2] > 1000)
size = 120;
else if (element[2] > 100)
size = 60;
else if (element[2] > 10)
size = 30;
else
size = 20;
point.setRadius(size);
point.setColor(color(64,64,64,100));
point.setStrokeColor(color(178,34,34));
point.setStrokeWeight(30);
point.setStrokeWeight(0);
point.setId(Integer.toString(i++));
markList.add(point);
}
MarkerManager man = new MarkerManager(markList);
map.addMarkerManager(man);
}
When the map is drawn and another set of markers must be drawn the following function is called:
public void drawOtherMarker(){
if(!markerRemarck.containsKey(keyM)){
markerRemarck.put(keyM, totalMark++);
createMarkers(dataMarkerProvince);
}
if(dataMarkerTown != null){
markerRemarck.put(keyM + "city", totalMark++);
createMarkers(dataMarkerTown);
}
for(int i = 0; i < totalMark;++i)
map.getMarkerManager(i).disableDrawing();
map.getMarkerManager(markerRemarck.get(keyM)).enableDrawing();
}
another function brings in the data required to make the markers. I just don't seem to manage to add a MarkerManager after the first draw.
EDIT
This map is placed inside a JPanel. And the years are choosen with the help of a JComboBox. Once a year is chosen the "dataMarker" variable containing the information for creating markers is updated
thanks in advance for helping me out.