Page 1 of 1
How to sort legend items along with its symbols
Posted: Tue Mar 27, 2012 8:26 pm
by 7667590
Hi.
I want to know if it is possible to sort the legend items along with its symbols in TeeChart?
For example, when I sort the legend items in box chart, but the symbols do not get sorted along with its legend items. I think it is because the index from getItemText of legendResolver is something I can't change.
Right now, the legend items and symbols are added in the order of rendering chart series. Could you help me how to sort the legend items by alphabetically or numerically?
Re: How to sort legend items along with its symbols
Posted: Thu Mar 29, 2012 12:04 pm
by yeray
Hi Jonathan,
I'm afraid it's not possible "as-is". However, you can calculate the order you wish and play with LegendResolver to modify the legend strings and the chartPainted event to draw the symbols over the old ones. For example:
Code: Select all
private static void initializeChart() {
tChart1.getAspect().setView3D(false);
Random r = new Random();
for (int i=0; i<4; i++) {
new Line(tChart1.getChart());
tChart1.getSeries(i).fillSampleValues(5);
tChart1.getSeries(i).setTitle("Series" + String.valueOf(r.nextInt(100)));
}
final int[] seriesOrder;
if (tChart1.getSeriesCount() > 1) {
seriesOrder = new int[tChart1.getSeriesCount()];
for (int i=0; i<tChart1.getSeriesCount(); i++)
seriesOrder[i] = i;
for (int i=0; i<seriesOrder.length; i++) {
for (int j=i+1; j<seriesOrder.length; j++) {
if (tChart1.getSeries(seriesOrder[j]).titleOrName().compareTo(tChart1.getSeries(seriesOrder[i]).titleOrName()) < 0) {
int tmp = seriesOrder[i];
seriesOrder[i] = seriesOrder[j];
seriesOrder[j] = tmp;
}
}
}
}
else {
seriesOrder = new int[tChart1.getSeries(0).getCount()];
for (int i=0; i<tChart1.getSeries(0).getCount(); i++)
seriesOrder[i] = i;
for (int i=0; i<seriesOrder.length; i++) {
for (int j=i+1; j<seriesOrder.length; j++) {
if (tChart1.getSeries(0).getYValues().getValue(seriesOrder[j]) < tChart1.getSeries(0).getYValues().getValue(seriesOrder[i])) {
int tmp = seriesOrder[i];
seriesOrder[i] = seriesOrder[j];
seriesOrder[j] = tmp;
}
}
}
}
tChart1.addChartPaintListener(new ChartPaintAdapter() {
@Override
public void chartPainted(ChartDrawEvent e) {
if (tChart1.getSeriesCount() > 1) {
for (int i=0; i<tChart1.getLegend().getLegendItems().size(); i++) {
Rectangle rect = tChart1.getLegend().getLegendItems().getLegendItem(i).getSymbolRect();
if ((tChart1.getSeries(seriesOrder[i]) instanceof Custom) && (((Custom)tChart1.getSeries(seriesOrder[i])).getPointer().getVisible())) {
tChart1.getGraphics3D().getBrush().setColor(tChart1.getSeries(seriesOrder[i]).getColor());
tChart1.getGraphics3D().rectangle(rect);
}
else {
tChart1.getGraphics3D().getPen().setColor(tChart1.getSeries(seriesOrder[i]).getColor());
tChart1.getGraphics3D().horizontalLine(rect.x, rect.getRight(), (rect.y + rect.getBottom()) / 2);
}
}
}
else {
for (int i=0; i<tChart1.getLegend().getLegendItems().size(); i++) {
Rectangle rect = tChart1.getLegend().getLegendItems().getLegendItem(i).getSymbolRect();
if ((tChart1.getSeries(0) instanceof Custom) && (((Custom)tChart1.getSeries(0)).getPointer().getVisible())) {
if (tChart1.getSeries(0).getColorEach()) {
tChart1.getGraphics3D().getBrush().setColor(tChart1.getSeries(0).getColors().getColor(seriesOrder[i]));
}
else {
tChart1.getGraphics3D().getBrush().setColor(tChart1.getSeries(0).getColor());
}
tChart1.getGraphics3D().rectangle(rect);
}
else {
if (tChart1.getSeries(0).getColorEach()) {
tChart1.getGraphics3D().getPen().setColor(tChart1.getSeries(0).getColors().getColor(seriesOrder[i]));
}
else {
tChart1.getGraphics3D().getPen().setColor(tChart1.getSeries(0).getColor());
}
tChart1.getGraphics3D().horizontalLine(rect.x, rect.getRight(), (rect.y + rect.getBottom()) / 2);
}
}
}
}
});
tChart1.setLegendResolver(new LegendResolver() {
@Override
public String getItemText(Legend legend, LegendStyle legendStyle, int index, String text) {
if (tChart1.getSeriesCount() > 1) {
return tChart1.getSeries(seriesOrder[index]).titleOrName();
}
else {
return String.valueOf(tChart1.getSeries(0).getYValues().getValue(seriesOrder[index]));
}
}
@Override
public LegendItemCoordinates getItemCoordinates(Legend legend, LegendItemCoordinates coordinates) {
return coordinates;
}
@Override
public Rectangle getBounds(Legend legend, Rectangle rectangle) {
return rectangle;
}
});
}
Re: How to sort legend items along with its symbols
Posted: Mon Apr 02, 2012 7:06 pm
by 7667590
Thanks for your help. It'd be great if your suggestion could be built-in APIs
Re: How to sort legend items along with its symbols
Posted: Tue Apr 03, 2012 7:47 am
by yeray
Hi Jonathan,
The possibility to sort the legend items is already in the wish list to be implemented in future releases (TJ71014085)
Re: How to sort legend items along with its symbols
Posted: Fri Apr 06, 2012 6:59 pm
by 7667590
Hi Yeray,
I have symbols on chart. When I play with the codes you suggested, I found that legend symbols doesn't get rendered properly. Could you tell me how to render the legend symbols correctly?
The example below, I added two series: one with START shape and the other with CIRCLE shape. After sorting, the shapes got covered by a rectangle.
Code: Select all
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setSize(600, 600);
final TChart tChart1 = new TChart();
panel.add(tChart1);
tChart1.getAspect().setView3D(false);
//add 2 line series
Line line2 = new Line(tChart1.getChart());
line2.add(1, 2);
line2.add(2, 3);
line2.add(3, 4);
line2.setColor(Color.RED);
line2.setTitle("STAR");
line2.getPointer().setStyle(PointerStyle.STAR);
line2.getPointer().setVisible(true);
line2.getPointer().getBrush().setColor(Color.RED);
line2.getPointer().getPen().setColor(Color.RED);
line2.setShowInLegend(true);
Line line1 = new Line(tChart1.getChart());
line1.add(1.0, 1.0);
line1.add(2.0, 2.0);
line1.add(3.0, 3.0);
line1.setColor(Color.BLACK);
line1.setTitle("CIRCLE");
line1.getPointer().setStyle(PointerStyle.CIRCLE);
line1.getPointer().setVisible(true);
line1.getPointer().getBrush().setColor(Color.BLACK);
line1.getPointer().getPen().setColor(Color.BLACK);
line1.setShowInLegend(true);
final int[] seriesOrder;
final boolean isSort = true;
if (tChart1.getSeriesCount() > 1) {
seriesOrder = new int[tChart1.getSeriesCount()];
for (int i=0; i<tChart1.getSeriesCount(); i++)
seriesOrder[i] = i;
// sorting !!
if(isSort){
for (int i=0; i<seriesOrder.length; i++) {
for (int j=i+1; j<seriesOrder.length; j++) {
if (tChart1.getSeries(seriesOrder[j]).titleOrName().compareTo(tChart1.getSeries(seriesOrder[i]).titleOrName()) < 0) {
int tmp = seriesOrder[i];
seriesOrder[i] = seriesOrder[j];
seriesOrder[j] = tmp;
}
}
}
}
}
else {
seriesOrder = new int[tChart1.getSeries(0).getCount()];
for (int i=0; i<tChart1.getSeries(0).getCount(); i++)
seriesOrder[i] = i;
for (int i=0; i<seriesOrder.length; i++) {
for (int j=i+1; j<seriesOrder.length; j++) {
if (tChart1.getSeries(0).getYValues().getValue(seriesOrder[j]) < tChart1.getSeries(0).getYValues().getValue(seriesOrder[i])) {
int tmp = seriesOrder[i];
seriesOrder[i] = seriesOrder[j];
seriesOrder[j] = tmp;
}
}
}
}
tChart1.addChartPaintListener(new ChartPaintAdapter() {
@Override
public void chartPainted(ChartDrawEvent e) {
if (tChart1.getSeriesCount() > 1) {
if(isSort){
for (int i=0; i<tChart1.getLegend().getLegendItems().size(); i++) {
Rectangle rect = tChart1.getLegend().getLegendItems().getLegendItem(i).getSymbolRect();
if ((tChart1.getSeries(seriesOrder[i]) instanceof Custom) && (((Custom)tChart1.getSeries(seriesOrder[i])).getPointer().getVisible())) {
tChart1.getGraphics3D().getBrush().setColor(tChart1.getSeries(seriesOrder[i]).getColor());
tChart1.getGraphics3D().getPen().setColor(tChart1.getSeries(seriesOrder[i]).getColor());
tChart1.getGraphics3D().rectangle(rect);
}
else {
tChart1.getGraphics3D().getPen().setColor(tChart1.getSeries(seriesOrder[i]).getColor());
tChart1.getGraphics3D().horizontalLine(rect.x, rect.getRight(), (rect.y + rect.getBottom()) / 2);
}
}
}
}
else {
for (int i=0; i<tChart1.getLegend().getLegendItems().size(); i++) {
Rectangle rect = tChart1.getLegend().getLegendItems().getLegendItem(i).getSymbolRect();
if ((tChart1.getSeries(0) instanceof Custom) && (((Custom)tChart1.getSeries(0)).getPointer().getVisible())) {
if (tChart1.getSeries(0).getColorEach()) {
tChart1.getGraphics3D().getBrush().setColor(tChart1.getSeries(0).getColors().getColor(seriesOrder[i]));
}
else {
tChart1.getGraphics3D().getBrush().setColor(tChart1.getSeries(0).getColor());
}
tChart1.getGraphics3D().rectangle(rect);
}
else {
if (tChart1.getSeries(0).getColorEach()) {
tChart1.getGraphics3D().getPen().setColor(tChart1.getSeries(0).getColors().getColor(seriesOrder[i]));
}
else {
tChart1.getGraphics3D().getPen().setColor(tChart1.getSeries(0).getColor());
}
tChart1.getGraphics3D().horizontalLine(rect.x, rect.getRight(), (rect.y + rect.getBottom()) / 2);
}
}
}
}
});
tChart1.setLegendResolver(new LegendResolver() {
@Override
public String getItemText(Legend legend, LegendStyle legendStyle, int index, String text) {
if (tChart1.getSeriesCount() > 1) {
return tChart1.getSeries(seriesOrder[index]).titleOrName();
}
else {
return String.valueOf(tChart1.getSeries(0).getYValues().getValue(seriesOrder[index]));
}
}
@Override
public LegendItemCoordinates getItemCoordinates(Legend legend, LegendItemCoordinates coordinates) {
return coordinates;
}
@Override
public Rectangle getBounds(Legend legend, Rectangle rectangle) {
return rectangle;
}
});
frame.add(panel);
frame.setSize(600, 600);
frame.setVisible(true);
}
Re: How to sort legend items along with its symbols
Posted: Wed Apr 11, 2012 1:07 pm
by yeray
Hi Jonathan,
Jonathan wrote:After sorting, the shapes got covered by a rectangle.
Note the code I suggested you is actually drawing that rectangles at chartPainted event:
Code: Select all
@Override
public void chartPainted(ChartDrawEvent e) {
//...
if (tChart1.getSeriesCount() > 1) {
//...
if ((tChart1.getSeries(seriesOrder[i]) instanceof Custom) && (((Custom)tChart1.getSeries(seriesOrder[i])).getPointer().getVisible())) {
//...
tChart1.getGraphics3D().rectangle(rect);
If you want to draw the symbol the series has, you should add some more logic. If you are source code customer, you can see at Custom.java, the drawLegendShape does something like:
Code: Select all
if (getPointer().getVisible())
{
if (drawLine)
{
drawLine(g, false, tmpLegendColor, rect);
}
point.drawLegendShape(g, tmpLegendColor, rect, getLinePen().getVisible());
}
And you can see at SeriesPointer.java, how drawLegendShape method is actually calling:
Code: Select all
draw(g, false, (rect.x + rect.getRight()) / 2,
(rect.y + rect.getBottom()) / 2,
Math.min(horizSize, tmpHoriz),
Math.min(vertSize, tmpVert), color, style);
However, there is an alternative that will probably be easier than all this manual drawing:
You could hide all the series from being drawn in the legend, but still calculating the correct order (using the method suggested above or any other you may think):
Code: Select all
for (int i=0; i<tChart1.getSeriesCount(); i++) {
tChart1.getSeries(i).setShowInLegend(false);
seriesOrder[i] = i;
}
And then, instead of the custom drawing routine and the legend texts customization, you could add clones of the series in the correct order:
Code: Select all
for (int i=0; i<seriesOrder.length; i++) {
Series s = tChart1.getSeries(seriesOrder[i]).cloneSeries();
s.clear();
s.setShowInLegend(true);
}
Re: How to sort legend items along with its symbols
Posted: Wed Apr 11, 2012 2:23 pm
by 7667590
Thanks for your feedback.
While waiting for your feedback, I actually come up with simpler solution, which is similar to the hiding series in the legend in your latest answer.
Code: Select all
//add 2 line series
Line line2 = new Line(tChart1.getChart());
line2.add(1, 2);
line2.add(2, 3);
line2.add(3, 4);
line2.setColor(Color.RED);
line2.setTitle("STAR");
line2.getPointer().setStyle(PointerStyle.STAR);
line2.getPointer().setVisible(true);
line2.getPointer().getBrush().setColor(Color.RED);
line2.getPointer().getPen().setColor(Color.RED);
line2.setShowInLegend(true);
Line line1 = new Line(tChart1.getChart());
line1.add(1.0, 1.0);
line1.add(2.0, 2.0);
line1.add(3.0, 3.0);
line1.setColor(Color.BLACK);
line1.setTitle("CIRCLE");
line1.getPointer().setStyle(PointerStyle.CIRCLE);
line1.getPointer().setVisible(true);
line1.getPointer().getBrush().setColor(Color.BLACK);
line1.getPointer().getPen().setColor(Color.BLACK);
line1.setShowInLegend(true);
Collection<Series> series = tChart1.getSeries();
List<Series> lineList = new ArrayList<Series>();
for(Series s : series){
lineList.add(s);
}
//remove the original series
series.removeAll(lineList);
// sort
Collections.sort(lineList, new Comparator<Series>(){
@Override
public int compare(Series o1, Series o2) {
return o1.getTitle().compareTo(o2.getTitle());
}
});
series.addAll(lineList);
Re: How to sort legend items along with its symbols
Posted: Thu Apr 12, 2012 10:43 am
by yeray
Hi Jonathan,
Right. Thanks for sharing!
Re: How to sort legend items along with its symbols
Posted: Wed Oct 12, 2016 8:12 pm
by 9337126
I have about 10 series that needed in a specific order. Unlike my example, I could not be control the order of their creation.
* Programatically create the your series and put the series pointers in a collection, array, etc.
Code: Select all
for TrcNum := 1 to 10 do begin
TrcDta[TrcNum] := TLineSeries.Create(Nil);
with TrcDta[TrcNum] do begin
Color := DfltGphClr[TrcNum];
Title := aTrcTitle;
ParentChart := Nil; // important : don't define the owning TeeChart yet
ShowInLegend := true;
end;
end;
Sort your collection or traverse your array in the REVERSE order you want the items to appear in the legend.
The order ParentChart is defined sets the order of the items in the legend.
Code: Select all
for TrcNum := 10 downto 1 do begin
TrcDta[TrcNum].ParentChart := MyTeeChart;
end;
Re: How to sort legend items along with its symbols
Posted: Fri Oct 14, 2016 2:35 pm
by yeray
Hello,
Thanks for sharing to you too!