[TODO] Selectable multiple attributes/colour per node

Visual manipulations and refinements
Ferretti
Posts:14
Joined:03 Feb 2012 19:49
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1275: count(): Parameter must be an array or an object that implements Countable
Re: [TODO] Selectable multiple attributes/colour per node

Post by Ferretti » 11 Feb 2012 19:17

Yeah I will definitely release a plug-in, I need to implement SVG and PDF first, and tidy it up a little. Is there a more robust way I could store the data to make it easier for people to use? At the moment it requires a column labelled 'colourList', which isn't to most straightforward thing. Also I have the problem that it will always use this renderer even if I disable the checkbox, presumably this is some error on my part?

A personal request - I like the feature in the overview where moving over one node highlights its neighbours, is it possible to replicate this in preview mode? Also is it possible to create a standalone interactive graph using Gephi as the basis but without having to actually load the gephi software?

Thanks

User avatar
mbastian
Gephi Architect
Posts:728
Joined:10 Dec 2009 10:11
Location:San Francisco, CA
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1275: count(): Parameter must be an array or an object that implements Countable

Re: [TODO] Selectable multiple attributes/colour per node

Post by mbastian » 12 Feb 2012 07:26

Really cool! It looks great!
At the moment it requires a column labelled 'colourList', which isn't to most straightforward thing
What data type to you use? Because we have a list type in Gephi. It can be imported from a GEXF for example by setting 'listint' for an integer list, separated by one of the default separators (,|;). We don't support color lists but anyway it's better to import ints or doubles and assign colors later. Lists are not really integrated in Gephi at this point (no filtering capabilities or ranking). The column will be there, visible in the Data Laboratory and accessible like any other column.
Also I have the problem that it will always use this renderer even if I disable the checkbox, presumably this is some error on my part?
Are you defining a new Node Renderer or inherit from the default?
A personal request - I like the feature in the overview where moving over one node highlights its neighbours, is it possible to replicate this in preview mode?
It should be possible but we avoided doing that to maximize refresh rate in Preview. Our idea was to have speed and interactivity in Overview and customization and aesthetic in Preview.
Also is it possible to create a standalone interactive graph using Gephi as the basis but without having to actually load the gephi software?
Yes you can use the Gephi Toolkit. Here is an example of a standalone Preview component usage.

Ferretti
Posts:14
Joined:03 Feb 2012 19:49
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1275: count(): Parameter must be an array or an object that implements Countable

Re: [TODO] Selectable multiple attributes/colour per node

Post by Ferretti » 12 Feb 2012 16:28

At the moment it requires a column labelled 'colourList', which isn't to most straightforward thing
What data type to you use? Because we have a list type in Gephi. It can be imported from a GEXF for example by setting 'listint' for an integer list, separated by one of the default separators (,|;). We don't support color lists but anyway it's better to import ints or doubles and assign colors later. Lists are not really integrated in Gephi at this point (no filtering capabilities or ranking). The column will be there, visible in the Data Laboratory and accessible like any other column.
At the moment the 'colourList' column contains RBG values separated by commas, presumably stored as a String. I pull out this string and run it through a scanner to extract the RGB vales, which I then use to create the colours. Thing may be more complicated by the fact I am using GraphML to hold my graph data, I'm not sure if you can define types. The problem is a person will have to somehow know that if they want to use my plug-in they will have to have the specifically labelled 'colourlist' column, else it won't work.

Also I have the problem that it will always use this renderer even if I disable the checkbox, presumably this is some error on my part?
Are you defining a new Node Renderer or inherit from the default?
Currently I have:

Code: Select all

@ServiceProvider(service = Renderer.class)
public class MultiColourRenderer implements Renderer {
...
}
A personal request - I like the feature in the overview where moving over one node highlights its neighbours, is it possible to replicate this in preview mode?
It should be possible but we avoided doing that to maximize refresh rate in Preview. Our idea was to have speed and interactivity in Overview and customization and aesthetic in Preview.
So would this be something I could easily turn on or would it requre lots of changes? It's not the most important thing but it makes the graph more interactive and feel more 'alive'.
Also is it possible to create a standalone interactive graph using Gephi as the basis but without having to actually load the gephi software?
Yes you can use the Gephi Toolkit. Here is an example of a standalone Preview component usage.
Great, I will look more into this.

Thanks for your help and all your work!

Ferretti
Posts:14
Joined:03 Feb 2012 19:49
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1275: count(): Parameter must be an array or an object that implements Countable

Re: [TODO] Selectable multiple attributes/colour per node

Post by Ferretti » 13 Feb 2012 18:12

Hi, I have had a go at implementing the SVG renderer today but I cannot get gephi to actually use my renderer when I click export SVG/PDF/PNG. I think it is related to whatever is causing my boolean to not function (MultiColourRenderer is used whether it is ticked or not).

Here is the full code I have done so far - hopefully you can spot the error. I am not 100% sure my SVG path calculations are correct, especially line 147, I have been unable to test them!

Code: Select all

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.ferretti.MultiColourNode;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.geom.Arc2D;
import java.util.ArrayList;
import java.util.Scanner;
import org.gephi.graph.api.Node;
import org.gephi.preview.api.*;
import org.gephi.preview.plugin.items.NodeItem;
import org.gephi.preview.spi.Renderer;
import org.openide.util.lookup.ServiceProvider;
import org.w3c.dom.Element;
import processing.core.PGraphicsJava2D;

/**
 *
 * @author James
 */
@ServiceProvider(service = Renderer.class)
public class MultiColourRenderer implements Renderer {

    @Override
    public void preProcess(PreviewModel previewModel) {
    }

    @Override
    public void render(Item item, RenderTarget target, PreviewProperties properties) {
        if (target instanceof ProcessingTarget) {
            renderProcessing(item, (ProcessingTarget) target, properties);
        } else if (target instanceof SVGTarget) {
            renderSVG(item, (SVGTarget) target, properties);
        } else if (target instanceof PDFTarget) {
            renderPDF(item, (PDFTarget) target, properties);
        }
    }

    @Override
    public PreviewProperty[] getProperties() {
        return new PreviewProperty[]{
                    PreviewProperty.createProperty(this, "MultiColourNode", Boolean.class,
                    "Multi Colour Nodes",
                    "Make a node be coloured more then one hue",
                    PreviewProperty.CATEGORY_NODES).setValue(false)
                };
    }

    @Override
    public boolean isRendererForitem(Item item, PreviewProperties properties) {
        return item.getType().equals(Item.NODE);
    }

    private void renderProcessing(Item item, ProcessingTarget target, PreviewProperties properties) {
        //Params
        Float xF = item.getData(NodeItem.X);
        Float yF = item.getData(NodeItem.Y);
        Float sizeF = item.getData(NodeItem.SIZE);

        int x = xF.intValue();
        int y = yF.intValue();
        int size = sizeF.intValue();

        Node n = (Node) item.getSource();
        String colourList = (String) n.getNodeData().getAttributes().getValue("colourList");

        ArrayList<Color> colourArray = splitColourList(colourList);
        int radius = size - 4;


        PGraphicsJava2D graphics = (PGraphicsJava2D) target.getGraphics();
        Graphics2D g2 = graphics.g2;


        // draw colour indices as pie chart around point
        if (colourArray.size() > 0) {
            double arcAngle = 360.0 / colourArray.size();

            // draw 'pieces of pie'
            for (int i = 0; i < colourArray.size(); i++) {
                //System.out.println(Integer.parseInt(n.getColour(i)));
                g2.setColor(colourArray.get(i));
                g2.fillArc((x - radius), (y - radius), (radius * 2), (radius * 2),
                        (int) (arcAngle * i), (int) arcAngle);
            }

            // draw 'spokes' between pieces
            if (colourArray.size() > 1) {
                Stroke oldStroke = g2.getStroke();
                for (int i = 0; i < colourArray.size(); i++) {
                    double spokeAngle = arcAngle * i / 180 * Math.PI;
                    g2.setColor(Color.BLACK);
                    g2.setStroke(new BasicStroke(0.5f));
                    g2.drawLine(x, y, (int) (x + radius * Math.cos(spokeAngle)), (int) (y - radius * Math.sin(spokeAngle)));
                }
                g2.setStroke(oldStroke);
            }

        } else {
            // draw filled white circle
            g2.setColor(Color.WHITE);
            g2.fillOval(x - radius, y - radius, radius * 2, radius * 2);
        }

        // draw black circle
        g2.setColor(Color.BLACK);
        g2.drawOval(x - radius, y - radius, radius * 2, radius * 2);


        //original
        //g2.setPaint(p);
        //g2.fillOval((int) (x.floatValue() - radius), (int) (y.floatValue() - radius), (int) (radius * 2), (int) (radius * 2));
    }

    private void renderSVG(Item item, SVGTarget target, PreviewProperties properties) {

        //Params
        Float x = item.getData(NodeItem.X);
        Float y = item.getData(NodeItem.Y);
        Float size = item.getData(NodeItem.SIZE);


        Node n = (Node) item.getSource();
        String colourList = (String) n.getNodeData().getAttributes().getValue("colourList");

        ArrayList<Color> colourArray = splitColourList(colourList);
        Float radius = size - 3;
        //float borderSize = properties.getFloatValue(PreviewProperty.NODE_BORDER_WIDTH);
        float alpha = properties.getIntValue(PreviewProperty.NODE_OPACITY) / 100f;
        if (alpha > 1) {
            alpha = 1;
        }

        // draw colour indices as pie chart around point
        if (colourArray.size() > 0) {
            float arcAngle = (float) (360.0 / colourArray.size());

            // draw 'pieces of pie'
            for (int i = 0; i < colourArray.size(); i++) {
                //Arc2D arca = new Arc2D.Float((x - radius), (y - radius), (radius * 2), (radius * 2), (arcAngle * i), (arcAngle), Arc2D.CHORD);
                float[] startXY = toCartesianCoordinate(x, y, radius, arcAngle*i);
                float[] endXY = toCartesianCoordinate(x, y, radius, (arcAngle*i)+arcAngle);
                Element nodeElem = target.createElement("path");
                nodeElem.setAttribute("class", n.getNodeData().getId());
                nodeElem.setAttribute("fill", target.toHexString(colourArray.get(i)));
                
                nodeElem.setAttribute("d", "M" + " " + startXY[0] + " " + startXY[1] + " " + "A" + " " + radius + " " + radius + " " + 0 + " " + 0 + " " + 0 + " " + endXY[0] + " " + endXY[1]);
                //PATH = M startXY[0] startXY[1] A radius radius 0 0 0 endXY[0] endXY[1]
                
                nodeElem.setAttribute("fill-opacity", "" + alpha);
                nodeElem.setAttribute("stroke", "black");
                nodeElem.setAttribute("stroke-width", "2");
            }


        } else {
            Element nodeElem = target.createElement("circle");
            nodeElem.setAttribute("class", n.getNodeData().getId());
            nodeElem.setAttribute("cx", x.toString());
            nodeElem.setAttribute("cy", y.toString());
            nodeElem.setAttribute("r", size.toString());
            nodeElem.setAttribute("fill", target.toHexString(Color.WHITE));
            nodeElem.setAttribute("fill-opacity", "" + alpha);
        }



    }

    private void renderPDF(Item item, PDFTarget pdfTarget, PreviewProperties properties) {
        //TODO
    }

    /**
     * turns a list of numbers into an ArrayList of Colours
     *
     * @param colorList String, list of colours taken from the column
     * "colourList"
     * @return An ArrayList of Colour objects, to be drawn on the node
     */
    private ArrayList<Color> splitColourList(String colourList) {
        ArrayList<Color> toReturn = new ArrayList<Color>();

        //-1 denotes a default value where no colours were attributed to a node
        if (!colourList.equals("-1")) {
            Scanner scan = new Scanner(colourList);
            scan.useDelimiter(",");
            while (scan.hasNext()) {
                String str = scan.next();
                Integer rgb = Integer.parseInt(str);
                Color col = new Color(rgb);
                toReturn.add(col);
            }
        }

        return toReturn;

    }

    private float[] toCartesianCoordinate(float centerX, float centerY, float radius, float angleInDegrees) {
        float angleInRadians = (float) (angleInDegrees * Math.PI / 180.0);
        float x = (float) (centerX + radius * Math.cos(angleInRadians));
        float y = (float) (centerY + radius * Math.sin(angleInRadians));
        float[] arr = {x, y};
        return arr;
    }
}
Thanks, hopefully we can crack this and get the plug in out there.

EDIT: After playing around with a few things I have discovered that preview mode is rendering two copies of the graph, mine and the default below it. This must be some error in how I have set up the plug-in!

User avatar
eduramiba
Gephi Code Manager
Posts:1064
Joined:22 Mar 2010 15:30
Location:Madrid, Spain
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1275: count(): Parameter must be an array or an object that implements Countable

Re: [TODO] Selectable multiple attributes/colour per node

Post by eduramiba » 13 Feb 2012 23:35

Hi,

To make your checkbox work you should change isRendererForItem to:

Code: Select all

public boolean isRendererForitem(Item item, PreviewProperties properties) {
    return item.getType().equals(Item.NODE) && properties.getBooleanValue("MultiColourNode");
}
It is normal that both normal nodes and your nodes render, because your renderer is not supersiding the default one. I am not sure about supersiding being safe when the amount of preview plugins grow, since some could rely on it.
So the user should clearly notice on this and future plugins that he has to disable the normal nodes rendering and enable yours. Anyone has a better idea for these cases?

In order to let the user select any column with any title you can create your own preview UI. A similar example called NodesZOrderingUI is available here https://github.com/gephi/gephi-plugins-bootcamp
Also if you use a number list column, you won't have to parse the strings to get the numbers and can be more friendly for users.

Eduardo

Ferretti
Posts:14
Joined:03 Feb 2012 19:49
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1275: count(): Parameter must be an array or an object that implements Countable

Re: [TODO] Selectable multiple attributes/colour per node

Post by Ferretti » 14 Feb 2012 18:19

Hi, I have fixed the check box and added support for Number List columns, but the SVG is still using the default renderer, and the original graph is still rendered underneath. This is undesirable because when I add labels they are attached the the bottom graph, so are blocked by the nodes in my plug-in rendering above them. Also If I create nodes that are smaller than the originals you can see them underneath.
So the user should clearly notice on this and future plugins that he has to disable the normal nodes rendering and enable yours.
Surely when you click the check box the original renderer should be disabled and only mine used? it would possibly make more sense to have a drop-down menu to select renderer next to where the "presets" menu is. You could select renderer and also be presented with options specific to that renderer in the panel on the right.

Is theres something in my code that is preventing the SVG from rendering using my renderer, or is it that a bug further up the chain?

Thanks

User avatar
eduramiba
Gephi Code Manager
Posts:1064
Joined:22 Mar 2010 15:30
Location:Madrid, Spain
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1275: count(): Parameter must be an array or an object that implements Countable

Re: [TODO] Selectable multiple attributes/colour per node

Post by eduramiba » 14 Feb 2012 21:14

Hi,
What happens is that a Renderer can't disable other renderer and does not automatically disable other node renderers, for example. So the only thing you could do is supersede it in ServiceProvider annotation, but that is not good in my opinion.

But you gave me an idea :) I think the best solution for these kind of problems would be to always have a panel in preview that shows every installed renderer and a checkbox to control it. This way the user controls easily what should be renderer, you would not have to create a checkbox to enable your renderer, and also this could be used to automatically hide preview settings of renderers that are not enabled at the moment.
What do you guys think about this?

About the labels under your nodes, note that the labels are rendered by another separate renderer and it should be executed after yours. So to control the order of renderers you use the position parameter of ServiceProvider.

For example NodeLabelRenderer has this:

Code: Select all

@ServiceProvider(service = Renderer.class, position = 400)
So just do the same with a lower than 400 number and your renderer will execute before the labels renderer.

About the SVG, I could not see why it is not working with your code, it looks right.

Eduardo

Ferretti
Posts:14
Joined:03 Feb 2012 19:49
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1275: count(): Parameter must be an array or an object that implements Countable

Re: [TODO] Selectable multiple attributes/colour per node

Post by Ferretti » 18 Feb 2012 20:11

Hi, the preview idea sounds great, it will be much more useful when there are many preview plugins out.

I am still having problems with the rendering unfortunately, I cannot get my lables above my nodes.

I have tried:

Code: Select all

@ServiceProvider(service = Renderer.class, position = 1)
same result.

Code: Select all

@ServiceProvider(service = Renderer.class, supersedes={"NodeRenderer"})
same result, and still renders original nodes. I have included the {} because it asks for a String[].

Code: Select all

@ServiceProvider(service = Renderer.class, position = 1, supersedes={"NodeRenderer"})
Same result.

Is it something to do with the Label renderer being attached to the original node renderer?

Thanks.

Also, SVG will still always use the default renderer. I don't need this function personally but it would be nice to get it working for others who may wish to in the future when this plugin is released.

Thanks, James

Is the label renderer somhow atatched to the NodeRenderer?

User avatar
eduramiba
Gephi Code Manager
Posts:1064
Joined:22 Mar 2010 15:30
Location:Madrid, Spain
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1275: count(): Parameter must be an array or an object that implements Countable

Re: [TODO] Selectable multiple attributes/colour per node

Post by eduramiba » 19 Feb 2012 15:32

Hi,
Yes we decided to do the Renderers manager idea.

To supersede a renderer you have to provide the full class name, in this case "org.gephi.preview.plugin.renderers.NodeRenderer"
If you want to disable node renderer you can set the opacity to 0. In the future this will be done to any renderer with the manager.

About the position, it is strange that it does not work.
Here is a list of the default renderers and their positions:
org.gephi.preview.plugin.renderers.EdgeRenderer 100
org.gephi.preview.plugin.renderers.ArrowRenderer 200
org.gephi.preview.plugin.renderers.NodeRenderer 300
org.gephi.preview.plugin.renderers.NodeLabelRenderer 400
org.gephi.preview.plugin.renderers.EdgeLabelRenderer 500

Eduardo

Ferretti
Posts:14
Joined:03 Feb 2012 19:49
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1275: count(): Parameter must be an array or an object that implements Countable

Re: [TODO] Selectable multiple attributes/colour per node

Post by Ferretti » 31 Mar 2012 16:26

Hi thee, sorry it has been such a long time, have you guys made much progress with the renderer manager?

It has come to the time where I need to use one of the graphs in my report, but I am still stuck when attempting to get the leabels to render correctly above my custom node renderer, maybe you guys have discovered the problem?

Attached is the code in its current state, the issue I presume lies in the @ServiceProvider line. Even when including the full renderer name in the supersedes field the original renderer still runs beneath mine.

I would like to get this finished and working to help others who wish to use this feature!

Thanks

Code: Select all

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.ferretti.MultiColourNode;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.util.ArrayList;
import java.util.Scanner;
import org.gephi.graph.api.Node;
import org.gephi.preview.api.*;
import org.gephi.preview.plugin.items.NodeItem;
import org.gephi.preview.spi.Renderer;
import org.gephi.data.attributes.type.IntegerList;
import org.gephi.preview.plugin.renderers.NodeRenderer;
import org.openide.util.lookup.ServiceProvider;
import org.w3c.dom.Element;
import processing.core.PGraphicsJava2D;

/**
 *
 * @author James
 */
@ServiceProvider(service = Renderer.class, position = 1, supersedes={"org.gephi.preview.plugin.renderers.NodeRenderer"})
public class MultiColourRenderer implements Renderer {

    @Override
    public void preProcess(PreviewModel previewModel) {
    }

    @Override
    public void render(Item item, RenderTarget target, PreviewProperties properties) {
        if (target instanceof ProcessingTarget) {
            renderProcessing(item, (ProcessingTarget) target, properties);
        } else if (target instanceof SVGTarget) {
            renderSVG(item, (SVGTarget) target, properties);
        } else if (target instanceof PDFTarget) {
            renderPDF(item, (PDFTarget) target, properties);
        }
    }

    @Override
    public PreviewProperty[] getProperties() {
        return new PreviewProperty[]{
                    PreviewProperty.createProperty(this, "MultiColourNode", Boolean.class,
                    "Multi Colour Nodes",
                    "Make a node be coloured more then one hue",
                    PreviewProperty.CATEGORY_NODES).setValue(false)
                };
    }

    @Override
    public boolean isRendererForitem(Item item, PreviewProperties properties) {
        return item.getType().equals(Item.NODE) && properties.getBooleanValue("MultiColourNode");
    }

    private void renderProcessing(Item item, ProcessingTarget target, PreviewProperties properties) {
        //Params
        Float xF = item.getData(NodeItem.X);
        Float yF = item.getData(NodeItem.Y);
        //Float sizeF = item.getData(NodeItem.SIZE);

        int x = xF.intValue();
        int y = yF.intValue();

        Node n = (Node) item.getSource();
        Integer size = (Integer) n.getNodeData().getAttributes().getValue("size");


        Object colourList = n.getNodeData().getAttributes().getValue("colourList");

        ArrayList<Color> colourArray = splitColourList(colourList);
        int radius = size;


        PGraphicsJava2D graphics = (PGraphicsJava2D) target.getGraphics();
        Graphics2D g2 = graphics.g2;


        // draw colour indices as pie chart around point
        if (colourArray.size() > 0) {
            double arcAngle = 360.0 / colourArray.size();

            // draw 'pieces of pie'
            for (int i = 0; i < colourArray.size(); i++) {
                //System.out.println(Integer.parseInt(n.getColour(i)));
                g2.setColor(colourArray.get(i));
                g2.fillArc((x - radius), (y - radius), (radius * 2), (radius * 2),
                        (int) (arcAngle * i), (int) arcAngle);
            }

            // draw 'spokes' between pieces
            if (colourArray.size() > 1) {
                Stroke oldStroke = g2.getStroke();
                for (int i = 0; i < colourArray.size(); i++) {
                    double spokeAngle = arcAngle * i / 180 * Math.PI;
                    g2.setColor(Color.BLACK);
                    g2.setStroke(new BasicStroke(0.5f));
                    g2.drawLine(x, y, (int) (x + radius * Math.cos(spokeAngle)), (int) (y - radius * Math.sin(spokeAngle)));
                }
                g2.setStroke(oldStroke);
            }

        } else {
            // draw filled white circle
            g2.setColor(Color.WHITE);
            g2.fillOval(x - radius, y - radius, radius * 2, radius * 2);
        }

        // draw black circle
        g2.setColor(Color.BLACK);
        g2.drawOval(x - radius, y - radius, radius * 2, radius * 2);


        //original
        //g2.setPaint(p);
        //g2.fillOval((int) (x.floatValue() - radius), (int) (y.floatValue() - radius), (int) (radius * 2), (int) (radius * 2));
    }

    private void renderSVG(Item item, SVGTarget target, PreviewProperties properties) {

        //Params
        Float x = item.getData(NodeItem.X);
        Float y = item.getData(NodeItem.Y);
        Float size = item.getData(NodeItem.SIZE);


        Node n = (Node) item.getSource();

        Object colourListObj = n.getNodeData().getAttributes().getValue("colourList");




        ArrayList<Color> colourArray = splitColourList(colourListObj);
        Float radius = size - 3;
        //float borderSize = properties.getFloatValue(PreviewProperty.NODE_BORDER_WIDTH);
        float alpha = properties.getIntValue(PreviewProperty.NODE_OPACITY) / 100f;
        if (alpha > 1) {
            alpha = 1;
        }

        // draw colour indices as pie chart around point
        if (colourArray.size() > 0) {
            float arcAngle = (float) (360.0 / colourArray.size());

            // draw 'pieces of pie'
            for (int i = 0; i < colourArray.size(); i++) {
                //Arc2D arca = new Arc2D.Float((x - radius), (y - radius), (radius * 2), (radius * 2), (arcAngle * i), (arcAngle), Arc2D.CHORD);
                float[] startXY = toCartesianCoordinate(x, y, radius, arcAngle * i);
                float[] endXY = toCartesianCoordinate(x, y, radius, (arcAngle * i) + arcAngle);
                Element nodeElem = target.createElement("path");
                nodeElem.setAttribute("class", n.getNodeData().getId());
                nodeElem.setAttribute("fill", target.toHexString(colourArray.get(i)));

                nodeElem.setAttribute("d", "M" + " " + startXY[0] + " " + startXY[1] + " " + "A" + " " + radius + " " + radius + " " + 0 + " " + 0 + " " + 0 + " " + endXY[0] + " " + endXY[1]);
                //PATH = M startXY[0] startXY[1] A radius radius 0 0 0 endXY[0] endXY[1]

                nodeElem.setAttribute("fill-opacity", "" + alpha);
                nodeElem.setAttribute("stroke", "black");
                nodeElem.setAttribute("stroke-width", "2");
            }


        } else {
            Element nodeElem = target.createElement("circle");
            nodeElem.setAttribute("class", n.getNodeData().getId());
            nodeElem.setAttribute("cx", x.toString());
            nodeElem.setAttribute("cy", y.toString());
            nodeElem.setAttribute("r", size.toString());
            nodeElem.setAttribute("fill", target.toHexString(Color.WHITE));
            nodeElem.setAttribute("fill-opacity", "" + alpha);
        }



    }

    private void renderPDF(Item item, PDFTarget pdfTarget, PreviewProperties properties) {
        //TODO
    }

    /**
     * turns a list of numbers into an ArrayList of Colours should be able to
     * deal with bot a string or a IntegerList item
     *
     * @param colorList String, list of colours taken from the column
     * "colourList"
     * @return An ArrayList of Colour objects, to be drawn on the node
     */
    private ArrayList<Color> splitColourList(Object colourListObj) {
        ArrayList<Color> toReturn = new ArrayList<Color>();

        if (colourListObj instanceof IntegerList) {
            IntegerList colourIntList = (IntegerList) colourListObj;
            if (colourIntList != null) {
                for (int i = 0; i < colourIntList.size(); i++) {
                    Integer rgb = colourIntList.getItem(i);
                    rgb = rgb/15;
                    Color col = new Color(rgb);
                    if (!toReturn.contains(col)) {
                        toReturn.add(col);
                    }
                }
            }
        } else if (colourListObj instanceof String) {
            //-1 denotes a default value where no colours were attributed to a node
            String colourList = (String) colourListObj;
            if (!colourList.equals("-1")) {
                Scanner scan = new Scanner(colourList);
                scan.useDelimiter(",");
                while (scan.hasNext()) {
                    String str = scan.next();
                    Integer rgb = str.hashCode();
                    rgb = rgb/15;
                    //Integer rgb = Integer.parseInt(str);
                    Color col = new Color(rgb);
                    if (!toReturn.contains(col)) {
                        toReturn.add(col);
                    }

                }
            }
        }
        return toReturn;
    }

    private float[] toCartesianCoordinate(float centerX, float centerY, float radius, float angleInDegrees) {
        float angleInRadians = (float) (angleInDegrees * Math.PI / 180.0);
        float x = (float) (centerX + radius * Math.cos(angleInRadians));
        float y = (float) (centerY + radius * Math.sin(angleInRadians));
        float[] arr = {x, y};
        return arr;
    }
}

Post Reply
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1275: count(): Parameter must be an array or an object that implements Countable