How to sort legend items along with its symbols
How to sort legend items along with its symbols
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?
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
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:
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;
}
});
}
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |
Re: How to sort legend items along with its symbols
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
Hi Jonathan,
The possibility to sort the legend items is already in the wish list to be implemented in future releases (TJ71014085)
The possibility to sort the legend items is already in the wish list to be implemented in future releases (TJ71014085)
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |
Re: How to sort legend items along with its symbols
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.
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
Hi Jonathan,
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:
And you can see at SeriesPointer.java, how drawLegendShape method is actually calling:
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):
And then, instead of the custom drawing routine and the legend texts customization, you could add clones of the series in the correct order:
Note the code I suggested you is actually drawing that rectangles at chartPainted event:Jonathan wrote:After sorting, the shapes got covered by a rectangle.
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);
Code: Select all
if (getPointer().getVisible())
{
if (drawLine)
{
drawLine(g, false, tmpLegendColor, rect);
}
point.drawLegendShape(g, tmpLegendColor, rect, getLinePen().getVisible());
}
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);
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;
}
Code: Select all
for (int i=0; i<seriesOrder.length; i++) {
Series s = tChart1.getSeries(seriesOrder[i]).cloneSeries();
s.clear();
s.setShowInLegend(true);
}
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |
Re: How to sort legend items along with its symbols
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.
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
Hi Jonathan,
Right. Thanks for sharing!
Right. Thanks for sharing!
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |
Re: How to sort legend items along with its symbols
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.
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.
* 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;
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
Hello,
Thanks for sharing to you too!
Thanks for sharing to you too!
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |