PureBasic Forum
http://forums.purebasic.com/english/

Simple Stacked Bar Chart
http://forums.purebasic.com/english/viewtopic.php?f=12&t=72026
Page 1 of 1

Author:  thanos [ Wed Jan 02, 2019 2:46 pm ]
Post subject:  Simple Stacked Bar Chart

Hello and Happy New Year to all!
I just created a simple but configurable stacked bar graph, το cover a specific need.
The code is not very elegant but covers my need.
If it is useful to someone it can use it freely.
Best regards.

Thanos

Updated, 03/01/2019
v 1.1 :: Small changes to draw the data series, if it is desirable

Code:
;##-<< Simple Stacked Bar Graph >>-#######################################################
;{
;#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;#       Author: Athanasios I. Douros
;#      Version: 1.0, 02/01/2019
;#      Changes: 1.1, 03/01/2019. Small changes to draw the data series, if it is desirable
;#      Purpose: Show stacked bars
;# Restrictions: Free to use, no restrictions.
;#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;}
;##-<< Simple Stacked Bar Graph >>-#######################################################

EnableExplicit


DeclareModule StackedBarChart
 
  EnableExplicit
  #STACKBAR_CHART_WIDTH    = 1200
  #STACKBAR_CHART_HEIGHT   = 700
  #DRAW_BAR_AT_POS         = 150
  #LEGEND_HEIGHT           = 15
  #BAR_HEIGHT              = 65
  #DISTANCE_BETWEEN_BARS   = 10
  #DISTANCE_BETWEEN_LABELS = 2
  #AXIS_WIDTH              = 100
 
 
  Structure Delay
    Header.s
    Value_1.d
    Value_2.d
    Value_3.d
    Value_4.d
    Value_5.d
    Value_6.d
    Value_7.d
    Value_8.d
    List DataSeries.d()
  EndStructure
 
  Declare StackedBarShow(sTitle.s, List Values.Delay(), List Labels.s(), DrawDataSeries = #True)
 
EndDeclareModule


Module StackedBarChart
 
  Procedure Max(Value1, Value2)
    If (Value1 >= Value2)
      ProcedureReturn Value1
    Else
      ProcedureReturn Value2
    EndIf
  EndProcedure
 
 
  Procedure StackedBarsCalcPercentages(List Values.Delay())
    Protected dSum.d
   
    ForEach Values()
      With Values()
        dSum = \Value_1 +
               \Value_2 +
               \Value_3 +
               \Value_4 +
               \Value_5 +
               \Value_6 +
               \Value_7 +
               \Value_8
       
        \Value_1 = (\Value_1 / dSum)
        \Value_2 = (\Value_2 / dSum)
        \Value_3 = (\Value_3 / dSum)
        \Value_4 = (\Value_4 / dSum)
        \Value_5 = (\Value_5 / dSum)
        \Value_6 = (\Value_6 / dSum)
        \Value_7 = (\Value_7 / dSum)
        \Value_8 = (\Value_8 / dSum)
       
        ;~ Fill the data for data series
        AddElement(\DataSeries()): \DataSeries() = \Value_1
        AddElement(\DataSeries()): \DataSeries() = \Value_2
        AddElement(\DataSeries()): \DataSeries() = \Value_3
        AddElement(\DataSeries()): \DataSeries() = \Value_4
        AddElement(\DataSeries()): \DataSeries() = \Value_5
        AddElement(\DataSeries()): \DataSeries() = \Value_6
        AddElement(\DataSeries()): \DataSeries() = \Value_7
        AddElement(\DataSeries()): \DataSeries() = \Value_8
      EndWith
    Next
   
  EndProcedure
 
 
  Procedure StackedBarsDraw(List Values.Delay(), List Labels.s(), WinHeight, Font1, Font2, Font3, DrawDataSeries)
    Protected CurrBar
    Protected BarLeft
    Protected BarTop
    Protected BarLen
    Protected BarValue.d
    Protected StackLen  = #STACKBAR_CHART_WIDTH - 175
    Protected LabelTop
    Protected LabelLeft
   
    Protected CurrVal
    Protected TotalLabels
    Protected sLabel.s
    ;~ Protected NewList BranchData.d()
    Protected Dim StackBarColor(7)
   
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;~ Colors
    ;{
    StackBarColor(00) = RGBA(102, 170, 000, 255)
    StackBarColor(01) = RGBA(016, 150, 024, 255)
    StackBarColor(02) = RGBA(034, 170, 153, 255)
    StackBarColor(03) = RGBA(221, 068, 119, 255)
    StackBarColor(04) = RGBA(255, 010, 010, 255)
    StackBarColor(05) = RGBA(153, 000, 153, 255)
    StackBarColor(06) = RGBA(127, 000, 000, 255)
    StackBarColor(07) = RGBA(048, 048, 048, 255)
    ;}
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   
    ForEach Values()
      ;~ ClearList(BranchData())
      ;~ AddElement(BranchData()): BranchData() = Values()\Value_1
      ;~ AddElement(BranchData()): BranchData() = Values()\Value_2
      ;~ AddElement(BranchData()): BranchData() = Values()\Value_3
      ;~ AddElement(BranchData()): BranchData() = Values()\Value_4
      ;~ AddElement(BranchData()): BranchData() = Values()\Value_5
      ;~ AddElement(BranchData()): BranchData() = Values()\Value_6
      ;~ AddElement(BranchData()): BranchData() = Values()\Value_7
      ;~ AddElement(BranchData()): BranchData() = Values()\Value_8       
     
      ;~ Set the drawing font
      DrawingFont(FontID(Font1))
     
      ;~ Take the values
      sLabel  = Values()\Header
      BarLeft = #DRAW_BAR_AT_POS
      BarTop  = (CurrBar * #BAR_HEIGHT)
      CurrVal = 0
     
      ForEach Values()\DataSeries()
        BarLen   = (StackLen * Values()\DataSeries())
        BarValue = (BarLen/StackLen) * 100
        LabelTop = BarTop  + (#BAR_HEIGHT / 2.5)
        Box(BarLeft, BarTop + (CurrBar * #DISTANCE_BETWEEN_BARS) + 5, BarLen, #BAR_HEIGHT,  StackBarColor(CurrVal))
        DrawText(BarLeft+5, LabelTop + (CurrBar * #DISTANCE_BETWEEN_BARS) + 5, StrD(BarValue, 2) + "%", $FFFFFF)
        BarLeft + BarLen
       
        ;~ Increase counter
        CurrVal + 1
      Next
     
      ;~ Set the label
      DrawingFont(FontID(Font2))
      DrawText(10, LabelTop + (CurrBar * #DISTANCE_BETWEEN_BARS), sLabel, RGBA(75, 75, 75, 75))
     
      CurrBar + 1
    Next
   
    ;~ Draw the legends
    CurrBar     = 0
    TotalLabels = ListSize(Labels()) + #DISTANCE_BETWEEN_LABELS
    BarTop      = WinHeight - (TotalLabels * #LEGEND_HEIGHT)
    ;~ Set the drawing font
    DrawingFont(FontID(Font3))
    ForEach Labels()
      Box(150, BarTop, 25, #LEGEND_HEIGHT, StackBarColor(CurrBar))
      DrawText(180, BarTop, Labels(), RGBA(75, 75, 75, 75))
      CurrBar + 1
      BarTop  + #LEGEND_HEIGHT + #DISTANCE_BETWEEN_LABELS
    Next
   
   
    ;~ Draw the Data series
    If (DrawDataSeries = #True)
      TotalLabels = ListSize(Labels()) + #DISTANCE_BETWEEN_LABELS
      LabelLeft   = 375
      ;~ Set the drawing font
      DrawingFont(FontID(Font3))
     
      ForEach Values()
        With Values()
          BarTop      = WinHeight - (TotalLabels * #LEGEND_HEIGHT) - 20
          DrawText(LabelLeft, BarTop, \Header, RGBA(75, 75, 75, 75))     
          ;~ Start drawing the data
          BarTop      = WinHeight - (TotalLabels * #LEGEND_HEIGHT)
          ForEach \DataSeries()
            DrawText(LabelLeft, BarTop, StrD((\DataSeries() * 100), 2) + "%", RGBA(75, 75, 75, 75))     
            BarTop    + #LEGEND_HEIGHT + #DISTANCE_BETWEEN_LABELS
          Next
        EndWith
        LabelLeft + #AXIS_WIDTH
      Next   
    EndIf
   
  EndProcedure
 
 
  Procedure StackedBarShow(sTitle.s, List Values.Delay(), List Labels.s(), DrawDataSeries = #True)
    Protected Event
    Protected hImg1
    Protected hImg2
    Protected hWnd
    Protected hScroll
    Protected WinHeight
    Protected WinWidth
    Protected Font1 = LoadFont(#PB_Any, "Tahoma",  7, #PB_Font_Bold|#PB_Font_HighQuality)
    Protected Font2 = LoadFont(#PB_Any, "Tahoma", 11, #PB_Font_HighQuality)
    Protected Font3 = LoadFont(#PB_Any, "Tahoma",  7, #PB_Font_HighQuality)
   
    WinHeight = ListSize(Values()) * (#BAR_HEIGHT + 5)
    WinHeight + ListSize(Labels()) * (#LEGEND_HEIGHT + 5)
    WinHeight * 1.05
    WinHeight = Max(WinHeight, #STACKBAR_CHART_HEIGHT)
   
    If (DrawDataSeries = #True)
      WinWidth  = ListSize(Values()) * (#AXIS_WIDTH * 1.30)
      WinWidth  = Max(WinWidth, #STACKBAR_CHART_WIDTH)
    Else
      WinWidth  = #STACKBAR_CHART_WIDTH
    EndIf
   
    hWnd = OpenWindow(#PB_Any, 0, 0, #STACKBAR_CHART_WIDTH, #STACKBAR_CHART_HEIGHT, sTitle, #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    If (hWnd)
      hScroll = ScrollAreaGadget(#PB_Any, 0, 0, #STACKBAR_CHART_WIDTH, #STACKBAR_CHART_HEIGHT, WinWidth, WinHeight, 30, #PB_ScrollArea_Flat)
     
      hImg1 = CreateImage(#PB_Any, WinWidth, WinHeight)
      If (hImg1) And (StartDrawing(ImageOutput(hImg1)))
        ;~ If CreateImage(0, #CHART_WIDTH, #CHART_HEIGHT) And StartDrawing(ImageOutput(0))
       
        DrawingMode(#PB_2DDrawing_Transparent)
       
        ;~ Change from values to percentages
        StackedBarsCalcPercentages(Values())
       
        ;~ Set white background for the whole chart
        Box(0, 0, WinWidth, WinHeight, $FFFFFF)
       
        ;~ Display the stacked bars
        StackedBarsDraw(Values(), Labels(), WinHeight, Font1, Font2, Font3, DrawDataSeries)
       
        StopDrawing()
        hImg2 = ImageGadget(#PB_Any, 0, 0, WinWidth, WinHeight, ImageID(hImg1))
        CloseGadgetList()
       
      EndIf
     
      Repeat
        Event = WaitWindowEvent()
      Until Event = #PB_Event_CloseWindow
      CloseWindow(hWnd)
    EndIf
  EndProcedure
EndModule


CompilerIf #PB_Compiler_IsMainFile
  Define NewList Labels.s()
  AddElement(Labels()): Labels() = "Label 1"
  AddElement(Labels()): Labels() = "Label 2"
  AddElement(Labels()): Labels() = "Label 3"
  AddElement(Labels()): Labels() = "Label 4"
  AddElement(Labels()): Labels() = "Label 5"
  AddElement(Labels()): Labels() = "Label 6"
  AddElement(Labels()): Labels() = "Label 7"
  AddElement(Labels()): Labels() = "Label 8"
 
  ;~ You can add as many Values() as you want
  ;~ Each Values() creates a new bar in chart
  Define NewList Values.StackedBarChart::Delay()
  AddElement(Values())
  Values()\Header   = "Header 001"
  Values()\Value_1 = 4898600.0
  Values()\Value_2 = 2811870.0
  Values()\Value_3 = 2013820.0
  Values()\Value_4 = 1834540.0
  Values()\Value_5 = 2586490.0
  Values()\Value_6 = 1134970.0
  Values()\Value_7 = 1253450.0
  Values()\Value_8 = 3738510.0
 
  AddElement(Values())
  Values()\Header   = "Header 002"
  Values()\Value_1 = 5068430.0
  Values()\Value_2 = 597752.0
  Values()\Value_3 = 1867140.0
  Values()\Value_4 = 1338630.0
  Values()\Value_5 = 422371.0
  Values()\Value_6 = 351421.0
  Values()\Value_7 = 307252.0
  Values()\Value_8 = 10894000.0
 
  AddElement(Values())
  Values()\Header   = "Header 003"
  Values()\Value_1 = 1098130.0
  Values()\Value_2 = 884433.0
  Values()\Value_3 = 277653.0
  Values()\Value_4 = 499117.0
  Values()\Value_5 = 448056.0
  Values()\Value_6 = 2138260.0
  Values()\Value_7 = 769726.0
  Values()\Value_8 = 3826260.0
 
  AddElement(Values())
  Values()\Header   = "Header 004"
  Values()\Value_1 = 1135720.0
  Values()\Value_2 = 371530.0
  Values()\Value_3 = 154354.0
  Values()\Value_4 = 46228.0
  Values()\Value_5 = 12444.2
  Values()\Value_6 = 0.0
  Values()\Value_7 = 8074.23
  Values()\Value_8 = 57124.9
 
  AddElement(Values())
  Values()\Header   = "Header 005"
  Values()\Value_1 = 522394.0
  Values()\Value_2 = 198548.0
  Values()\Value_3 = 108467.0
  Values()\Value_4 = 163168.0
  Values()\Value_5 = 62078.0
  Values()\Value_6 = 44384.9
  Values()\Value_7 = 131412.0
  Values()\Value_8 = 236213.0
 
  AddElement(Values())
  Values()\Header   = "Header 006"
  Values()\Value_1 = 522394.0
  Values()\Value_2 = 198548.0
  Values()\Value_3 = 108467.0
  Values()\Value_4 = 663168.0
  Values()\Value_5 = 62078.0
  Values()\Value_6 = 44384.6
  Values()\Value_7 = 131412.0
  Values()\Value_8 = 236213.0
 
  AddElement(Values())
  Values()\Header   = "Header 007"
  Values()\Value_1 = 222394.0
  Values()\Value_2 = 198548.0
  Values()\Value_3 = 108467.0
  Values()\Value_4 = 163168.0
  Values()\Value_5 = 62078.0
  Values()\Value_6 = 44385.1
  Values()\Value_7 = 131412.0
  Values()\Value_8 = 236213.0
 
  ;~ Show the chart
  StackedBarChart::StackedBarShow("Stacked bar demo", Values.StackedBarChart::Delay(), Labels(), #True)
CompilerEndIf

Author:  HanPBF [ Wed Jan 02, 2019 4:48 pm ]
Post subject:  Re: Simple Stacked Bar Chart

This is really simple -> thanks to PureBasic!

This is a great example -> thanks to thanos!

Thanks a lot!!!

Author:  thanos [ Wed Jan 02, 2019 6:22 pm ]
Post subject:  Re: Simple Stacked Bar Chart

@HanPBF
Thank you very much for the kind words!
Regards

Thanos

Author:  Kwai chang caine [ Thu Jan 03, 2019 12:13 pm ]
Post subject:  Re: Simple Stacked Bar Chart

Nice and simple
Thanks for sharing 8)

Author:  RSBasic [ Thu Jan 03, 2019 12:26 pm ]
Post subject:  Re: Simple Stacked Bar Chart

Nice :)

Author:  thanos [ Thu Jan 03, 2019 6:22 pm ]
Post subject:  Re: Simple Stacked Bar Chart

There is an updated version with small changes.
Code has been updated in the first post.
Regards

Thanos

Author:  Andre [ Thu Jan 03, 2019 8:42 pm ]
Post subject:  Re: Simple Stacked Bar Chart

Very nice, thank you! :D

Page 1 of 1 All times are UTC + 1 hour
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/