Friday, January 12, 2018

Friday Fun LVII - Stream Charts

Aloha,

Here we go again...last week I stumbled upon a really nice charts that are inspired by Edward Tufte's Stream Charts. This is how they look like...



And here you can find more information about them.
The chart can be used to visualize a series of data with the variation of the data it contains over time. On each date different items of the series are stacked like in a stacked bar chart. The items are sorted by their value from bottom to top, meaning to say the items with the lowest value are always at the bottom and the one with the highest values are always on top.
To be honest I have again no use case for it but I really like the visualization. By choosing the colors wisely one could visualize dominating series over time very well.
Long story short...here is my implementation of such a chart...



As you can see I don't have such good data as in the example above but you get the idea :)

To create such a chart I make use of my ChartItem class which has a timestamp property that is needed here to group the chart items for the visualization. The idea is to have a list of ChartItems that may also contain multiple ChartItems from the same day. The StreamChart component has a category property which can be one of the following categories:

  • DAY
  • WEEK
  • MONTH
  • YEAR

So let's assume you have a list of ChartItems that contains data from different days and you would like to visualize the chart grouped by days you set the category to DAY.
With this feature you can define if you would like to group the given list of ChartItems by one of the above categories...hmm...hope that explanation was more or less clear :)

It might be easier to simply take a look at the source code (see links below).

In principle this chart is similar to the Sankey Plot but not exactly the same so I've started from there and created a modified version which you can see above. This chart is now part of my own JavaFX charts library which you can find here:

sources at github

binaries at bintray

Please find the demo classes for all the charts in the test package.

Well that's it for today...so keep coding...

Friday, January 5, 2018

Friday Fun LVI - Nested Bar Charts

Aloha and a happy new year,

Today I just have a short post about some nice little bar chart which I've found last week when looking for new ideas on the web. Here is the image I've stumbled upon...



I saw it and directly understood the idea behind it because it's like a compact view of two bar charts. The big bars in the background show the sum of all inner bars (like in a stacked bar chart) and the inner bars visualize the distribution of that sum into portions. If you want to know how to realize this kind of chart in Excel you should take a look at Jon Peltier's blog where this image was taken from.

To be honest the thing that got my attention are the colors he used for this chart because they directly reminded me on the Material Design colors
And because I once implemented these colors in JavaFX I gave it a try.
Well I was surprised how easy it was to implement and finished the whole thing within 1.5h and here is a little screenshot of the result...



As you can see this kind of chart works really well with the Material Design colors. So it does not make sense to use it for everything but there might be some use cases where saves a lot of space and still transfers the information.

Because I will add this chart to my JavaFX charts library anyway I did not spend more time on implementing axis and labels but I only implemented a mouse event handler. Meaning to say if you click on an element the component will fire an event that contains the data of the selected series (the big bar) and if you've clicked on one of the inner bars it will also contain the data of the selected item.
Using this event I've implemented a simple popup that will show the selected data.

This kind of chart can for example be used to compare sales data of products per quarter or similar things, you will find something ;)

As always the source is available over at github so enjoy playing around with it.

That's it for today...I wish you a codeful year 2018...keep coding...

Friday, December 29, 2017

Friday Fun LV - Florence Nightingale inspired Coxcomb Chart

Aloha,

For the last Friday in 2017 I have another friday fun component for you. It's a variation of a donut chart where the segment width varies with the value. To give you an idea what this chart looks like here is a little picture that I've found on the web...



In principle this chart is not really fancy but the one thing that caught my attention are the shadows that are only visible on the lower elements, meaning to say they are not besides the segment. In JavaFX we have effects like drop shadows directly build in but they won't work here because if you would use a simple drop shadow on each segment you would get something like follows...


So we now have the drop shadows but not only on the lower segments but all around each segment which is not the same. One trick could be to use clipping for which you have to clip each segment with a path.
Well to be honest I was to lazy and decided to go another way. In principle you could imitate a drop shadow by using a linear gradient. This works but is not easy to achieve. So what I did was to add another segment at the end of each segment which I stroke with a linear gradient that goes from gray to transparent. To give it a little bit more realistic look I've also added a gaussian blur. So my result looks as follows...


To be honest I'm not really satisfied with the result because the shadow still looks not realistic enough but hey...for an early morning hack it's good enough ;)

UPDATE:
Well what I should I say...this shadow problem nagged me last night so I reworked my implementation and now I make use of the inbuild DropShadow effect in combination with clipping. On the following picture you can see the LinearGradient based approach (left) compared to the DropShadow approach (right)...




To make the effect more visible I've set the drop shadow color to opaque black on the right side and now the shadows look more natural...at least to me ;)
For the new approach I've added an additional path at the end of each segment and adjusted the shadow offset in x- and y-direction for each segment.
This worked nicely except the fact that the shadow also showed up outside of the segment.
Well a picture is better than thousand words, so on the following picture I've used plain red for the drop shadow color and here you can see what I'm talking about...



To avoid this problem I simply clip each segment with a circle that has the same radius and by using this little clipping trick the result looks like follows (with black as shadow color again)...



And now it looks exactly as I would like to see it :)
To use the clipping in JavaFX Canvas (or HTML5 Canvas) you have to define a path that will be used for the clipping and call clip() before you draw the elements that you would like to clip. The next thing you need to keep in mind is that once the clipping path is set it will affect all operations defined here.
In my case the problem is that the radius of the segments will increase so the clipping path also has to "grow". The canvas has a nice feature which makes it possible to save and restore it's state. Meaning to say before I set the clipping path I save the canvas by calling the save() method on the GraphicsContext and after I've finished the segment I reset the canvas to the saved state by calling the restore() method on the GraphicsContext. The nice thing is that you can save/restore the canvas as often as you like...but you have to keep track of it.

As a little advice let me tell you that if you use save/restore more than once it makes sense to either add some comments to each save/restore statement so that you know for which operation you save/restore or you also simply intend your code after each save statement to visualize the saved code blocks.

But now back to the chart...
For my implementation of the coxcomb chart the values of each segment are not related to the segment radius and therefor it only makes sense if you sort the items in the list.
For this reason I've added two convenience methods to sort the chart either ascending or descending where ascending would look like this...


Well I like the descending version more but this is personal taste.
I did not add a legend to the chart because I think this could be a separate control to be more flexible. I've created a simple item class that has properties for value, name and color.
To create the chart above you simply need the following code...


Item[] items = {
    new Item(27, Color.web("#96AA3B")),
    new Item(24, Color.web("#29A783")),
    new Item(16, Color.web("#098AA9")),
    new Item(15, Color.web("#62386F")),
    new Item(13, Color.web("#89447B")),
    new Item(5, Color.web("#EF5780"))
};
CoxcombChart chart = new CoxcombChart(items);

I'm always impressed how easy it is to create stuff like this in JavaFX, creating the control and writing this blog post tooks me only 2.5h which is one of the reasons why I love coding in JavaFX, the time from the first idea to some running code is really short and with this the productivity is really high and the code for the control is just around 280 330 (I've added 2 properties with their getters and setters) lines incl. import statements, license etc. Long story short...I ❤️ it :)

Oh and if you are interested in the code you can find it as always on github.

This chart is very specific and does not work for everything but it could be quite useful for some special use cases and to be honest it simply looks nice :)

So I guess that's it for 2017, now I wish all of you a happy new year and...keep coding...

Friday, December 15, 2017

Friday Fun LIV - Path Gradient

Aloha,

I've always thought about how to implement a path gradient. Meaning to say a gradient that follows a path. First of all keep in mind that this kind of gradient is not used very often but sometimes it can create some really nice effects.
I've mainly saw the effect in circular components like the fitness gauge on the Apple Watch...


The color of each bar changes along the bar as you can see on the image. For this specific problem I've created the ConicalGradient in the past which works nicely for circular components but what about this...



If you would like to fill the path above with a gradient from blue over green and yellow to red you will see that it won't work with linear gradients. You can either fill it horizontally or vertically but both times the gradient won't follow the path itself. So here are two examples...


To fill it with a gradient along the path you need to split the path into small segments and fill each segment with a linear gradient along the line.
If you go with this approach you can achieve something like follows...


As you can see here it works nicely but that was not that easy to realize. The most important part of this little fun project was taking a closer look to the goodies that are already in the JDK. Especially the Java2D package contains a lot of nice stuff.
So my idea was to use this kind of path gradient in the JavaFX canvas node and lucky me the Java2D api is quite close to the JavaFX canvas api.
I won't go through the code because it's simply to much but let me explain the steps that are needed to achieve that result...

  • Split the path into it's elements (MoveTo, LineTo, QuadCurveTo, BezierCurveTo, Close etc.)
  • Split each element into single lines
  • Stroke each single line with the right part of the complete gradient
Like already mentioned above a lot of the functionality is already in the JDK but unfortunately it sometimes is hidden in private classes that are not accessible from the outside. So the solution for this problem was to fork all parts that I needed from the Apache Harmony project (the stuff Android is based on). So in principle I've forked the all classes from the Java2D packages that are related to bounds, shapes and transforms.
In the classes above I've removed all 3D related things and completely switched to doubles instead of floats.
I've also added several other classes and added functionality to some of the classes. One problem was for example that in the JDK there was no code to split lines into "sub-lines" which means I had to add this kind of things.
I've also renamed some classes to be more compatible to the JavaFX canvas. So the CubicCurve now is a BezierCurve etc.
In the end I've needed a path class that holds all elements and a lookup mechanism for the gradient.
Long story short with my current implementation the code to produce the path gradient will look like follows...


GradientLookup gradientLookup = new GradientLookup();
gradientLookup.setStops(new Stop(0.0, Color.BLUE),
                        new Stop(0.25, Color.LIME),
                        new Stop(0.5, Color.YELLOW),
                        new Stop(0.75, Color.ORANGE),
                        new Stop(1.0, Color.RED));

Path path = new Path();
path.moveTo(91, 36);
path.lineTo(182, 124);
path.bezierCurveTo(248, 191, 92, 214, 92, 214);
path.bezierCurveTo(-26, 248, 200, 323, 200, 323);
path.bezierCurveTo(303, 355, 383, 141, 383, 141);


double lineWidth = 20;


Canvas            canvas = new Canvas(400, 400);
GraphicsContext2D ctx    = canvas.getGraphicsContext2D();
PathGradient.strokePathWithGradient(ctx, path, gradientLookup, lineWidth, StrokeLineCap.ROUND);


So as you can see I've tried to keep the api as close to the JavaFX canvas api as possible but instead of drawing the path directly on the canvas context you first create the path object, define a gradient lookup which contains the list of stops and colors you need for the gradient and define width for the stroked line.

That's already neat but it could even be better because in the Path class you will find a SVGParser and with this you can directly use a SVG path string from an SVG file.
As an example here is the SVG file of the path on the above image...


<?xml version="1.0" standalone="no"?>

<!-- Generator: Adobe Fireworks CS6, Export SVG Extension by Aaron Beall (http://fireworks.abeall.com) . Version: 0.6.1  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg id="Untitled-Page%201" viewBox="0 0 500 500" style="background-color:#ffffff00" 
    version="1.1"xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
    x="0px" y="0px" width="500px" height="500px">
    <path d="M 91 36 L 182 124 C 248 191 92 214 92 214 C -26 248 200 323 200 323 C 303 355 383 141 383 141 " stroke="#000000" stroke-width="1" fill="none"/>
</svg>


And with the the mentioned parser the code above could also be written like follows...

Path path = new Path();
path.appendSVGPath("M 91 36 L 182 124 C 248 191 92 214 92 214 " +
                   "C -26 248 200 323 200 323 C 303 355 383 141 383 141");

double lineWidth = 20;

Canvas canvas       = new Canvas(400, 400);
GraphicsContext ctx = canvas.getGraphicsContext2D();

PathGradient.strokePathWithGradient(ctx, path, gradientLookup, lineWidth, StrokeLineCap.ROUND);

To me that looks quite ok :)
As always I do not really have any use case yet so the whole thing is not tested for all possible use cases but at least it will give you an idea what is possible :)

And also as always the code is available on github.

Well that's it for today...I hope it was somehow interesting...keep coding... :)

Wednesday, December 6, 2017

William Playfair inspired charts...

Aloha,

Today I just would like to share a little blogpost about a chart that I've implemented last Friday evening. The chart design is inspired by William Playfair who invented this kind of chart to visualize economic data like import and export of theUS in relation to other countries.
One of his charts looks like follows...

The idea is pretty simple, take two line charts and fill the area between the two charts with a color. The color depends on which line is on top. With this technique one can visualize for example gain and loss of processes etc.
Like mentioned the idea is simple but the realization is not as trivial as it looks. The problem here is that you have two separate line charts that you have to combine to not only one polygon but to multiple polygons.
So every time the two lines cross each other one has to fill the area before the intersection point with one color and the area after the intersection point with the other color.
After thinking about the chart for a bit I've got an idea on how to realize that behavior and here is one result...


As always I do not really have a use case for that chart but I can imagine that it might be useful for someone out there :)

So if you would like to play around with it, feel free to check out the code at github.

I hope to find some time within the next days to add some interactivity to the chart...so stay tuned :)

Well...I guess that's it for today...so keep coding... :)

Friday, December 1, 2017

Friday Fun LIII - Sankey Plots

Aloha everyone,

Creating charts is really fun...again Thomas Nield(@thomasnield9272) pointed me to a nice chart which is called Sankey chart and again I could not withstand to try my best to implement it in JavaFX.
To give you an idea on what I'm talking about here is an example of such a Sankey plot...


Compared to last weeks Circular plots these plots can be multilevel and after searching the web for some hours I figured out that you can find all sorts of Sankey plots which might look completely different...here another example...


That doesn't make it easier to implement such a chart and so I've started reading about the history of that chart. In the end it turned out that the main purpose of this kind of chart is the visualization of flows where the width of the arrows/lines is shown proportionally to the flow quantity.
So I had to make a decision which style I should follow and I've decided to go with the first visualization of the above pictures.
Lucky me there is also a version of the Sankey plots in the Google charts which I took as a template.
Here is a screenshot of what I've come with...


This is the more colorful version of the chart but it is also possible to create other versions as you can see here...


In this version I've used different parameters for the width of the items and here also the direction of the flow is indicated by arrows (but I only support one direction anyway).

To get nice results you have to keep in mind that in my implementation you have to think about how to order the items in the chart when adding it to the control.
Meaning to say I do not have some hyper smart algorithm that do some fancy automatic sorting of items but you have to use your own brain and think about the chart before you create it. For the example above I've added the items exactly in the order as they appear on the chart which would look like follows...

// Setup chart itemsPlotItem brazil      = new PlotItem("Brazil", Colors.LIGHT_BLUE.get());
PlotItem mexico      = new PlotItem("Mexico", Colors.ORANGE.get());
PlotItem usa         = new PlotItem("USA", Colors.ORANGE.get());
PlotItem canada      = new PlotItem("Canada", Colors.LIGHT_RED.get());

PlotItem germany     = new PlotItem("Germany", Color.web("#FF48C6"));

PlotItem portugal    = new PlotItem("Portugal", Colors.LIGHT_BLUE.get());
PlotItem spain       = new PlotItem("Spain", Colors.LIGHT_GREEN.get());
PlotItem england     = new PlotItem("England", Colors.LIGHT_RED.get());
PlotItem france      = new PlotItem("France", Colors.LIGHT_GREEN.get());

PlotItem southAfrica = new PlotItem("South Africa", Colors.YELLOW.get());
PlotItem angola      = new PlotItem("Angola", Colors.PURPLE.get());
PlotItem morocco     = new PlotItem("Morocco", Colors.YELLOW.get());
PlotItem senegal     = new PlotItem("Senegal", Colors.PURPLE.get());
PlotItem mali        = new PlotItem("Mali", Colors.BLUE.get());

PlotItem china       = new PlotItem("China", Colors.BLUE.get());
PlotItem japan       = new PlotItem("Japan", Colors.GREEN.get());
PlotItem india       = new PlotItem("India", Colors.GREEN.get());

After that is done you have to define the connections between the items by defining only the outgoing streams for each item. Because that's a lot for the chart above I will only show you the ones for the first column which will look as follows...

// Setup flowsbrazil.addToOutgoing(portugal, 5);
brazil.addToOutgoing(france, 1);
brazil.addToOutgoing(spain, 1);
brazil.addToOutgoing(england, 1);
canada.addToOutgoing(portugal, 1);
canada.addToOutgoing(france, 5);
canada.addToOutgoing(england, 1);
mexico.addToOutgoing(portugal, 1);
mexico.addToOutgoing(france, 1);
mexico.addToOutgoing(spain, 5);
mexico.addToOutgoing(england, 1);
usa.addToOutgoing(portugal, 1);
usa.addToOutgoing(france, 1);
usa.addToOutgoing(spain, 1);
usa.addToOutgoing(england, 5);

As mentioned you define the streams that goes from each item to other items with their values.
After that is done you can setup the chart using the SankeyPlotBuilder as follows...

SankeyPlot sankeyPlot = SankeyPlotBuilder.create()
                                         .prefSize(600, 400)
                                         .items(brazil, mexico, usa, canada,germany,
                                                portugal, spain, england, france,
                                                southAfrica, angola, morocco, 
                                                senegal, mali, china, japan, india)
                                         .build();

And that's all it takes to create such a chart. Because the chart is again based on the JavaFX Canvas node there is no interactivity at the moment but I'm already working on a little project that will make it possible to have interactivity in the future...so stay tuned :)

Of course the code is available on github as always.

That's it for today...so keep coding...

Friday, November 24, 2017

Friday Fun LII - Circular Plots

Aloha,

Slowly getting into the charting business ;)
After Thomas Nield (@thomasnield9272) pointed me to so called Circular Plots I've couldn't hold back. If you know these charts you might understand why I was so keen on creating such a chart. 
So to give you an example here is an image of such a chart...




To be honest when I first saw the plot I was fascinated even without knowing how to read it and without knowing what this chart is good for. But after I took a look at more and more of those charts I got an idea on how to use them.
So I'm not a data scientist which is the reason why I've implemented it in a way that seemed logical for me.
The biggest problem was to find some data that I could use for the visualization. So in the end I've decided to take the public available data from the current parliamentary election in Germany.
To give you an idea what my chart is visualizing I think I need to explain it a bit. Each section on the chart shows one party with it's name, color and the voting result related to the number of eligible voters (61.5 Million).
Because there was a new party this year it was interesting to see where did the voters came from, so my chart visualizes the migration from all parties to other parties. The bigger the arrow the more voters migrated from the party to another.
So here is my chart...


So in the chart one can see that most of the AfD voters came from the Union party, the so called Non-Voters ("Nichwaehler") and others.
I've also created another chart that shows fictive data about travellers that travel between some asian countries. As always I do not have any use case for this chart and cannot guarantee that it is useful for real data analysis but at least it works for me and was fun to create. So here is the other chart...


At the moment there is not interactivity in this chart but if I will find some time I will definitely add it.

As always you can find the code on github.

That's it for today...enjoy the upcoming weekend and...keep coding ;)