B4J Library [B4X] [XUI] xChart Class and b4xlib

Peter Meares

Member
Licensed User
Longtime User
Klaus, a great project.
I was playing with drawing a simple popup Barchart and if one sets the DrawOuterFrame as a basic setting at the start of a project it crashes due to the DrawChart command in xChart line 2235.
Commenting the line out solves the issue. It fails due to having no data to draw.
I preferred to set everything up and then call DrawChart.

B4X:
Public Sub setDrawOuterFrame (DrawOuterFrame As Boolean)
    Graph.DrawOuterFrame = DrawOuterFrame
    DrawChart
End Sub
[\code]
 

Peter Meares

Member
Licensed User
Longtime User
Another possible glitch. I suspect this is common on all chart types, but I have only explored the Bar chart.
If I draw a bar chart with one line, it does not draw a legend. IncludeLegend set to say "BOTTOM".
This is due to Items.Size > 1, which should be Items.Size >= 1 or > 0.
Lines 1401 in the xChart.bas

B4X:
    If Legend.IncludeLegend <> "NONE" And Items.Size > 1 Then
        DrawLegend
    End If
[\code]
 

Tayfur

Well-Known Member
Licensed User
Longtime User
Hello @klaus ;
Thanks for very good class.

I used your class for my project.
But. A Value line is not show or mix with bottom grid line. I cant see red line on 54.8
Max(blue) line = upper limits
Min(red) line = lower limits
Olculen(yellow ) line = random values


is it a bug or I forgot a parameter?





B4X:
Private Sub CreateLineChart1Data
    ' Initialize the line data
    LineChart1.ClearData
  
    LineChart1.Title = "Three graphs"
    LineChart1.XAxisName = "Year"
    LineChart1.YAxisName = "Values"
'    LineChart1.YAxisName = ""
'    LineChart1.IncludeLegend = False
    LineChart1.YScaleMaxValue = 100
    LineChart1.YScaleMinValue = -100
    LineChart1.IncludeLegend = "BOTTOM"
    LineChart1.AutomaticScale = True
    LineChart1.YZeroAxis=False
    LineChart1.XScaleTextOrientation = "VERTICAL"
'    LineChart1.XScaleTextOrientation = "45 DEGREES"
    LineChart1.AddLine("max", xui.Color_Blue) '0 = random color
    LineChart1.AddLine("min", xui.Color_Red)
    LineChart1.AddLine("Olculen", xui.Color_Yellow)
  
    ' Add the line points.
   ' this is max values (Blue)
    Dim mx As List= Array As Double(55.20,55.20,55.20,55.20,55.20,55.20,55.20,55.20,55.20,55.20)
   ' this is min values (Red)
    Dim mn As List= Array As Double(54.80,54.80,54.80,54.80,54.80,54.80,54.80,54.80,54.80,54.80)
   ' this is random values (yellow)
    Dim vl As List= Array As Double(55.05,55,55.11,55.12,55,55.05,55.11,54.91,55.03,54.88)
  
  
  
    For i = 0 To mx.Size-1
  
        LineChart1.AddLineMultiplePoints(2005+i, Array As Double(mx.Get(i),mn.Get(i),vl.Get(i)),True)
        Next
    LineChart1.DrawChart
End Sub
 

klaus

Expert
Licensed User
Longtime User
This is because at the end of drawing the lines I redraw the frame.
If you comment the line below in the DrawLines routine in the xChart module, the red line will be visible.
1164 xcvsGraph.DrawRect(Graph.Rect, Graph.GridFrameColor, False, 2dip)
 

Tayfur

Well-Known Member
Licensed User
Longtime User
This is because at the end of drawing the lines I redraw the frame.
If you comment the line below in the DrawLines routine in the xChart module, the red line will be visible.
1164 xcvsGraph.DrawRect(Graph.Rect, Graph.GridFrameColor, False, 2dip)

thank you for feedback @klaus

My sample ; it has same "Y-axis-min value" and "min of my points."
in this case, you need to start a little more from below.(Y-axiis : 54,80 >> for exp. 55,60 ). This min value is calculated automatically.

its should be ;This min value is calculated automatically. like my pictures.
(Y-axis-min value) < (min of my points )

We can fix this.?
 
Last edited:

Tayfur

Well-Known Member
Licensed User
Longtime User
I added a line in your code. this is my solution.
if you approve @klaus

Thanks again for your nice share.





B4X:
    ' calculate the scale min value
    nbMin = Floor(ValMinMax(0) / Scale(Axis).IntervalAuto)
    If Abs(ValMinMax(0)) <= 0.0000000000001 Then
        Scale(Axis).MinAuto = 0
    Else If ValMinMax(0) >= 0 Then
        Scale(Axis).MinAuto = nbMin * Scale(Axis).IntervalAuto
        '---------------------Tayfur added this line------------
        If Scale(Axis).MinAuto=ValMinMax(0) Then Scale(Axis).MinAuto=Scale(Axis).MinAuto-Scale(Axis).IntervalAuto
        '------------------------------------------------------
    Else If ValMinMax(0) < 0 And ValMinMax(1) > 0 Then
        Scale(Axis).MinAuto = Floor(ValMinMax(0) / Scale(Axis).IntervalAuto + 0.00000000000001) * Scale(Axis).IntervalAuto
    Else
        Scale(Axis).MinAuto = Floor(ValMinMax(0) / Scale(Axis).IntervalAuto + 0.00000000000001) * Scale(Axis).IntervalAuto
    End If
   
    ' distribution of empty intervals
[/ CODE]
 

klaus

Expert
Licensed User
Longtime User
Your suggestion works only in your specific case and only for the bottom line and because the upper scale segment is empty.
The same could also happen for the top line.
To do this, the whole automatic scale calculation would need to be modified.
And if the problem happens on both lines the scale would be reduced.

I have removed the redrawing of the the frame for the next update.
 

klaus

Expert
Licensed User
Longtime User
How do you add the line points?
Do you need all XAxis tags?
If you use a For/Next loop you can, at the end of the AddLineMultiplePoints line,
replace True
by i Mod 2 = 0 diplaying 1 tag out of two
or i Mod 4 = 0 diplaying 1 tag out of four
etc.
 

VVS963

New Member
Sorry for my English. Dear Klaus. Can I insert a point outside the line in a line chart? Like this: As a result, it was possible to insert, but only by creating another line and lowering it below visibility with Autoscale = False. and only when the value on the X axis reaches the desired value to raise the line. The line itself is drawn with the background color. But this is not correct
 

Tayfur

Well-Known Member
Licensed User
Longtime User
How do you add the line points?
Do you need all XAxis tags?
If you use a For/Next loop you can, at the end of the AddLineMultiplePoints line,
replace True
by i Mod 2 = 0 diplaying 1 tag out of two
or i Mod 4 = 0 diplaying 1 tag out of four
etc.


Yes; its work only manually;
I changed your code; Now is auto (for only VERTICAL mode)

Updated DrawXScale

B4X:
'draws the X scale
Private Sub DrawXScale
    Private i, x, XInterval As Int
    Private txt As String
    
    If Graph.ChartType = "YX_CHART" Then
        XInterval = Graph.Width / Scale(sX).NbIntervals
        For i = 0 To Scale(sX).NbIntervals
            x = Graph.Left + i * XInterval
            txt = NumberFormat3(Scale(sX).MinVal + i * Scale(sX).Interval, 6)
#If B4i
            xcvsGraph.DrawLine(x, Graph.Bottom, x, Graph.Bottom + 4dip, Graph.GridFrameColor, 2dip)
            xcvsGraph.DrawLine(x, Graph.Top, x, Graph.Bottom, Graph.GridColor, 1dip)
            Select Graph.XScaleTextOrientation
                Case "HORIZONTAL"
                    xcvsGraph.DrawText(txt, x, Graph.Bottom + 1.35 * Texts.ScaleTextHeight, Texts.ScaleFont, Texts.ScaleTextColor, "CENTER")
                Case "VERTICAL"
                    xcvsGraph.DrawTextRotated(txt, x + 0.33 * Texts.ScaleTextHeight, Graph.Bottom + 0.5 * Texts.ScaleTextHeight, Texts.ScaleFont, Texts.ScaleTextColor, "RIGHT", -90)
                Case "45 DEGREES"
                    xcvsGraph.DrawTextRotated(txt, x + 0.4 * Texts.ScaleTextHeight, Graph.Bottom + 0.9 * Texts.ScaleTextHeight, Texts.ScaleFont, Texts.ScaleTextColor, "RIGHT", -45)
            End Select
#Else
            xcvsGraph.DrawLine(x, Graph.Bottom, x, Graph.Bottom + 4dip, Graph.GridFrameColor, 2dip)
            xcvsGraph.DrawLine(x, Graph.Top, x, Graph.Bottom, Graph.GridColor, 1dip)
            Select Graph.XScaleTextOrientation
                Case "HORIZONTAL"
                    xcvsGraph.DrawText(txt, x, Graph.Bottom + 1.1 * Texts.ScaleTextHeight, Texts.ScaleFont, Texts.ScaleTextColor, "CENTER")
                Case "VERTICAL"
                    xcvsGraph.DrawTextRotated(txt, x + 0.25 * Texts.ScaleTextHeight, Graph.Bottom + 0.6 * Texts.ScaleTextHeight, Texts.ScaleFont, Texts.ScaleTextColor, "RIGHT", -90)
                Case "45 DEGREES"
                    xcvsGraph.DrawTextRotated(txt, x + 0.3 * Texts.ScaleTextHeight, Graph.Bottom + 0.8 * Texts.ScaleTextHeight, Texts.ScaleFont, Texts.ScaleTextColor, "RIGHT", -45)
            End Select
#End If           
        Next
    Else
        For i = 0 To Points.Size - 1
            Private PD As PointData
            PD = Points.Get(i)
            If Graph.ChartType = "LINE" Then
                x = Graph.Left + i * Scale(sX).Scale
            Else
                x = Graph.Left + Graph.XOffset + (i + 0.5) * Graph.XInterval
            End If
#If B4i
            If PD.ShowTick = True Then
                xcvsGraph.DrawLine(x, Graph.Bottom, x, Graph.Bottom + 4dip, Graph.GridFrameColor, 2dip)
                xcvsGraph.DrawLine(x, Graph.Top, x, Graph.Bottom, Graph.GridColor, 1dip)
                Select Graph.XScaleTextOrientation
                    Case "HORIZONTAL"
                        xcvsGraph.DrawText(PD.X, x, Graph.Bottom + 1.35 * Texts.ScaleTextHeight, Texts.ScaleFont, Texts.ScaleTextColor, "CENTER")
                    Case "VERTICAL"
                        xcvsGraph.DrawTextRotated(PD.X, x + 0.33 * Texts.ScaleTextHeight, Graph.Bottom + 0.5 * Texts.ScaleTextHeight, Texts.ScaleFont, Texts.ScaleTextColor, "RIGHT", -90)
                    Case "45 DEGREES"
                        xcvsGraph.DrawTextRotated(PD.X, x + 0.4 * Texts.ScaleTextHeight, Graph.Bottom + 0.9 * Texts.ScaleTextHeight, Texts.ScaleFont, Texts.ScaleTextColor, "RIGHT", -45)
                End Select
            End If
#Else
            If PD.ShowTick = True Then
                xcvsGraph.DrawLine(x, Graph.Bottom, x, Graph.Bottom + 4dip, Graph.GridFrameColor, 2dip)
                xcvsGraph.DrawLine(x, Graph.Top, x, Graph.Bottom, Graph.GridColor, 1dip)
                Select Graph.XScaleTextOrientation
                    Case "HORIZONTAL"
                        xcvsGraph.DrawText(PD.X, x, Graph.Bottom + 1.1 * Texts.ScaleTextHeight, Texts.ScaleFont, Texts.ScaleTextColor, "CENTER")
                    Case "VERTICAL"
                        '**********************UPFATEED LINES**********************************************
                        Dim exksenyazi As String=""
                        If TextShowForX Then
                            xcvsGraph.DrawTextRotated(PD.X, x + 0.25 * Texts.ScaleTextHeight, Graph.Bottom + 0.6 * Texts.ScaleTextHeight, Texts.ScaleFont, Texts.ScaleTextColor, "RIGHT", -90)
                        Else
                            If i Mod Ceil(Texts.ScaleTextHeight/Scale(sX).Scale)=0 Then
                                exksenyazi=PD.X
                                Else
                                exksenyazi=""
                            End If
                            xcvsGraph.DrawTextRotated(exksenyazi, x + 0.25 * Texts.ScaleTextHeight, Graph.Bottom + 0.6 * Texts.ScaleTextHeight, Texts.ScaleFont, Texts.ScaleTextColor, "RIGHT", -90)
                        End If
                        '**********************************ORJINAL*******************************************
                        'xcvsGraph.DrawTextRotated(PD.X, x + 0.25 * Texts.ScaleTextHeight, Graph.Bottom + 0.6 * Texts.ScaleTextHeight, Texts.ScaleFont, Texts.ScaleTextColor, "RIGHT", -90)
                    Case "45 DEGREES"
                        xcvsGraph.DrawTextRotated(PD.X, x + 0.3 * Texts.ScaleTextHeight, Graph.Bottom + 0.8 * Texts.ScaleTextHeight, Texts.ScaleFont, Texts.ScaleTextColor, "RIGHT", -45)
                End Select
            End If
#End If
        Next
    End If
End Sub

Added get/set propertiy for auto or full showing

B4X:
'Class variable:
' Private TextShowForX as boolean 

'gets or sets the X axis values on graph
'setting this text size sets automatically ShowAllValue=TRUE
Public Sub setTextAllShowX(ShowAllValue As Boolean)
    TextShowForX=ShowAllValue
End Sub

'gets or sets the X axis values on graph
'setting this text size sets automatically ShowAllValue=TRUE
Public Sub getTextAllShowX As Boolean
    Return TextShowForX
End Sub


 

klaus

Expert
Licensed User
Longtime User
Hi Tayfur,
Sorry for answering only today, I was very busy with other projects.
I will look what I can do for this problem.

Yes; its work only manually;
It would be possible to calculate when ticks should be skipped depending on the number of samples when adding the points.
 
Last edited:

Tayfur

Well-Known Member
Licensed User
Longtime User
Hi Tayfur,
Sorry for answering only today, I was very busy with other projects.
I will look what I can do to for this problem.


It would be possible to calculate when ticks should be skipped depending on the number of samples when adding the points.

thanks @klaus ;

my update working when resize action. No need extra calculation.

Thank again for nice share.
 

stevel05

Expert
Licensed User
Longtime User
Hi Klaus,

Thanks for this excellent code module.

I am looking to incorporate a basic Line graph into my LogServer as a time plot which doesn't need a title to be displayed. Making the title field in the designer empty removes the title field from the graph, but the top line value is drawn half above the top of the parent pane. I thought I should report it.


To fix this I have changed the code in InitChart to :

B4X:
If Graph.Title <> "" Then
        Graph.Top = Graph.Top + 1.2 * Texts.TitleTextHeight
    Else
        Graph.Top = 0.3 * Texts.TitleTextHeight
    End If

It doesn't appear to affect any thing else, but as I don't know the code very well, I thought I should check in case there there may be a knock on in this or another chart that I haven't used yet.

Thanks Again

Steve
 
Last edited:
Cookies are required to use this site. You must accept them to continue using the site. Learn more…