Friday, December 3, 2021

All things countries...

Aloha,

As some of you might know I've created a JavaFX world map component a while back which I also integrated in my TilesFX and charts library.

Well the component itself works so far but it was always only a world map. I mean it is possible to strip out single countries and draw them but then you have the problem that this country map won't come with the same features as the world map.

So in principle I was always looking for something similar to Googles GeoChart. Well...long story short...I've created something similar :)

And I simply named it countries...because it is all about countries. It is another JavaFX library and it comes with 3 JavaFX controls:

- CountryPane

- RegionPane

- WorldPane

Each of those panes has more or less the same functionality. They show at least 1 country (CountryPane), a set of countries (RegionPane) or the whole world (WorldPane).

The WorldPane and the RegionPane in addition have the ability to select countries by clicking on them.

All 3 panes can overlay a heatmap and also so called connections (e.g. flight connections between airports).

In addition to the countries with their shapes the library also contains around 41000 cities with information about their population (if available), location, country and if it is a capital (if available). In addition I've also added around 8500 airports that you can use.

Countries can have value objects (metadata if you like) and can also have simple values, you can color them as you like. I hope I have build in enough capabilities to use for data visualization (if you miss something...just let me know).

Yep this is great...but it comes with lots of data...so the library is 13 MB in size!!!

But to be honest I don't care, it is just handy if you can directly make use of this data without loading other external data. Of course you can use your own data if you like, as long as you have latitude/longitude information it will work.

The library is build on JDK17, meaning to say if you would like to use it...move your stuff to JDK17 ;)

To give you an idea how it could be used, here are some screenshots...

This is the CountryPane showing Germany with some cities (population > 300000). To make it easier I simply added the same cities as heatmapSpots. In addition you see a connection between the FMO airport and the MUC airport.


Here you see the RegionPane showing the European Union. In this map I show the available capitals (cyan dots) and used cities with a population > 200000 for the heatmap. In addition I here show 3 connections between some airports (LIS -> ARN, MAD -> ARN, FMO -> ARN). I already added some predefined country regions in the BusinessRegion class. There you will find regions like DACH, EMEA, APAC, AMERICAS, CENTRAL_ASIA, NORTHERN_AMERICA etc. You can define your own regions by using the CountryRegion class.



And finally the WorldPane which again shows the available capitals (cyan spots), cities with a population > 1000000 for the heatmap and again some connections between international airports.

Not sure if this might be interesting for you but I needed it :)

As always the source is available over at github where you can also find the latest release. And of course it is also availble on maven central.

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


Tuesday, November 23, 2021

TilesFX 17.0.11

Aloha,

when working with dashboard using my TilesFX library I came across some missing things...first of all I needed a Tile that simply has a text in the center of it. Well nothing easier than that...I simply added a CenterTextTileSkin class that offers exactly this functionality. Here is a little screenshot that shows it in action...


As you can see I needed it to visualize the state of a server. If the server goes down the text will change from "ONLINE" to "OFFLINE" and the background color of the tile will change from green to red...very simple but very effective :)

To change the text you have to set the description of the tile.

Here is the code to create the tile above:

Tile serverTile = TileBuilder.create()
.skinType(SkinType.CENTER_TEXT)
.title("Server")
.text("Last check")
.backgroundColor(Dark.GREEN)
.description("ONLINE")
.build();

The other thing I stumbled upon was the fact that handling big numbers in a dashboard can really suck. When you have a dashboard with lots of tiles, there is sometimes simply not enough space to show those big numbers.

So the idea again is simple...just shorten the big numbers to a more readable format. For example 2350 can become 2.3k and 1230401 can become 1.2M. With this you can also show big numbers in a small tile.

The feature to use here is the property shortenNumbers in Tile. I've added it for some tiles where I thought it might come in handy but there might still be places where it is missing...so if you find a place where it could make sense, please file an issue over at github

You could also use the method Helper.shortenNumber(final long value) to shorten the numbers on your own before you set it somewhere. The method will return the formatted number as a String.

The result of using the shortenNumber property in Tile can be seen in the left Tile on image above.

Those new features can be found in the latest version of TilesFX which is 17.0.11 and which is available on github and also on Maven central.

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


Tuesday, November 16, 2021

Panel Barchart

 Aloha,

I'm currently working on a dashboard where I needed a way to visualize data in a specific way. Let's say we would like to compare the load of 3 servers for each day of a week. And in addition we would like to be able to compare the current week with the last week.

There are probably different ways how you can visualize this and I decided to go with a so called Panel Barchart.

Here is an example of such a chart:


In principle this is some kind of a rotated stacked bar chart where the segments are separated from each other. So my version looks a bit different but you will see it's similar, here you go:


So in the upper chart you see the server load of our 3 servers for this week (of course the numbers don't make sense and are random but you get the idea).

You need to define categories (here it's the days of the week). Now you need to add a series of chart items for each category and each server.

In upper chart eh bars are colored by the categories (workdays = gray, weekend = red). This colors can be defined in the categories. 

If you switch this feature off (colorByCategory = false [default]) it will use the colors of the items in each series.

The chart will show the name of the series on the far left column and the sum of each series on the far right column.

On top of each category column it will show the sum per category (in this case per day). On the upper right corner it will show the overall sum of all values.

Well that's good but sometimes you would like to compare the current values with values from another point in time e.g. last week or last year.

To make this possible you can switch enableComparison to true and as you might already thought you need to define the data of the things you would like to compare.

To be able to compare data you need the exact same number of series in the listOfSeries and the comparisonListOfSeries. In addition the items in the each lisOfSeries need to use the same categories that you use in the comparisonListOfSeries.

When you fullfill these requirements the chart will now show name and the comparisonName in the upper left corner (yes you can set the colors for both of them separately). Now you will also see the items for both series of data and if you like you can also define the colors for the series sums and the category sums separately.

The chart is interactive in the way that you can click on each item and a little popup will show you some text and the value of the item. The text that will be shown in the popup could either be the name of the item or the description of the item. If you set both (name and description) it will take the description.

You can find the code for the example above in the PanelBarChartTest class in the test package of the current jdk17 branch of my charts library.

The latest release is available on github (at the moment it is 17.0.11) and also on maven central.

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


Monday, September 20, 2021

Mission Timer X

Aloha,

Last week I've watched the live stream of SpaceX Mission "Inspiration4". When following the countdown on the screen I saw a nice control on the bottom of the screen...a mission timer. Well my very first Swing control I've created was the mission timer of the Apollo missions. As you can see I always was fascinated by those things... :)

So here is the screenshot I took:


The thing I really liked is the idea of having a circle where the upcoming events moving around. Very nice design. Of course there are details like colors, dots within the event circles etc. So I just had this screenshot and tried to re-create this control in JavaFX.

First thing to do (as always)...create a good vector drawing of the control.

So here you go:


My version also supports days which is the reason why I have the format in the way you see it on the image above. Another thing which I might improve is the changing colors of the items. In my version the color depends on the angle of the item on the circle but I think fading the item color might be better...we will see, maybe I will add this later on.

Also the font is not really the same as the one used by SpaceX. I've tried to find an appropriate one and decided to use the one in the image above.

The intersting thing about this control is that the width of the control is the only thing I used to do all the calculations. This was needed to make sure the aspect ratio of the control is always the same.

The MissionTimerX control also fires events of the type MissionTimerXEvent.PROCESSED. These events will be fired once an item reaches the center of the control which means it happens :)

Here is a little gif that shows the control in action...


And as always the code is available over at github.

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


Wednesday, July 7, 2021

SpinnerTileSkin

 Aloha,

I finally found some time to continue working on TilesFX. There was an issue in the TilesFX repo over at github that I would like to do for a long time but never really found the time.

So I now added a new skin called SpinnerTileSkin which is based on this issue/request. It does not look exactly like the requested one but I think it's close enough.

In principle the skin shows a numerical value that when changed will spin through the numbers from 0-9 as if they where on a wheel.

Because a screenshot won't really show the effect, here is a little video:


As you can see it is nothing really special but sometimes it might be exactly what you need.

To set it up you simple need the following code:

Tile tile = TileBuilder.create()
.skinType(SkinType.SPINNER)
.prefSize(300, 300)
.title("SpinnerTile")
.minValue(-50)
.maxValue(50)
.value(0)
.decimals(2)
.text("Animated number spinner")
.animated(false)
.build();
tile.currentValueProperty().addListener((o, ov, nv) -> {
if (nv.doubleValue() < 0) {
tile.setValueColor(Tile.RED);
} else {
tile.setValueColor(Tile.FOREGROUND);
}
});


Switching the color from white to red in case the number is negative is done by the listener attached to the currentValueProperty of the tile and is not the standard behavior.

Because I'm preparing my libraries for the upcoming JDK17 LTS release, this skin can only be found in the JDK16 branch of TilesFX. Not sure if I will backport it to the JDK11 master branch.

At the moment the JDK16 branch is not available on Maven Central but I will probably create a release in the coming days...so stay tuned...and keep coding :)


Friday, July 2, 2021

BubbleGridChart

 Aloha,

Last week I was playing around with some data and could not find the right chart to visualize it.

To give you an idea about the data, let's take the harvest of some fruits as an example. You will have ripe and unripe fruits, fruits that have been eaten by birds or caterpillars. Some of them might have been damaged by hail or did not get enough water, others might be rotten or mouldy. For each fruit you have those different numbers and you have the sum of each fruit and the sum of all fruits.

The best way to compare all those numbers would be a matrix style chart. So I've stumbled upon the so called Bubble Grid Chart. So here is an example that I've found on the web:

As you can see it shows the fruit data that I described above.

The value of each crosspoint e.g. 90 Apples that are ripe will be visualized by the size of the bubble. Sizing the bubbles is a bit tricky because you would like to avoid having a few big bubbles and a lot of tiny bubbles. So you need to make sure that the size of the bubbles has no linear relationship to it's value.

In addition the max size of a bubble is given by either the height of the y-category items or the width of the x-category items, depends on which is smaller.

I also would like to have a grid in the background to make it easier to find specific coordinates. So, long story short, here is my version of the BubbleGridChart:


As you can see I've decided to put the x-category items on the bottom and also added the ability to show not only the values on the bubbles but also on the rows and columns of the chart. I really was impressed on how much information you can get out of one chart. At a glance you can see that the number of all ripe fruits is 215 which is 43% of all fruits. Because in this example the number of each fruit was always 100 you cannot really compare by the x-category but this could be different.

You can see that 90 Apples have been ripe which is 18% of all fruits. This information will be shown in a little info that will popup when you click on the bubble. In addition I've added the ability to sort the chart in x- and y-direction by either their indices or their values.

To be able to sort the items by their index you have to define it upfront.

Let me show you how to set up the x- and y-category items for the chart above.

Y-Category Items:

ChartItem ripe = ChartItemBuilder.create().name("Ripe").index(0).fill(Color.BLUE).build();

ChartItem unripe = ChartItemBuilder.create().name("Unripe").index(0).fill(Color.RED).build();

X-Category Items:

ChartItem peaches = ChartItemBuilder.create().name("Peaches").index(0).fill(Color.ORANGERED).build();

ChartItem apples = ChartItemBuilder.create().name("Apples").index(1).fill(Color.LIMEGREEN).build();

BubbleChart Items:

BubbleGridChartItem peaches1 = BubbleGridChartBuilder.create().categoryXItem(peaches).categoryYItem(ripe).value(60).fill(Color.ORANGERED).build();

BubbleGridChartItem peaches2 = BubbleGridChartBuilder.create().categoryXItem(peaches).categoryYItem(unripe).value(5).fill(Color.ORANGERED).build();

BubbleGridChartItem apples1 = BubbleGridChartBuilder.create().categoryXItem(apples).categoryYItem(ripe).value(90).fill(Color.LIMEGREEN).build();

BubbleGridChartItem apples2 = BubbleGridChartBuilder.create().categoryXItem(apples).categoryYItem(ripe).value(0).fill(Color.LIMEGREEN).build();

The index that you define will later be used to sort the items, just make sure you don't have duplicate indices because I do not check that at the moment (I just needed something that works quickly). So you first create the x- and y-category items and from those you create the actual BubbleGridChart items that will be used to visualize the chart.

The BubbleGridChart itself can be create as follows:

BubbleGridChart bubbleGridChart = 
    BubbleGridChartBuidler.create()
                          .chartBackground(Color.web("#0e0e0e"))
                          .textColor(Color.WHITE)
                          .gridColor(Color.rgb(255, 255, 255, 0.1))
                          .showGrid(true)
                          .showValues(true)
                          .showPercentage(true)
                          .items(bubbleGridChartItems)
                          .sortXCategoryItemsByIndexAscending()
                          .sortYCategoryItemsByIndexDescending()
                          .useXCategoryFill()
                          .useGradientFill(false)
                          .gradient(new LinearGradient(0, 0, 1, 0, true
                                    CycleMethod.NO_CYCLE
                                    new Stop(0, Color.BLUE), 
                                    new Stop(1, Color.RED))
                          .build();

Sorting the categories via the build only works if you also provide the items, otherwise you have to call the sorting methods like sortXCategoryItemsByIndexAscending() after you have added the bubbleGridChartItems. For me the charts now works fine but you might have other requirements, so please do not hesitate to file issues/request over at github.

The BubbleGridChart can be find in the current jdk16 branch which is also available on maven central. The jdk16 branch is more a temporary branch that I use to test stuff before JDK17 will come out in September. Because this will be the next long term stable version I will create a jdk17 branch in the future which will become the new main branch then.

That's it for today, so enjoy the upcoming weekend and...keep coding... :)

Wednesday, June 16, 2021

Fun Selector

 Aloha,

Time flies, it's already mid of June so it's time for another little blogpost about a fun control I've created last week.

It's a selector between two states and the fun is the animation when switching between the two states.

Here is a little demonstration of the control...


So the light green ball defines the selected state. It's not really something special but I like the idea of using animations in a fun way. Always keep in mind that such effects are nice in tools that you use once or twice but you don't want to use these things in a business app every day :)

As always the code is available over at github.

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