Web WaferMap Chart

1 2 > >> (Page 1 of 2)
  • james

    james - 2011-08-10


    Is there a way to display a wafermap chart using cewolf?


  • Ulf Dittmer

    Ulf Dittmer - 2011-08-10

    Not currently, but since the JFreeChart library (on which cewolf's charts are based) can generate those, it shouldn't be too hard to add. I should have a new release by over the weekend that does this.

  • james

    james - 2011-08-11

    Thank you so much. Looking forward for the new release.

  • Ulf Dittmer

    Ulf Dittmer - 2011-08-12

    If you haven't noticed yet - the release is out. The JFreeChart wafer map code is actually buggy, so I had to work around that.

  • james

    james - 2011-08-13

    Thank you for making the change. I have just checked the code and it works as expected. I also did a few changes to make the wafer map work while waiting for your release. I added a class de.laures.cewolf.cpp.WaferMapRendererProcessor.java to address other needs such as adding legends, subtitles (still working on this), etc. to the chart (to take care of aesthetics). Do you have an existing implementation to cater this functional requirement i could use as well? (I'd rather use your implementation if it exists) Also, i added a few lines of code into de.laures.cewolf.cpp.SeriesPaintProcessor.java to provide users a way to dynamically configure the series paint to the chart, this is one integral part in creating wafer map charts because it will allow users to correlate the legends with the wafer cell values. Appreciate your feedback. Thank you.

  • Ulf Dittmer

    Ulf Dittmer - 2011-08-13

    Adding and styling titles and subtitles is handled by the TitleEnhancer postprocessor.

    Legends can be shown or hidden via the "showlegend" attribute.

    The SeriesPaintProcessor wasn't set up to handle wafer map plots; I've just fixed that locally.

  • Ulf Dittmer

    Ulf Dittmer - 2011-08-13

    Released version 1.1.8 that fixes the SeriesPaintProcessor.

  • james

    james - 2011-08-13

    Thank you once again for making the necessary changes on SeriesPaintProcessor  and TitleEnhancer. Regarding the legends, i was hoping to customize the color coding the description of every color (what the cell colors mean). It would look like a group of "<color>-<description>", enclosed in a box on the upper right corner of the chart. Is it okay to post a code snippet here? i have created a sample implementation that could help visualize what the legend looks like… (I'm not quite sure if this is already possible with the current library). Appreciate your kind support. Thanks.

  • Ulf Dittmer

    Ulf Dittmer - 2011-08-13

    I can't picture how that would be different from how legends look now -except for a different position- so, yeah, feel free to post the code here or send it to me by email.

  • james

    james - 2011-08-13

    Below is the code, please let me know if this is already possible with the current library or if you have any other thoughts about it. Thanks.

    public class WaferMapLegendProcessor implements ChartPostProcessor, Serializable {
        static final long serialVersionUID = -1915129061254557435L;
        public void processChart(Object chart, Map params) {
            JFreeChart localChart = (JFreeChart) chart;
            Plot plot = (Plot) localChart.getPlot();

            if (plot instanceof WaferMapPlot) {
                //WaferMapPlot waferMapPlot = (WaferMapPlot) plot;
                //WaferMapRenderer render = new WaferMapRenderer(params.size(), WaferMapRenderer.POSITION_INDEX);

                LegendItemCollection legendItemCollection = new LegendItemCollection();
                if (params.size() > 0) {
                    String colorStr = null;
                    String legendDesc = null;
                    Iterator iterator = params.keySet().iterator();
                    while (iterator.hasNext()) {
                    colorStr = (String) iterator.next();
                    legendDesc = (String) params.get(colorStr);
                    legendItemCollection.add(new LegendItem(legendDesc, Color.decode(colorStr)));

                LegendItemSource legendItemSource = setLegendItemSource(legendItemCollection);

        public static LegendItemSource setLegendItemSource(final LegendItemCollection legendItemCollection) {
            LegendItemSource legendItemSrc = new LegendItemSource() {

                public LegendItemCollection getLegendItems() {
                    return legendItemCollection;
            return legendItemSrc;

        public static LegendTitle getLegendTitle(LegendItemSource legendItemSource) {
            int labelCount = legendItemSource.getLegendItems().getItemCount();
            Arrangement hLayout = new GridArrangement(labelCount, 1);
            Arrangement vLayout = new GridArrangement(0, 0);

            LegendTitle legendTitle = new LegendTitle(legendItemSource, hLayout, vLayout);
            legendTitle.setBorder(1, 1, 1, 1);
            legendTitle.setMargin(5, 5, 5, 10);
            legendTitle.setItemFont(new Font("SansSerif", Font.BOLD, 10));

            return legendTitle;

  • Ulf Dittmer

    Ulf Dittmer - 2011-08-13

    What would the parameters look like?

  • james

    james - 2011-08-13

    Oops I forgot to include that….

    Here is how it is being used in the JSP.

    <jsp:useBean id="waferMapLegend" class="de.laures.cewolf.cpp.WaferMapLegendProcessor" />

    <cewolf:chartpostprocessor id="waferMapLegend">
                    <cewolf:param name="#14ff1a" value="1-desc" />
                    <cewolf:param name="#ff0000" value="7-desc" />
                    <cewolf:param name="#ff00fe" value="10-desc" />
                    <cewolf:param name="#7640ff" value="12-desc" />
                    <cewolf:param name="#4896ff" value="21-desc" />
                    <cewolf:param name="#ffd0d4" value="22-desc" />
                    <cewolf:param name="#ffd0d4" value="24-desc" />
                    <cewolf:param name="#9c0c1e" value="25-desc" />
                    <cewolf:param name="#d29428" value="26-desc" />

  • Ulf Dittmer

    Ulf Dittmer - 2011-08-14

    Thanks. I've added a slightly reworked version to cewolf 1.1.9 - it uses the main legend, so the showlegend and legendanchor attributes work with it.

    (As an aside, in the future please leave the import statements intact when posting code - it's no fun having to hunt those down.)

  • james

    james - 2011-08-15

    Thank you for the update. The new legend looks great! Your integration to the legendanchor is excellent!

    Point well noted regarding the code posting.

    I will keep you posted if anything else comes up. Thanks again!

  • james

    james - 2011-08-15

    I was playing around with the TitleEnhancer and i came across some limitations with the current feature. I implemented a few additional ways to provide users more freedom to customize the look and alignment of the subtitle objects.

    Below is the updated code i came up with, kindly counter check and let me know if this could be implemented or are there any other better approaches… Once again, thank you so much for the continuous support!

    package de.laures.cewolf.cpp;

    import java.awt.Color;
    import java.awt.Font;
    import java.io.Serializable;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;

    import de.laures.cewolf.ChartPostProcessor;

    import org.jfree.chart.JFreeChart;
    import org.jfree.chart.title.TextTitle;
    import org.jfree.ui.HorizontalAlignment;
    import org.jfree.ui.RectangleEdge;

    * A postprocessor for setting a (sub)title on a chart. It supports the following parameters:
    * <BR><b>type</b> title/subtitle; default is title
    * <BR><b>title</b> no default, title won't be set if empty
    * <BR><b>fontname</b> optional; default SansSerif
    * <BR><b>fontsize</b> optional; default 18 for titles, 12 for subtitles
    * <BR><b>paint</b> optional; default #000000 (i.e., black)
    * <BR><b>backgroundpaint</b> optional; default #FFFFFF (i.e., white)
    * <BR><b>bold</b> true/false; optional; default true
    * <BR><b>italic</b> true/false; optional; default false
    * <P>
    * Usage:<P>
    * &lt;chart:chartpostprocessor id="subTitle"&gt;<BR>
    * &nbsp;&nbsp;&lt;chart:param name="type" value="title" /&gt;<BR>
    * &nbsp;&nbsp;&lt;chart:param name="title" value="My Important Title" /&gt;<BR>
    * &nbsp;&nbsp;&lt;chart:param name="fontname" value="Serif" /&gt;<BR>
    * &nbsp;&nbsp;&lt;chart:param name="fontsize" value="24" /&gt;<BR>
    * &nbsp;&nbsp;&lt;chart:param name="paint" value="#FF8800" /&gt;<BR>
    * &nbsp;&nbsp;&lt;chart:param name="backgroundpaint" value="#0088FF" /&gt;<BR>
    * &nbsp;&nbsp;&lt;chart:param name="bold" value="false" /&gt;<BR>
    * &nbsp;&nbsp;&lt;chart:param name="italic" value="true" /&gt;<BR>
    * &lt;/chart:chartpostprocessor&gt;
    * <P>
    * Based on the ExtraTitleEnhancer class from the cewolfexample web app.

    public class TitleEnhancer implements ChartPostProcessor, Serializable
    static final long serialVersionUID = 591686288142936677L;

        public void processChart (Object chart, Map params) {
    JFreeChart localChart = (JFreeChart) chart;
    String title = "";
    String type = "title";
    String fontName = "SansSerif";
    Color paint = null;
    Color backgroundPaint = null;
    int fontSize = 18;
    boolean isBold = true;
    boolean isItalic = false;
    HorizontalAlignment tAlign = HorizontalAlignment.CENTER;
                    HorizontalAlignment hAlign = HorizontalAlignment.CENTER;
                    RectangleEdge position = RectangleEdge.TOP;

    String typeParam = (String) params.get("type");
    if (typeParam != null && typeParam.trim().length() > 0)
    type = typeParam.trim();

                    // change on the title entry will provide a way to have a
                    // subtitle with mutliple lines on the rendered image.
    String titleParam = (String) params.get("title");
    if (titleParam != null && titleParam.trim().length() > 0) {
                        String strArray = titleParam.split(",");
                        for (int i = 0; i < strArray.length; i++) {
                            title += strArray_ + "\n";

    String fontNameParam = (String) params.get("fontname");
    if (fontNameParam != null && fontNameParam.trim().length() > 0)
    fontName = fontNameParam.trim();

    String fontSizeParam = (String) params.get("fontsize");
    if (fontSizeParam != null && fontSizeParam.trim().length() > 0) {
    try {
    fontSize = Integer.parseInt(fontSizeParam);
    if (fontSize < 1)
    fontSize = 18;
    } catch (NumberFormatException nfex) { }

    String paintParam = (String) params.get("paint");
    if (paintParam != null && paintParam.trim().length() > 0) {
    try {
    paint = Color.decode(paintParam);
    } catch (NumberFormatException nfex) { }

    String backgroundpaintParam = (String) params.get("backgroundpaint");
    if (backgroundpaintParam != null && backgroundpaintParam.trim().length() > 0) {
    try {
    backgroundPaint = Color.decode(backgroundpaintParam);
    } catch (NumberFormatException nfex) { }

    String boldParam = (String) params.get("bold");
    if (boldParam != null)
    isBold = "true".equals(boldParam.toLowerCase());

    String italicParam = (String) params.get("italic");
    if (italicParam != null)
    isItalic = "true".equals(italicParam.toLowerCase());

                    // just uncommented the previous code to enable text align.
    String tAlignParam = (String) params.get("talign");
    if (tAlignParam != null) {
                        if ("left".equalsIgnoreCase(tAlignParam)) {
                            tAlign = HorizontalAlignment.LEFT;
                        } else if ("right".equalsIgnoreCase(tAlignParam)) {
                            tAlign = HorizontalAlignment.RIGHT;

                    // allow users to configure the horizontal alignment of the
                    // object.
                    String hAlignParam = (String) params.get("halign");
    if (hAlignParam != null) {
                        if ("left".equalsIgnoreCase(hAlignParam)) {
                            hAlign = HorizontalAlignment.LEFT;
                        } else if ("right".equalsIgnoreCase(hAlignParam)) {
                            hAlign = HorizontalAlignment.RIGHT;

                    // allow users to configure the position of the object.
                    String positionParam = (String) params.get("position");
                    if (positionParam != null) {
                        if ("right".equalsIgnoreCase(positionParam)) {
                            position = RectangleEdge.RIGHT;
                        } else if ("bottom".equalsIgnoreCase(positionParam)) {
                            position = RectangleEdge.BOTTOM;
                        } else if ("left".equalsIgnoreCase(positionParam)) {
                            position = RectangleEdge.LEFT;

    if (title != null || "title".equals(type)) {
    TextTitle tt = null;
    if ("subtitle".equals(type)) {
    // search for subtitle

                                    List subTitles = localChart.getSubtitles();
    Iterator iter = subTitles.iterator();
    while (iter.hasNext()) {
    Object o = iter.next();
    if (o instanceof TextTitle) {
    tt = (TextTitle) o;

    //if (tt == null) {
    tt = new TextTitle(title);
    } else {
    tt = localChart.getTitle();
    if (tt == null) {
    tt = new TextTitle(title);

    Font font = new Font(fontName,
    (isBold ? Font.BOLD : 0) + (isItalic ? Font.ITALIC : 0),
    if (paint != null)
    if (backgroundPaint != null)
                            if (tAlign != null)
                            if (hAlign != null)
                            if (position != null)


  • Ulf Dittmer

    Ulf Dittmer - 2011-08-17

    Looks good, I'll ad a slightly adapted version to the next point-release. I'm just waiting for feedback about an unrelated performance issue.

  • james

    james - 2011-08-18

    Thanks, looking forward to the new release.

    One other question I have in mind, is there by any way we can add tooltips to the wafer map cells?

    I have been looking into the jfreechart library and it seems that tooltip inclusion to wafer map cells is one of the limitations.

    Thanks and regards.

  • Ulf Dittmer

    Ulf Dittmer - 2011-08-18

    Tooltips would be a cewolf feature, not a JFreeChart feature. Since wafer maps weren't supported by cewolf until recently, it's not surprising nobody has looked at this :-)

  • james

    james - 2011-08-22

    I though it was a jfreechart feature because I saw a couple of jfreechart examples implementing tooltips and assumed it was the base reference of cewolf. Thank you for the info and redirecting me to the right path regarding this topic.

    Will it be easy to implement the wafer map cell tooltips (eg. xy coordinate info)?
    For now, I will also try to explore the existing code base on how you implemented the tooltips and hopefully get a good grasp about the process involved in building one. Please let me know if you have any tips/suggestions that would help me better understand the process behind tooltip creation.

    Thanks again for the continuous support. :-)

  • Ulf Dittmer

    Ulf Dittmer - 2011-08-22

    It's possible JFreeChart has some facilities for doing this, but those would be geared towards desktop apps (via Swing). But JFC knows nothing about HTML image maps, that's all cewolf's doing. And no, I'm afraid I can't help - I've never touched the code that creates tooltips.

  • james

    james - 2011-08-27

    This clears up a lot of things for me. Thanks. :-)

    Do you know who is the author of the tooltips for cewolf? I'd truly appreciate if you could redirect me to the right direction again. 

    Please do let me know if I could also lend some hand in improving this very useful library. Thanks and best regards.

  • james

    james - 2011-09-01


    Another feature that might be useful is, the option to allow wafer map cell values to be displayed on the wafer map chart.

    I have modified the de.laures.cewolf.jfree.WaferMapPlot.java to enable the aforementioned feature. (Right now the cell values are always being displayed, we need to incorporate a flag that will help control the display behavior)

    Drilling down… the change was made on drawChipGrid() method. (I included comments to show where the modifications took place)

    Please let me know if you have any suggestions or any thoughts about the change. Thanks!

    * Calculates and draws the chip locations on the wafer.
    * @param g2  the graphics device.
    * @param plotArea  the plot area.
    protected void drawChipGrid(Graphics2D g2, Rectangle2D plotArea) {

        Shape savedClip = g2.getClip();
        Rectangle2D chip = new Rectangle2D.Double();
        int xchips = 35;
        int ychips = 20;
        double space = 1d;
        if (this.dataset != null) {
            xchips = this.dataset.getMaxChipX() + 2;
            ychips = this.dataset.getMaxChipY() + 2;
            space = this.dataset.getChipSpace();
        double startX = plotArea.getX();
        double startY = plotArea.getY();
        double chipWidth = 1d;
        double chipHeight = 1d;
        if (plotArea.getWidth() != plotArea.getHeight()) {
            double major = 0d;
            double minor = 0d;
            if (plotArea.getWidth() > plotArea.getHeight()) {
                major = plotArea.getWidth();
                minor = plotArea.getHeight();
            } else {
                major = plotArea.getHeight();
                minor = plotArea.getWidth();
            //set upperLeft point
            if (plotArea.getWidth() == minor) { // x is minor
                startY += (major - minor) / 2;
                chipWidth = (plotArea.getWidth() - (space * xchips - 1)) / xchips;
                chipHeight = (plotArea.getWidth() - (space * ychips - 1)) / ychips;
            } else { // y is minor
                startX += (major - minor) / 2;
                chipWidth = (plotArea.getHeight() - (space * xchips - 1)) / xchips;
                chipHeight = (plotArea.getHeight() - (space * ychips - 1)) / ychips;

        for (int x = 1; x <= xchips; x++) {
            double upperLeftX = (startX - chipWidth) + (chipWidth * x) + (space * (x - 1));
            for (int y = 1; y <= ychips; y++) {
                double upperLeftY = (startY - chipHeight) + (chipHeight * y)
                        + (space * (y - 1));
                chip.setFrame(upperLeftX, upperLeftY, chipWidth, chipHeight);

    // Start of modification //
                String chipValueString = new String(" ");

                Number chipValue = this.dataset.getChipValue(x - 1, ychips - y - 1);
                if (chipValue != null) {
                    chipValueString = String.valueOf(chipValue.intValue());


                Rectangle2D bounds = chip.getBounds2D();
                int fontSize = (int) (Math.floor(bounds.getHeight() / 2));
                Font font = new Font("SanSerif", Font.PLAIN, fontSize);
                FontRenderContext frc = g2.getFontRenderContext();
                TextLayout layout = new TextLayout(chipValueString, font, frc);

                Float xCoordinate = new Float(bounds.getMinX());
                Float yCoordinate = new Float(bounds.getMaxY());

                layout.draw(g2, xCoordinate, yCoordinate);
    // Start of modification //

  • Ulf Dittmer

    Ulf Dittmer - 2011-09-10

    I worked that feature into the latest release. It can be turned on in the WaferMapLegendProcessor.

  • james

    james - 2011-09-13

    Great! Thank you for adopting the change. I have also tested the released 1.1.10 jar on my local machine and it works well.

    If it is not that much of a bother, may I request the SVN source code to be updated as well for me to see/learn how you implemented the change. I'd appreciate it.

    BTW, another thing that I will be trying to integrate is the option to add tool tips to the wafer map cells that would show the x,y coordinates.

    Thank you once again! :-)

  • Ulf Dittmer

    Ulf Dittmer - 2011-09-13

    Oops, I had forgotten to check it in; it's there now.

1 2 > >> (Page 1 of 2)

Log in to post a comment.