B4J Library jCharts

Here's my first library for B4J. It's a wrapper of javafx.scene.chart with additional functions and classes.

jCharts.jpg
chart2.jpg


To take a snapshot of a chart, set its animated property to False before adding the data or wait until all animations are over.

Changelog:
v1.21:
- I added a workaround for a bug in OpenJDK 11 (thanks to Chris2)

v1.2:
- XAxis and YAxis created by the designer can now raise events with the default event prefix "XAxis" / "YAxis";
- I added the LegendChanged event to all charts;
- I fixed a bug (NullPointerException) in GetChildStyleMap and StyleMap.

v1.11:
- I added the SetChildStyleMap2 function;
- I modified the fourth demo to show a simple way to add the colored bands.

v1.1:
- I added the Plot event to all charts except PieChart;
- I added a demo to show how to use the Plot event (this project requires jGraphicLib);
- I modified the third demo to use a layout made with the designer.

v1.0:
- All charts can be added as custom views in the visual designer;
- I added the Width and Height properties to all charts and axis;
- I added the Series property to XYCoord;
- I added the MouseToData function to all charts and removed the EventPrefixForPlot parameter from Initialize (MouseToData is more convenient than events);
- I modified the second demo to show MouseToData in use;
- I modified the third demo so that the slider value sets the upper bound of the displayed series.

v0.9:
- I added ForceZeroInRange and TickUnit to NumberAxis;
- I added RemoveAllData to PieChart;
- I added FindNearestX to XYSeries;
- I added FindSeries and RemoveAllSeries to all charts using series;
- I added Padding to all charts;
- I added a new example and some documentation.
 

Attachments

  • jCharts_1_21.zip
    74.1 KB · Views: 936
Last edited:

Harris

Expert
Licensed User
Longtime User
Another question about formatting axes:

There are 3 possibilities (example):

a.) XAxisL.TickLabelFont=fx.DefaultFont(20) but not all properties available

b.) CSSUtils.SetStyleProperty(XAxisL,"-fx-tick-label-font-size","20px")

c.) Dim FirstLineStyle As Map = LineChartSensorData.GetChildStyleMap(".axis")
FirstLineStyle.Put("-fx-tick-label-font-size", "20px" )
LineChartSensorData.SetChildStyleMap(".axis", FirstLineStyle)

I wonder how to access some styles of the YAxisL (child axis-tick-mark)
e.g. axis-tick-mark fx-stroke-width

(XAxisL works see post #11, but how to access the YAxisL?)
Good question... I can't get the Y to format as well, try as I might.
 
Last edited:

Harris

Expert
Licensed User
Longtime User
I'm not sure of the meaning of the question because YAxisL is not different from XAxisL. You have an example in the first demo (I add "m" after the number).
Nice...

Now that I have gone this far, how difficult is it to make my project a web-app? Since I use ABM primarily (but Chartist lacks jCharts functionality), I would love to make this project a webapp.

Thanks
 

dk9uv

Member
Licensed User
Longtime User
I'm not sure of the meaning of the question because YAxisL is not different from XAxisL. You have an example in the first demo (I add "m" after the number).

I understand how to change the labels at the ticks.
But how to change the stroke-width of the tick lines?

E.g. in the graph in post #11 the tick lines of the xaxis are formatted with

Dim FirstLineStyle AsMap = LineChart.GetChildStyleMap(".axis-tick-mark")
FirstLineStyle.Put("-fx-stroke","black")
FirstLineStyle.Put("-fx-stroke-width","2")
LineChart.SetChildStyleMap(".axis-tick-mark", FirstLineStyle)

The tick lines of the yaxis are not formatted by this code as one can see in the graph.

I wonder how to access the yaxis, respectivley how to alter LineChart.GetChildStyleMap(".axis-tick-mark")
to access the yaxis?
 

Informatix

Expert
Licensed User
Longtime User
I understand how to change the labels at the ticks.
But how to change the stroke-width of the tick lines?

E.g. in the graph in post #11 the tick lines of the xaxis are formatted with

Dim FirstLineStyle AsMap = LineChart.GetChildStyleMap(".axis-tick-mark")
FirstLineStyle.Put("-fx-stroke","black")
FirstLineStyle.Put("-fx-stroke-width","2")
LineChart.SetChildStyleMap(".axis-tick-mark", FirstLineStyle)

The tick lines of the yaxis are not formatted by this code as one can see in the graph.

I wonder how to access the yaxis, respectivley how to alter LineChart.GetChildStyleMap(".axis-tick-mark")
to access the yaxis?
Ah OK. Indeed, I do not know how to change the width of tick lines for the Y axis. It seems there's no independent setting (".axis-tick-mark" should alter both axis) and I cannot say for now why the setting has no effect on the Y axis.
 

Harris

Expert
Licensed User
Longtime User
Skinning with CSS - using the file (caspian.css).

skin1.jpg


Attached is the zip containing the caspian.css file - used for JavaFX.
Place the css in your projects files folder and add it in the IDE under files tab.

Add this line after Mainform.show...
MainForm.Stylesheets.Add(File.GetUri(File.DirAssets, "caspian.css"))

Refer to this page for examples on styling using the css..
http://docs.oracle.com/javafx/2/css_tutorial/jfxpub-css_tutorial.htm

Now mod the css to get the desired effects you want without having to code it in your project.

B4X:
.chart-series-line {
    -fx-stroke: #f9d900;
    -fx-stroke-width: 1px;   /* changed line width from 5 to 1 px */
    /* -fx-effect: dropshadow( two-pass-box , rgba(0,0,0,0.3) , 8, 0.0 , 0 , 3 ); */
    /* I removed the drop shadow */
}
/*.default-color0.chart-line-symbol { -fx-background-color: #f9d900, white; }*/

/* changed symbol colors to match line colors that I wanted */

.default-color0.chart-line-symbol { -fx-background-color: black, white; }
.default-color1.chart-line-symbol { -fx-background-color: green, white; }
.default-color2.chart-line-symbol { -fx-background-color: blue, white; }
.default-color3.chart-line-symbol { -fx-background-color: #c62b00, white; }
.default-color4.chart-line-symbol { -fx-background-color: #2f357f, white; }
.default-color5.chart-line-symbol { -fx-background-color: #860061, white; }
.default-color6.chart-line-symbol { -fx-background-color: #c62b00, white; }
.default-color7.chart-line-symbol { -fx-background-color: #ff5700, white; }

/*.default-color0.chart-series-line { -fx-stroke: #f9d900; }*/

.default-color0.chart-series-line { -fx-stroke: black; }
.default-color1.chart-series-line { -fx-stroke: green; }
.default-color2.chart-series-line { -fx-stroke: blue; }
.default-color3.chart-series-line { -fx-stroke: #c62b00; }
.default-color4.chart-series-line { -fx-stroke: #2f357f; }
.default-color5.chart-series-line { -fx-stroke: #860061; }
.default-color6.chart-series-line { -fx-stroke: #c62b00; }
.default-color7.chart-series-line { -fx-stroke: #ff5700; }

With all this, still unable to set Y axis styling however...
 

Attachments

  • c90c03c645d18722ddb0-master.zip
    23.2 KB · Views: 516
Last edited:

dk9uv

Member
Licensed User
Longtime User
I think that's a bug in the JavaFX lib.

Problem solved.

I used

B4X:
MainForm.Stylesheets.Add(File.GetUri(File.DirAssets, "caspian.css"))

from post #26 and changed in the caspian.css the following section

B4X:
.axis-tick-mark {
  -fx-fill: null;
  -fx-stroke: #666666;
  -fx-stroke-width: 3;
}

Now the tick strokes at both axes are thicker.
 
Last edited:

dk9uv

Member
Licensed User
Longtime User
Question about removing and adding series:

I modified example 1 of the jcharts lib (from line 115)

B4X:
    LineChart.AddAllSeries(Array As XYSeries(Series1, Series2))
    LineChart.RemoveAllSeries
    LineChart.AddAllSeries(Array As XYSeries(Series1, Series2))

I thought that I could remove and again add a series but this throws the
exeception "duplicate series added". I wonder what I have done wrong or misunderstood.
 

Informatix

Expert
Licensed User
Longtime User
Question about removing and adding series:

I modified example 1 of the jcharts lib (from line 115)

B4X:
    LineChart.AddAllSeries(Array As XYSeries(Series1, Series2))
    LineChart.RemoveAllSeries
    LineChart.AddAllSeries(Array As XYSeries(Series1, Series2))

I thought that I could remove and again add a series but this throws the
exeception "duplicate series added". I wonder what I have done wrong or misunderstood.
EDIT: Changes cannot be instant when the chart is animated.
 

dk9uv

Member
Licensed User
Longtime User
EDIT: Changes cannot be instant when the chart is animated.
thank you, works perfect

B4X:
    LineChart.AddAllSeries(Array As XYSeries(Series1, Series2))
    LineChart.Animated=False
    LineChart.RemoveAllSeries
    LineChart.AddAllSeries(Array As XYSeries(Series1, Series2))   
    LineChart.Animated=True
 

Informatix

Expert
Licensed User
Longtime User
New version 1.1

The great feature added to the version 1.1 is the Plot event. This event is raised just after all series are plotted and allows to change what's plotted or add your own drawings (e.g. colored areas, line to show the average value, texts for minimum and maximum, etc.). I use it myself to break lines and creates gaps when pauses are detected in the data flow.

Changelog:
- I added the Plot event to all charts except PieChart;
- I added a demo to show how to use the Plot event (this project requires jGraphicLib);
- I modified the third demo to use a layout made with the designer.
 

Informatix

Expert
Licensed User
Longtime User
jCharts is not very fast and when you have to plot 20000 points, the waiting (for series creation + plotting) is too long for the average user, so I created a method to reduce the number of data to plot. It's really fast as data are processed before they are added to series. I run my code in a thread while I display a message above the chart but whatever amount of data I have, the waiting message is not displayed more than 1 or 2 seconds with this method.
The following code is mainly pseudocode because the real code is too specific to my application... and I'm too lazy to write a generic example ;). What it does is simple: it computes a size for sequences of data and splits the list of data to analyze each sequence. It keeps only the data that defines the range of the sample (the data with the maximum or the minimum value of the sample), and also the first and last data of the list.
The first function to call is TooMuchDataForScreen. If the result is True, you call Reduce_Data.
B4X:
Private Sub Compute_SequenceSize(Data As DataList) As Int
    Return Floor(2 * Data.Size / fx.PrimaryScreen.MaxX)
End Sub

Public Sub TooMuchDataForScreen(Data As DataList) As Boolean
    SequenceSize = Compute_SequenceSize(Data)
    Return (SequenceSize > 2)
End Sub

Public Sub Reduce_Data(Data As DataList) As DataList
    ReducedData.Initialize
    AnalyseAndSelect_Data(Data)
    Return ReducedData
End Sub

Private Sub AnalyseAndSelect_Data(Data As DataList)

'Do a loop here where you create a sample each time LoopIndex / SequenceSize = Floor(LoopIndex / SequenceSize).
'The sample is analyzed with a second loop that goes from the stored LoopIndex of the last sample +1 to the current LoopIndex.
'You keep only data with maximum and minimum.

End Sub

EDIT: I removed the advices that were specific to my app.
 
Last edited:

Harris

Expert
Licensed User
Longtime User
jCharts is not very fast and when you have to plot 20000 points
That's got me written all over it.

I parse my data for a day and break it out into 1 hour segments. Then you can page thru each hour (60 x 60 = 3600 data points - when each point is 1 second).
Loading the whole day at this rate is just overload. Your solution seems to address this. Nice...

I do the same with Google Charts in ABM (1 hour segments) . It is amazingly fast!
Your wrapper of jCharts and Google Charts are great additions - when and where you need to use them.

Google Charts is very easy to integrate into a webapp (ABM) - as I discovered.
 

Informatix

Expert
Licensed User
Longtime User
Loading the whole day at this rate is just overload. Your solution seems to address this. Nice...

To get the idea, let's consider a list with 20 values. Suppose that your screen is only 5 pixels wide. "Compute_SequenceSize" returns 8 (2*20/5). So each sequence has a size of 8 values.
The first value is always kept, so the first sequence goes from the index 1 to 8. The second sequence from 9 to 17. The third sequence from 18 to 18 (the last data, with index 19, is automatically kept so there's no need to include it in the last sequence).
For each sequence, the maximum and minimum of the sequence are kept, so you will get a total number of values at the end equal to 1 (first value) + 2 for each sequence + 1 (last value). As the last sequence (18 to 18) has only one value, the reduced size = 7 values. That's more than the screen size (5) but that's reduced enough to be a lot faster to display and looks visually very close to the original series.
If you want to zoom in on data, you apply again this method on the zoomed portion (taken out from the original series, not from the displayed series).

Google Charts are great additions
I'm not the wrapper of this library.

EDIT: I removed the advices that were specific to my app.
 
Last edited:

rbghongade

Active Member
Licensed User
Longtime User
Dear Informatix,
Is it possible to have a scrolling display with this library? If yes , can you please provide a simple example?
 

dk9uv

Member
Licensed User
Longtime User
There's no scrolling in the original library. You can simulate the scrolling by changing the bounds of axis but I don't think that it will be very smooth.
I use a range slider from the ControlsFX library and change the bounds of the axis. This works pretty smooth in my case.
 

alienhunter

Active Member
Licensed User
Longtime User
Hi
i have bar-chart and i want to color the second bar green
with the code below it just colors the first one red
i could not find how to colors the second one/third and so on
any hints ?
thanks



B4X:
          Dim Back As Map = BarChart.GetChildStyleMap(".default-color0.chart-bar")
            Back.Put("-fx-bar-fill", "red")
            Back.Put("-fx-bar-fill", "red")
            BarChart.SetChildStyleMap(".default-color0.chart-bar", Back)

barchart.jpg
 
Last edited:

alienhunter

Active Member
Licensed User
Longtime User
Hi
i have bar-chart and i want to color the second bar green
with the code below it just colors the first one red
i could not find how to colors the second one/third and so on
any hints ?
thanks



B4X:
          Dim Back As Map = BarChart.GetChildStyleMap(".default-color0.chart-bar")
            Back.Put("-fx-bar-fill", "red")
            Back.Put("-fx-bar-fill", "red")
            BarChart.SetChildStyleMap(".default-color0.chart-bar", Back)

View attachment 51344


got it
.data0.chart-bar
.data1.chart-bar
.data2.chart-bar
.....

B4X:
For i = 0 To 9           
            Dim Back As Map = BarChart.GetChildStyleMap(".data"& i &".chart-bar")
            Back.Put("-fx-bar-fill", "blue")
            BarChart.SetChildStyleMap(".data"& i &".chart-bar", Back)       
            Next
 
Top