How can I get entries on screen(not all) in MPAndroidChart?
What I need to use? ViewPortHandler or what? Do I need to left element on screen, and get low of him.(this is a candle chart)
I have silly issues play with width of candletick, cuz i have method for get min/max X cord on screen(left right candle).
But its only cord, not index of entry.
i found solution, but maybe its bad.
float lowestVisibleX = mainChart.getLowestVisibleX();
float highestVisibleX = mainChart.getHighestVisibleX();
int left = (int) Math.ceil(lowestVisibleX);
int right = (int) Math.ceil(highestVisibleX);
List<Integer> indexCheck = new ArrayList<>();
int loopCount = right - left;
while (loopCount != 0) {
indexCheck.add(new Integer(left));
left++;
loopCount--;
}
List<CandleEntry> entriesOnScreen = new ArrayList<>();
for (Integer in : indexCheck) {
entriesOnScreen.add(candleDataSet.getValues().get(in));
}
Related
I am creating a CandleStick chart
from API: https://min-api.cryptocompare.com/data/histoday?fsym=BTC&tsym=USD&limit=10
Using Library: https://github.com/PhilJay/MPAndroidChart
When I creating the chart with the count of values as X-axis, There is no problem (ploat_point.add(new CandleEntry(i,high,low,open,close); in for loop ).
But when I use ploat_point.add(new CandleEntry(time,high,low,open,close); in for loop, And parse X-axis values using my custom function.
i.e :
xAxis = candle_chart.getXAxis();
xAxis.setValueFormatter(new IAxisValueFormatter() {
#Override
public String getFormattedValue(float value, AxisBase axis) {
Log.e(TAG, "getFormattedValue: " + (int) value);
return Utilities.timeStampToMonth((int) value + "");
}
});
This time it is showing the graph only when the paint style is set to Paint.Style.FILL_AND_STROKE, But It does not increasing the bar size with candleDataSet.setBarSize() . It depending only the candleDataSet.setShadowWidth().
my code :
private void drawCandleStickChart(JSONArray dataArr) throws JSONException {
mChart.setVisibility(View.GONE);
ArrayList<CandleEntry> plot_point = new ArrayList<>();
for (int i = 0; i < dataArr.length(); i++) {
JSONObject point = dataArr.getJSONObject(i);
int time = Math.round(Float.parseFloat(point.getString("time")));
float open = Float.parseFloat(String.valueOf(point.getString("open")));
float close = Float.parseFloat(String.valueOf(point.getString("close")));
float high = Float.parseFloat(String.valueOf(point.getString("high")));
float low = Float.parseFloat(String.valueOf(point.getString("low")));
plot_point.add(new CandleEntry(time, high, low, open, close));
}
CandleDataSet cds = new CandleDataSet(plot_point, "Entries");
cds.setShadowColor(Color.WHITE);
cds.setDecreasingColor(Color.RED);
cds.setDecreasingPaintStyle(Paint.Style.FILL_AND_STROKE);
cds.setIncreasingColor(Color.GREEN);
cds.setIncreasingPaintStyle(Paint.Style.FILL_AND_STROKE);
cds.setNeutralColor(Color.BLUE);
cds.setShowCandleBar(true);
cds.setBarSpace(0.5f);
cds.setShadowWidth(0.1f);
cds.setHighlightEnabled(false);
cds.setDrawValues(false);
candle_chart.setMaxVisibleValueCount(20);
CandleData cd = new CandleData(cds);
candle_chart.setData(cd);
candle_chart.invalidate();
candle_chart.setVisibility(View.VISIBLE);
}
I need X-axis as time and bar size is more than shadow please help me.
I acheived it by the changing constant value in library class 'CandleStickChartRenderer'. This has a method 'drawDataSet' with the code block
mBodyBuffers[0] = xPos - 0.5f + barSpace;
mBodyBuffers[1] = close * phaseY;
mBodyBuffers[2] = (xPos + 0.5f - barSpace);
mBodyBuffers[3] = open * phaseY;
This 0.5 constant you have to change to the some bigger value like 1000, As candle stick library has some issue with bigger x value.
Its possible to make float random from range 1.3000 to 1.4000? That give me numbers like 13405, 13855 etc.
I know double is more flexible with range floating point, but i cant use it.
So i create something like:
float highmax = 0.6500f;
float highlow = 0.7000f;
float generatedFloatHigh = highmax + new Random().nextFloat() * (highlow - highmax);
But this not work what i want.
Any suggestion? Or maybe i should look for other libraly?
You can try to get a random number(for example x) between 0 and 1000, then you can get a number from range 1.3000 to 1.4000 like this :
int x = new Random(1000).nextInt();
float result = 1.3000f + x*0.0001f;
Random generator = new Random(System.currentTimeMillis());
int n = generator.nextInt(1000);
float generatedFloatHigh = 1.3000 + n/1000;
I have problem with my algoritm. I delete position on 0, but my dataset ddint move like -1. Then i add a new Entry on position 25. Continuous this maked my project alway delete last entry and non stop adding the Entry in position 25.
Here is code:
private void addEntry() {
data = mChart.getData();
if (set1 == null) {
set1 = createSet();
data.addDataSet(set1);
}
int prog = 1;
for (int i = 0; i < prog; i++) {
float val = (float) (Math.random() * 2);
float high = (float) (Math.random() * 1) + 2f;
float low = (float) (Math.random() * 1) + 2f;
float open = (float) (Math.random() * 2) + 1f;
float close = (float) (Math.random() * 2) + 1f;
boolean even = i % 2 == 0;
data.addEntry(new CandleEntry(25, val + high, val - low, even ? val + open : val - open,
even ? val - close : val + close), 0);
data.notifyDataChanged();
mChart.notifyDataSetChanged();
mChart.setVisibleXRangeMaximum(25);
mChart.moveViewTo(data.getEntryCount() - 24, 2f, YAxis.AxisDependency.RIGHT);
}
}
private void removeLastEntry() {
CandleData data = mChart.getData();
if (data != null) {
ICandleDataSet set = data.getDataSetByIndex(0);
if (set != null) {
Entry e = set.getEntryForIndex(0);
data.removeEntry(e, 0);
data.notifyDataChanged();
mChart.notifyDataSetChanged();
mChart.invalidate();
}
}
}
DataSet#getEntryForIndex(int index) returns the entry that is first in the backing array of Entry which may or may not be the Entry with the minimum x value on the chart. From the javadoc:
Returns the Entry object found at the given index (NOT xIndex) in the values array.
I suspect you actually want to use something like the following:
float xMin = dataSet.getXMin();
dataSet.remove(dataSet.getEntryForXPos(xMin);
See the javadoc here.
However, your use case is a little bit unusual. You want all the other entries to "move down", it would seem, when you remove the Entry with the minimum value. If you are only doing this infrequently, it may be easier to construct a new dataset when you do that. Please note that while adding Entry to the chart is easy, random access to Entry and removing them is not supported so well. See the following note in the wiki
Please be aware that this library does not officially support drawing LineChart data from an Entry list not sorted by the x-position of the entries in ascending manner. Adding entries in an unsorted way may result in correct drawing, but may also lead to unexpected behaviour.
I have a TextView with an OnTouchListener. What I want is the character index the user is pointing to when I get the MotionEvent. Is there any way to get to the underlying font metrics of the TextView?
Have you tried something like this:
Layout layout = this.getLayout();
if (layout != null)
{
int line = layout.getLineForVertical(y);
int offset = layout.getOffsetForHorizontal(line, x);
// At this point, "offset" should be what you want - the character index
}
Hope this helps...
I am not aware of a simple direct way to do this but you should be able to put something together using the Paint object of the TextView via a call to TextView.getPaint()
Once you have the paint object you will have access to the underlying FontMetrices via a call to Paint.getFontMetrics() and have access to other functions like Paint.measureText() Paint.getTextBounds(), and Paint.getTextWidths() for accessing the actual size of the displayed text.
While it generally works I had a few problems with the answer from Tony Blues.
Firstly getOffsetForHorizontal returns an offset even if the x coordinate is way beyond the last character of the line.
Secondly the returned character offset sometimes belongs to the next character, not the character directly underneath the pointer. Apparently the method returns the offset of the nearest cursor position. This may be to the left or to the right of the character depending on what's closer by.
My solution uses getPrimaryHorizontal instead to determine the cursor position of a certain offset and uses binary search to find the offset underneath the pointer's x coordinate.
public static int getCharacterOffset(TextView textView, int x, int y) {
x += textView.getScrollX() - textView.getTotalPaddingLeft();
y += textView.getScrollY() - textView.getTotalPaddingTop();
final Layout layout = textView.getLayout();
final int lineCount = layout.getLineCount();
if (lineCount == 0 || y < layout.getLineTop(0) || y >= layout.getLineBottom(lineCount - 1))
return -1;
final int line = layout.getLineForVertical(y);
if (x < layout.getLineLeft(line) || x >= layout.getLineRight(line))
return -1;
int start = layout.getLineStart(line);
int end = layout.getLineEnd(line);
while (end > start + 1) {
int middle = start + (end - start) / 2;
if (x >= layout.getPrimaryHorizontal(middle)) {
start = middle;
}
else {
end = middle;
}
}
return start;
}
Edit: This updated version works better with unnatural line breaks, when a long word does not fit in a line and gets split somewhere in the middle.
Caveats: In hyphenated texts, clicking on the hyphen at the end of a line return the index of the character next to it. Also this method does not work well with RTL texts.
I want to ask about some ideas / study materials connected to binarization. I am trying to create system that detects human emotions. I am able to get areas such as brows, eyes, nose, mouth etc. but then comes another stage -> processing...
My images are taken in various places/time of day/weather conditions. It's problematic during binarization, with the same treshold value one images are fully black, other looks well and provide me informations I want.
What I want to ask you about is:
1) If there is known way how to bring all images to the same level of brightness?
2) How to create dependency between treshold value and brightness on image?
What I have tried for now is normalize the image... but there are no effects, maybe I'm doing something wrong. I'm using OpenCV (for android)
Core.normalize(cleanFaceMatGRAY, cleanFaceMatGRAY,0, 255, Core.NORM_MINMAX, CvType.CV_8U);
EDIT:
I tried adaptive treshold, OTSU - they didnt work for me. I have problems with using CLAHE in Android but I managed to implement Niblack algorithm.
Core.normalize(cleanFaceMatGRAY, cleanFaceMatGRAY,0, 255, Core.NORM_MINMAX, CvType.CV_8U);
nibelBlackTresholding(cleanFaceMatGRAY, -0.2);
private void nibelBlackTresholding(Mat image, double parameter) {
Mat meanPowered = image.clone();
Core.multiply(image, image, meanPowered);
Scalar mean = Core.mean(image);
Scalar stdmean = Core.mean(meanPowered);
double tresholdValue = mean.val[0] + parameter * stdmean.val[0];
int totalRows = image.rows();
int totalCols = image.cols();
for (int cols=0; cols < totalCols; cols++) {
for (int rows=0; rows < totalRows; rows++) {
if (image.get(rows, cols)[0] > tresholdValue) {
image.put(rows, cols, 255);
} else {
image.put(rows, cols, 0);
}
}
}
}
The results are really good, but still not enough for some images. I paste links cuz images are big and I don't want to take too much screen:
For example this one is tresholded really fine:
https://dl.dropboxusercontent.com/u/108321090/a1.png
https://dl.dropboxusercontent.com/u/108321090/a.png
But bad light produce shadows sometimes and this gives this effect:
https://dl.dropboxusercontent.com/u/108321090/b1.png
https://dl.dropboxusercontent.com/u/108321090/b.png
Do you have any idea that could help me to improve treshold of those images with high light difference (shadows)?
EDIT2:
I found that my previous Algorithm is implemented in wrong way. Std was calculated in wrong way. In Niblack Thresholding mean is local value not global. I repaired it according to this reference http://arxiv.org/ftp/arxiv/papers/1201/1201.5227.pdf
private void niblackThresholding2(Mat image, double parameter, int window) {
int totalRows = image.rows();
int totalCols = image.cols();
int offset = (window-1)/2;
double tresholdValue = 0;
double localMean = 0;
double meanDeviation = 0;
for (int y=offset+1; y<totalCols-offset; y++) {
for (int x=offset+1; x<totalRows-offset; x++) {
localMean = calculateLocalMean(x, y, image, window);
meanDeviation = image.get(y, x)[0] - localMean;
tresholdValue = localMean*(1 + parameter * ( (meanDeviation/(1 - meanDeviation)) - 1 ));
Log.d("QWERTY","TRESHOLD " +tresholdValue);
if (image.get(y, x)[0] > tresholdValue) {
image.put(y, x, 255);
} else {
image.put(y, x, 0);
}
}
}
}
private double calculateLocalMean(int x, int y, Mat image, int window) {
int offset = (window-1)/2;
Mat tempMat;
Rect tempRect = new Rect();
Point leftTop, bottomRight;
leftTop = new Point(x - (offset + 1), y - (offset + 1));
bottomRight = new Point(x + offset, y + offset);
tempRect = new Rect(leftTop, bottomRight);
tempMat = new Mat(image, tempRect);
return Core.mean(tempMat).val[0];
}
Results for 7x7 window and proposed in reference k parameter = 0.34: I still can't get rid of shadow on faces.
https://dl.dropboxusercontent.com/u/108321090/b2.png
https://dl.dropboxusercontent.com/u/108321090/b1.png
things to look at:
http://docs.opencv.org/java/org/opencv/imgproc/CLAHE.html
http://docs.opencv.org/java/org/opencv/imgproc/Imgproc.html#adaptiveThreshold(org.opencv.core.Mat,%20org.opencv.core.Mat,%20double,%20int,%20int,%20int,%20double)
http://docs.opencv.org/java/org/opencv/imgproc/Imgproc.html#threshold(org.opencv.core.Mat,%20org.opencv.core.Mat,%20double,%20double,%20int) (THRESH_OTSU)