这一章节将讲解给各式各样的图表设置数据的方法。
想给图表添加数据,使用如下方法:
public void setData(ChartData data) { ... }
基类ChartData囊括所有图表在渲染过程中所需要的信息。针对不同的图表,有不同的ChartData的子类来为对应的图表设置数据,例如针对LineChart,你可以使用LineData。在构造函数中,你可以传递List
/** List constructor */
public LineData(List<ILineDataSet> sets) { ... }
/** Constructor with one or multiple ILineDataSet objects */
public LineData(ILineDataSet...) { ... }
那么,什么是DataSet?为什么你需要使用到它呢?其实很简单。一个DataSet代表在图表中显示的一组数据条目。它的设计初衷是为了将同一个图表中的不同组数据在逻辑上分离开,这样子看上去更清晰。针对不同的图表,存在不同的DataSet的子类(例如,LineDataSet),它们都有着自己的样式。
比如说,你想在一个线形图中展示两家公司一年中四个季度的收入。这种情况下,建议创建两个不同的LineDataSet(对应两个公司),每个LineDataSet包含四个季度的值(一年四个季度)。当然你也可以使用一个LineDataSet,然后包含两个公司8个季度的值。
通过以下方式创建LineDataSet:
public LineDataSet(List<Entry> entries, String label) { ... }
从构造方法可以看出,LineDataSet创建的时候需要一个List< Entry>和一个用于描述LineDataSet的String,这个String也是在图例上显示的标签。 此外,此标签可用于在包含其他LineDataSet的LineData对象中查找该LineDataSet。
Entry列表包含图表中的所有数据。一个Entry对象,实际上就是对一个含有X值和Y值得数据条目的封装。
public Entry(float x, float y) { ... }
综上(两家公司一年内季度收入的例子):
首先,创建 List< Entry>来存放数据值:
List<Entry> valsComp1 = new ArrayList<Entry>();
List<Entry> valsComp2 = new ArrayList<Entry>();
然后,使用Entry对象填写列表。 确保条目对象包含x轴的正确索引。 (当然,这里可以使用一个循环,在这种情况下,循环的计数器变量可以是x轴上的索引)。
Entry c1e1 = new Entry(0f, 100000f); // 0 == quarter 1
valsComp1.add(c1e1);
Entry c1e2 = new Entry(1f, 140000f); // 1 == quarter 2 ...
valsComp1.add(c1e2);
// and so on ...
Entry c2e1 = new Entry(0f, 130000f); // 0 == quarter 1
valsComp2.add(c2e1);
Entry c2e2 = new Entry(1f, 115000f); // 1 == quarter 2 ...
valsComp2.add(c2e2);
//...
List< Entry>搞定之后,创建LineDataSet对象:
LineDataSet setComp1 = new LineDataSet(valsComp1, "Company 1");
setComp1.setAxisDependency(AxisDependency.LEFT);
LineDataSet setComp2 = new LineDataSet(valsComp2, "Company 2");
setComp2.setAxisDependency(AxisDependency.LEFT);
通过调用setAxisDependency(…),指定DataSet对应的轴。 最后但同样重要的是
,创建一个IDataSets列表并构建ChartData对象:
// use the interface ILineDataSet
List<ILineDataSet> dataSets = new ArrayList<ILineDataSet>();
dataSets.add(setComp1);
dataSets.add(setComp2);
LineData data = new LineData(dataSets);
mLineChart.setData(data);
mLineChart.invalidate(); // refresh
在调用invalidate()之后,图表将会刷新,我们提供的数据将会被绘制出来。
如果我们要为x轴添加更多的描述性值(而不是不同季度的0到3的数字),我们可以通过使用IAxisValueFormatter接口来实现。 此接口允许在XAxis上绘制的值自定义样式。 在此示例中,格式化程序可能如下所示:
// the labels that should be drawn on the XAxis
final String[] quarters = new String[] { "Q1", "Q2", "Q3", "Q4" };
IAxisValueFormatter formatter = new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
return quarters[(int) value];
}
// we don't draw numbers, so no decimal digits needed
@Override
public int getDecimalDigits() { return 0; }
};
XAxis xAxis = mLineChart.getXAxis();
xAxis.setGranularity(1f); // minimum axis-step (interval) is 1
xAxis.setValueFormatter(formatter);
关于IAxisValueFormatter 接口的更多使用方法,请查阅IAxisValueFormatter
上面示例的运行结果大致如下
给BarChart,ScatterChart,BubbleChart和CandleStickChart设置数据的方法类似于LineChart。 一个特殊情况是针对多组数据的BarChart,这个后面会进行详细的介绍。
请注意,本开源库不支持X轴非升序的Entry组成的LineDataSet的绘制。以未排序的方式添加条目可能会导致正确的绘制,但也可能导致意外的结果。 Entry对象列表可以手动排序,也可以使用EntryXComparator:
List<Entry> entries = ...;
Collections.sort(entries, new EntryXComparator());
因为本库使用了二分查找算法来优化性能,所以只能在排好序后的列表数据上工作。
BarChart上设置数据的方式和LineChart很相似。主要的差别是用于设置的数据对象从Entry变成了BarEntry。除此之外,BarChart还支持更多的样式。
下面是一个给BarChart填充数据的例子:
List<BarEntry> entries = new ArrayList<>();
entries.add(new BarEntry(0f, 30f));
entries.add(new BarEntry(1f, 80f));
entries.add(new BarEntry(2f, 60f));
entries.add(new BarEntry(3f, 50f));
// gap of 2f
entries.add(new BarEntry(5f, 70f));
entries.add(new BarEntry(6f, 60f));
BarDataSet set = new BarDataSet(entries, "BarDataSet");
在上面的例子中,创建了五个BarEntry对象并将其添加到BarDataSet中。 请注意,在第四个到第五个条目之间的x位置上存在“2”的差距。 在这个例子中,这个差距用于解释BarChart中非常不错的定位方式。 本教程末尾的截图将显示给定数据的结果BarChart,后面会看到。 然后下一步,创建一个BarData对象:
BarData data = new BarData(set);
data.setBarWidth(0.9f); // set custom bar width
chart.setData(data);
chart.setFitBars(true); // make the x-axis fit exactly all bars
chart.invalidate(); // refresh
在上述代码片段中,创建了一个BarData对象。 当创建图表的BarEntry对象时,每个柱形之间的间隔是1f(以中心为起点终点)。 通过将柱形宽度设置为0.9f,我们在每个柱形之间有效地创建一个0.1f的空间。 setFitBars(true)调用会告诉图表调整它的x轴值的范围,以精确地适合所有的柱形,并且在两边不会有柱形断层。
创建BarData对象后,我们将其设置到图表中并进行刷新。 运行结果如下:
从v3.0.0版本开始,MPAndroidChart开始支持显式分组的柱形图,或者用户自定义,这种情况下用户可以通过改变X坐标将柱形图放在图表的任何位置。
本节将重点介绍显式分组的BarChart,这意味着开源库会帮你处理柱状图的x位置。 示例如下:
YourData[] group1 = ...;
YourData[] group2 = ...;
List<BarEntry> entriesGroup1 = new ArrayList<>();
List<BarEntry> entriesGroup2 = new ArrayList<>();
// fill the lists
for(int i = 0; i < group1.length; i++) {
entriesGroup1.add(new BarEntry(i, group1.getValue()));
entriesGroup2.add(new BarEntry(i, group2.getValue()));
}
BarDataSet set1 = new BarDataSet(entriesGroup1, "Group 1");
BarDataSet set2 = new BarDataSet(entriesGroup2, "Group 2");
这个例子中,我们将有两组柱状图,每组由一个BarDataSet表示。 在显式分组的情况下,条目的实际x位置并不重要,它将会根据条目列表中BarEntry的位置执行分组:
float groupSpace = 0.06f;
float barSpace = 0.02f; // x2 dataset
float barWidth = 0.45f; // x2 dataset
// (0.02 + 0.45) * 2 + 0.06 = 1.00 -> interval per "group"
BarData data = new BarData(set1, set2);
data.setBarWidth(barWidth); // set the width of each bar
barChart.setData(data);
barChart.groupBars(1980f, groupSpace, barSpace); // perform the "explicit" grouping
barChart.invalidate(); // refresh
在上面的代码片段中,BarDataSet对象被添加到BarChart。 groupBars(…)方法执行两个BarDataSet对象的分组。 该方法采用以下参数:
public void groupBars(float fromX, float groupSpace, float barSpace) { ... }
fromX参数确定XAxis上分组条目开始的位置(在这种情况下为“1980”),groupSpace确定每组条目之间留下的空间,barSpace确定组中单个条目之间的空间。 基于这些参数,groupBars(…)方法将XAxis上的每个栏的位置更改为分组的外观,保留各个BarEntry对象的顺序。
每个组在XAxis上的“间隔”(占用空间)也由groupSpace、barSpac以及barWidth定义。
运行结果如下:
当然,分组的BarChart也可以在不使用groupBars(…)方法的情况下实现,只需通过手动的方式将各个条目直接定位到XAxis上即可。
为了确保XAxis的标签位于上述屏幕截图上所示的中间位置,可以使用setCenterAxisLabels(…)方法:
XAxis xAxis = chart.getXAxis();
xAxis.setCenterAxisLabels(true);
堆积柱形图的使用方式和正常柱形图的使用方式基本相同。有点差异的是BarEntry的创建方式不太一样,在堆叠柱形图的使用中,需要使用到BarEntry的另一个构造方法:
public BarEntry(float x, float [] yValues) { ... }
这个构造方法允许传入多个yValues,代表每个堆积的柱形图的值。下面有个例子:
BarEntry stackedEntry = new BarEntry(0f, new float[] { 10, 20, 30 });
这个BarEntry由3个堆积的值组成,高度分别是10,20,30
与其他图表类型不同,PieChart以PieEntry对象的形式获取数据。PieEntry的构造方法如下:
public PieEntry(float value, String label) { ... }
构造函数的第一个参数用于在PieChart中绘制为饼图的实际“值”,第二个参数“label”作为第一个参数绘制的那部分饼的描述。 示例如下:
List<PieEntry> entries = new ArrayList<>();
entries.add(new PieEntry(18.5f, "Green"));
entries.add(new PieEntry(26.7f, "Yellow"));
entries.add(new PieEntry(24.0f, "Red"));
entries.add(new PieEntry(30.8f, "Blue"));
PieDataSet set = new PieDataSet(entries, "Election Results");
PieData data = new PieData(set);
pieChart.setData(data);
pieChart.invalidate(); // refresh
PieEntry对象不需要保存x位置的值,因为图表中显示的PieEntry对象的顺序由其在条目列表中的顺序确定。
添加一下样式设置之后,上面的例子将得到下面的饼图:
暂无介绍
暂无介绍
从V1.4.0版本开始,在之前版本上负责设置颜色的ColorTemplate 不再被需要。但是,一些预定义的颜色值依然保存在这个类中(例如,ColorTemplate.VORDIPLOM_COLORS),并且提供便利的方法,方便我们将颜色资源转换成真正的颜色。通过给DataSet直接指定颜色来代替ColorTemplate,同时你可以给每个DataSet分别设计样式。
在下面这个简单的例子中,我们使用两个不同的LineDataSet分别代表两家公司一年内四个季度的收入,我们给每个公司的数据分别设置不同的颜色。
代码如下:
LineDataSet setComp1 = new LineDataSet(valsComp1, "Company 1");
// sets colors for the dataset, resolution of the resource name to a "real" color is done internally
setComp1.setColors(new int[] { R.color.red1, R.color.red2, R.color.red3, R.color.red4 }, Context);
LineDataSet setComp2 = new LineDataSet(valsComp2, "Company 2");
setComp2.setColors(new int[] { R.color.green1, R.color.green2, R.color.green3, R.color.green4 }, Context);
除了上面这个方法外,还有很多给DataSet设置颜色的方法。具体如下:
方法 | 作用 |
---|---|
setColors(int [] colors, Context c) | 设置DataSet的颜色。当数据条目超过颜色数组的大小时,颜色将会被重复使用。你可以使用new int[] { R.color.red, R.color.green, … }来为这个方法提供颜色数组,实际上,内部是通过 getResources().getColor(…)来解析你传入的参数的 |
setColors(int [] colors) | 设置DataSet的颜色。当数据条目超过颜色数组的大小时,颜色将会被重复使用。确保颜色是通过getResources().getColor(…)后获取的值,也就是颜色的16进制值 |
setColors(ArrayList< Integer> colors) | 设置DataSet的颜色。当数据条目超过颜色数组的大小时,颜色将会被重复使用。确保颜色是通过getResources().getColor(…)后获取的值,也就是颜色的16进制值 |
setColor(int color) | 给DataSet设置一个唯一的颜色值。实际上,内部也是使用一个数组,只是数组中的颜色是一样的而已 |
ColorTemplate示例:
LineDataSet set = new LineDataSet(...);
set.setColors(ColorTemplate.VORDIPLOM_COLORS);
如果没有给DataSet设置颜色,我们将会使用默认值。
V1.6.2版本引入,V2.1.4版本优化
IValueFormatter接口允许用户自定义格式化类来将图表中的数据按照一种特定的方式格式化后再进行绘制。
你可以创建一个类,实现IValueFormatter接口,然后在getFormattedValue(…)方法中,返回你希望在图表中绘制的内容。
public class MyValueFormatter implements IValueFormatter {
private DecimalFormat mFormat;
public MyValueFormatter() {
mFormat = new DecimalFormat("###,###,##0.0"); // use one decimal
}
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
// write your logic here
return mFormat.format(value) + " $"; // e.g. append a dollar-sign
}
}
然后,将格式化程序设置到ChartData或者DataSet:
// usage on whole data object
lineData.setValueFormatter(new MyValueFormatter());
// usage on individual dataset object
lineDataSet.setValueFormatter(new MyValueFormatter());
Formatter | 介绍 |
---|---|
LargeNumberFormatter | 用于格式化大于1000的数字。”1.000”->”1k”, “1.000.000”->”1m” (million), “1.000.000.000”->”1b” (billion)等等 |
PercentFormatter | 用于显示保留一位小数的百分数,在饼图中用的比较多。50->50.0% |
StackedValueFormatter | 为堆积柱形图设置的格式化程序。可以明确指出是需要绘制所有的堆积值还是只绘制顶部值 |
v3.0.0版本中引入,用于格式化X轴和Y轴上的显示值。
轴值自定义格式只需要一步:创建实现IAxisValueFormatter 接口的自定义格式类。
如下所示,这个例子中,将轴值格式化为1为小数。
public class MyYAxisValueFormatter implements IAxisValueFormatter {
private DecimalFormat mFormat;
public MyAxisValueFormatter() {
// format values to 1 decimal digit
mFormat = new DecimalFormat("###,###,##0.0");
}
@Override
public String getFormattedValue(float value, AxisBase axis) {
// "value" represents the position of the label on the axis (x or y)
return mFormat.format(value) + " $";
}
/** this is only needed if numbers are returned, else return 0 */
@Override
public int getDecimalDigits() { return 1; }
}
下面这个例子展示如何将一个字符串数组展示到轴上:
public class MyXAxisValueFormatter implements IAxisValueFormatter {
private String[] mValues;
public MyXAxisValueFormatter(String[] values) {
this.mValues = values;
}
@Override
public String getFormattedValue(float value, AxisBase axis) {
// "value" represents the position of the label on the axis (x or y)
return mValues[(int) value];
}
/** this is only needed if numbers are returned, else return 0 */
@Override
public int getDecimalDigits() { return 0; }
}
创建完Formatter之后,设置到对应的轴:
YAxis left = chart.getAxisLeft();
left.setValueFormatter(new MyYAxisValueFormatter());
String[] values = new String[] { ... };
XAxis xAxis = chart.getXAxis();
xAxis.setValueFormatter(new MyXAxisValueFormatter(values));
现在轴上将绘制Formatter提供的数据,而非默认的数据最小值和最大值。
如果你使用基于数组索引的格式化程序(如上所述),将轴的最小间隔限制为“1”是有意义的:
axis.setGranularity(1f); // restrict interval to 1 (minimum)
这将防止格式化程序绘制重复的轴标签(由轴间隔<1)引起。 只要图表的“缩放级别”足够高,它将停止重新计算更小的间隔。
Formatter | 介绍 |
---|---|
LargeNumberFormatter | 用于格式化大于1000的数字。”1.000”->”1k”, “1.000.000”->”1m” (million), “1.000.000.000”->”1b” (billion)等等 |
PercentFormatter | 用于显示保留一位小数的百分数,在饼图中用的比较多。50->50.0% |
DayAxisValueFormatter,该格式化程序将提供的值转换为日期字符串,根据比例改变字符串。
在v3.0.0之前的版本,针对X轴和Y轴分别存在两个Formatter,具体请查阅:
本节重点介绍适用于本库中所有图表类型的基本设置和样式。
方法 | 使用 |
---|---|
invalidate() | 调用该方法后,图表将会被刷新(重绘),从而使我们的修改在图表上生效 |
notifyDataSetChanged() | 让图表知道底层数据发生了变化,需要重新进行所有的必需计算(位移,图例,最大值,最小值等等)。在加载动态数据的时候这个是很有必要的 |
方法 | 使用 |
---|---|
setLogEnabled(boolean enabled) | 设置为true,打开图表的日志输出。打开日志对性能有影响,没必要的话最好保持关闭 |
下面是一些和风格相关的方法,你可以直接在图表对象上使用:
方法 | 使用 |
---|---|
setBackgroundColor(int color) | 设置整个图表的背景颜色,也可以通过xml文件设置 |
setDescription(String desc) | 设置在图表右下角显示的描述文字 |
setDescriptionColor(int color) | 设置描述文字的颜色 |
setDescriptionPosition(float x, float y) | 设置描述文字显示的位置 |
setDescriptionTypeface(Typeface t) | 设置描述文字字体 |
setDescriptionTextSize(float size) | 设置描述文字的字体大小(px), 最小6f, 最大16f. |
setNoDataText(String text) | 设置图表中没有数据时显示的文字. |
setDrawGridBackground(boolean enabled) | 设置为true之后,图表绘制区域后面的矩形会被绘制 |
setGridBackgroundColor(int color) | 设置要绘制的网格背景的颜色。 |
setDrawBorders(boolean enabled) | 启用/禁用绘制图表边框(图表周围的线). |
setBorderColor(int color) | 设置图表边框的颜色 |
setBorderWidth(float width) | 设置图表边框线的宽度(dp) |
setMaxVisibleValueCount(int count) | 设置图表上最大可见绘制值标签的数量。 这仅在启用setDrawValues()时才会生效。 |
方法 | 使用 |
---|---|
setAutoScaleMinMaxEnabled(boolean enabled) | 指示是否启用y轴上的自动缩放的标志。 如果启用,只要视口更改,y轴就会自动调整到当前x轴范围的最小和最大y值。 这对于显示财务数据的图表尤其有用。 默认值:false |
setKeepPositionOnRotation(boolean enabled) | 设置方向更改后图表是否应保持其位置(缩放/滚动)。 默认值:false |
方法 | 使用 |
---|---|
setDrawValueAboveBar(boolean enabled) | 设置为true,所有条目的值将会绘制在条目的上方,而不是顶部的下面 |
setDrawBarShadow(boolean enabled) | 如果设置为true,则在每个条之后绘制一个指示最大值的灰色区域。 打开这个开关将会是性能下降40% |
setDrawValuesForWholeStack(boolean enabled) | 如果设置为true,则堆叠条的所有值都是单独绘制的,而不仅仅是它们的总和. |
setDrawHighlightArrow(boolean enabled) | 设置为true后,若取值高亮,将会在每个高亮的条目上绘制一个箭头 |
方法 | 使用 |
---|---|
setDrawSliceText(boolean enabled) | 将其设置为true可将x值文本绘制到饼图切片中 |
setUsePercentValues(boolean enabled) | 如果启用此功能,则图表中的值将以百分比绘制,而不是以原始值绘制。提供给ValueFormatter的值将会以百分比的形式 |
setCenterText(SpannableString text) | 设置绘制在饼图中心的文字,过长的文字会被自动处理以免延伸到饼图切片中。 |
setCenterTextRadiusPercent(float percent) | 设置中心文本边界框的矩形半径,以饼孔默认值的百分比为1.f(100%) |
setHoleRadius(float percent) | 设置饼图中心空洞的半径,默认是整个饼图半径的一半也就是50% |
setTransparentCircleRadius(float percent) | 设置饼图中孔旁边的透明圆的半径,最大半径的百分比(max =整个图的半径),默认值55% - >表示默认值比中心孔大5% |
setTransparentCircleColor(int color) | 设置透明圆圈的颜色 |
setTransparentCircleAlpha(int alpha) | 设置透明圆圈的透明值 |
setMaxAngle(float maxangle) | 设置用于计算饼形圆的最大角度。 360f意味着它是一个完整的PieChart,180f结果是一个半饼图。 默认值:360f |
方法 | 使用 |
---|---|
setSkipWebLineCount(int count) | 允许跳过来自图表中心的网页线。 特别有用,如果有很多行。 |