我有点难过。我查看了MPAndroidChart的文档以及这里提出的一系列问题,但我无法弄清楚是什么导致了它。
基本上,除非我有12个左右的标签,或者我只强制标签计数,否则我的图表中没有星期一。标签在周日晚上和周二早上一直放置,这导致星期一不被绘制。理想情况下,在某个缩放级别,我应该看到几个月,然后是几天,然后是几个小时,但标签必须在逻辑位置(月的第一天,午夜,小时的开始等等)
我喜欢做的是能够强制xLabel的特定间隔。例如:在某个缩放级别有24小时,1小时或15分钟的间隔,但都是从午夜开始,所以不会有任何奇怪的时间标签。到目前为止,我还没有找到一个确认的解决方案...至少没有真实的,不规则的Epoch时间戳。提出了这个非常相似的问题,但它并没有引导任何地方:MPAndroidChart x-axis date/time label formatting
(没有星期一,除非你放大每小时视图,如果我强制标签格式显示天数,它们会变得可见)
我正在绘制各种数据点,但它们的x值是所有unix时间戳。
我的代码:
在我的onCreate中:
// creates line graphs for al DPs
for (int i = 0; i < activeDataPointIDs.size(); i++) {
// gets id and dataPointLogic
int id = DataPointsManager.activeDataPointIDs.get(i);
DataPointLogic logic = DataPointsManager.getDataPointLogic(id);
// creates the chart
LineChart lineChart;
lineChart = createLineGraph(logic, UnitConverter.dpToPixel(300, this));
// creates a label
TextView textView = new TextView(this);
textView.setText(DataPointsManager.dataPointNames[id]);
// adds the chart and label to the containing view
mainContainer.addView(textView);
mainContainer.addView(lineChart);
// adds the chart to a list accessible within the activity class
lineChartList.add(lineChart);
}
calculateGraphRange();
calculateGraphRange():
// calculates the graph range based on the time interval selected
void calculateGraphRange() {
int days = CompassApp.daysToShowStats;
// figuring out stupid timezone offsets
long baseOffset = TimeZone.getDefault().getRawOffset();
long dstOffset = TimeZone.getDefault().getDSTSavings();
long timezoneOffset = baseOffset + dstOffset;
// default values are set for 1 week, TODO: deal with timezones
long graphMax = System.currentTimeMillis();
long graphMaxExtra = graphMax % TimeUtilities.UNIX_DAY;
graphMax = graphMax - graphMaxExtra + TimeUtilities.UNIX_DAY - timezoneOffset;
long graphMin = graphMax - (TimeUtilities.UNIX_DAY * days);
//
// prevents invalid graphs from being drawn //TODO: fix labels when range is 0 or null
if (days == 0) {
graphMax = 0;
graphMin = 0;
}
// applies to all charts
for (int i = 0; i < lineChartList.size(); i++) {
LineChart chart = lineChartList.get(i);
chart.getXAxis().setAxisMaximum(graphMax);
chart.getXAxis().setAxisMinimum(graphMin);
chart.notifyDataSetChanged();
chart.invalidate();
}
}
日期格式化程序中没有任何时髦。大多数都被注释掉以便于测试
IAxisValueFormatter createDateFormatter() {
IAxisValueFormatter formatter = new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
Date date = new Date((long) value);
SimpleDateFormat fmt;
// switch (labelModeSelected) {
// case HOURS_FORMAT:
// fmt = new SimpleDateFormat("h:mm a");
// break;
//
// case DAYS_FORMAT:
// fmt = new SimpleDateFormat("E d");
// break;
//
// case WEEKS_FORMAT:
// fmt = new SimpleDateFormat("d MMM");
// break;
//
// case MONTHS_FORMAT:
// fmt = new SimpleDateFormat("MMM yyyy");
// break;
//
// case YEARS_FORMAT:
// fmt = new SimpleDateFormat("yyyy");
//
// break;
//
// default:
// fmt = new SimpleDateFormat("E d MMM");
// break;
// }
fmt = new SimpleDateFormat("MMM d H:mm zz"); //TODO remove after tests and add switch
fmt.setTimeZone(TimeZone.getDefault()); // sets time zone... I think I did this properly...
String s = fmt.format(date);
return s;
}
// we don't draw numbers, so no decimal digits needed
public int getDecimalDigits() {
return 0;
}
};
return formatter;
}
创建线图的方法
LineChart createLineGraph(DataPointLogic dataPointLogic, int height) {
final LineChart lineChart = new LineChart(this);
lineChart.setMinimumHeight(height);
List<Entry> entries = new ArrayList<Entry>();
List<Number> xList = new ArrayList<>();
List<Number> yList = new ArrayList<>();
xList = dataPointLogic.getXVals(); //TODO: does this just not work with the class inheritance
yList = dataPointLogic.getYVals(); //TODO: does this just not work with the class inheritance
for (int i = 0; i < xList.size(); i++) {
long x = xList.get(i).longValue();
float y = yList.get(i).floatValue();
entries.add(new Entry(x, y));
}
//
final LineDataSet dataSet = new LineDataSet(entries, "Time series");
// graph smoothing params
dataSet.setCubicIntensity(0.5f);
dataSet.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);
// graph fill params
dataSet.setDrawFilled(true);
// dataSet.setFillDrawable(ContextCompat.getDrawable(this, R.drawable.doge));
dataSet.setFillColor(primaryColor);
// line params
dataSet.setColor(primaryColor);
dataSet.setLineWidth(1f);
// circle params
dataSet.setCircleRadius(2.5f);
dataSet.setCircleColor(primaryColor);
dataSet.setDrawCircleHole(false);
LineData lineData = new LineData(dataSet);
lineData.setDrawValues(false);
lineChart.setData(lineData);
//
// applies the timestamp formatting
XAxis xAxis = lineChart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xAxis.setValueFormatter(createDateFormatter());
xAxis.setDrawLabels(true);
xAxis.setCenterAxisLabels(true);
xAxis.setLabelRotationAngle(90f); // rotates label so we can see it all TODO remove after tests
YAxis yAxisRight = lineChart.getAxisRight();
yAxisRight.setDrawLabels(false);
yAxisRight.setDrawGridLines(false);
YAxis yAxisLeft = lineChart.getAxisLeft();
yAxisLeft.setDrawGridLines(false);
yAxisLeft.setSpaceBottom(0.0f);
// removes description and legend
lineChart.getLegend().setEnabled(false);
lineChart.getDescription().setEnabled(false);
// sets the maximum zoom... must be provided unix time values
lineChart.setVisibleXRangeMinimum(TimeUtilities.UNIX_HOUR);
lineChart.setOnChartGestureListener(new OnChartGestureListener() {
@Override
public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
}
@Override
public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
}
@Override
public void onChartLongPressed(MotionEvent me) {
}
@Override
public void onChartDoubleTapped(MotionEvent me) {
}
@Override
public void onChartSingleTapped(MotionEvent me) {
}
@Override
public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {
}
@Override
public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
scaleChartLabels(lineChart);
}
@Override
public void onChartTranslate(MotionEvent me, float dX, float dY) {
}
});
// applies the scale
scaleChartLabels(lineChart);
lineChart.invalidate(); // refreshes data
return lineChart;
}
方法更改标签的显示方式,具体取决于图表的比例
// changes the scale of the chart labels depending on what is selected
void scaleChartLabels(LineChart chart) {
float max = chart.getHighestVisibleX();
float min = chart.getLowestVisibleX();
float totalXVisible = max - min;
float granularity = TimeUtilities.UNIX_DAY;
int labelCount = 0;
// conditional switch to determine display params of graphs
if (totalXVisible < TimeUtilities.UNIX_DAY) {
labelCount = 8;
granularity = TimeUtilities.UNIX_HOUR;
labelModeSelected = HOURS_FORMAT;
// Day view
} else if (totalXVisible < TimeUtilities.UNIX_DAY * 2) {
labelCount = 2;
granularity = TimeUtilities.UNIX_DAY;
labelModeSelected = DAYS_FORMAT;
// Week view
} else if (totalXVisible < TimeUtilities.UNIX_DAY * 3) {
labelCount = 3;
granularity = TimeUtilities.UNIX_DAY;
labelModeSelected = DAYS_FORMAT;
// Week view
} else if (totalXVisible < TimeUtilities.UNIX_DAY * 4) {
labelCount = 4;
granularity = TimeUtilities.UNIX_DAY;
labelModeSelected = DAYS_FORMAT;
// Week view
} else if (totalXVisible < TimeUtilities.UNIX_DAY * 5) {
labelCount = 5;
granularity = TimeUtilities.UNIX_DAY;
labelModeSelected = DAYS_FORMAT;
// Week view
} else if (totalXVisible < TimeUtilities.UNIX_DAY * 6) {
labelCount = 6;
granularity = TimeUtilities.UNIX_DAY;
labelModeSelected = DAYS_FORMAT;
// Week view
} else if (totalXVisible < TimeUtilities.UNIX_WEEK) {
labelCount = 7;
granularity = TimeUtilities.UNIX_DAY;
labelModeSelected = DAYS_FORMAT;
// Week view
} else if (totalXVisible < (TimeUtilities.UNIX_WEEK * 2)) {
labelCount = 7;
granularity = TimeUtilities.UNIX_DAY;
labelModeSelected = DAYS_FORMAT;
// Week view
} else if (totalXVisible < TimeUtilities.UNIX_MONTH) {
labelCount = 7;
granularity = TimeUtilities.UNIX_DAY;
labelModeSelected = WEEKS_FORMAT;
//Month view
} else if (totalXVisible < TimeUtilities.UNIX_MONTH * 3) {
labelCount = 3;
granularity = TimeUtilities.UNIX_MONTH;
labelModeSelected = MONTHS_FORMAT;
// 90 day view
} else if (totalXVisible < TimeUtilities.UNIX_YEAR) {
labelCount = 6;
granularity = TimeUtilities.UNIX_MONTH;
labelModeSelected = MONTHS_FORMAT;
// year view
} else if (totalXVisible > TimeUtilities.UNIX_YEAR) {
Log.w(TAG, "case not implemented yet");
}
chart.getXAxis().setGranularityEnabled(true);
chart.getXAxis().setGranularity(granularity);
chart.getXAxis().setLabelCount(labelCount);
}
答案 0 :(得分:2)
事实证明,由于Entries使用了浮点数,我的时间戳上的精度正在下降......足以弄乱x轴上标签之间的间隔。
我把它们全部分成60 000作为一个快速测试,以毫秒为单位将我的时间戳以毫秒计入时间戳,这似乎就是诀窍。
答案 1 :(得分:0)
我遇到了同样的问题,我通过
解决了1。设置
xAxis.setAxisMinimum(minimumPoint)
和
xAxis.setAxisMaximum(maximumPoint)
分别与起点和终点相对应。
xAxis.setLabelCount(length,true)
`,其中length是标签数组的大小。