Simple Stacked Bar Chart

Share your advanced PureBasic knowledge/code with the community.
thanos
Enthusiast
Enthusiast
Posts: 422
Joined: Sat Jan 12, 2008 3:25 pm
Location: Greece
Contact:

Simple Stacked Bar Chart

Post by thanos »

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: Select all

;##-<< 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
Last edited by thanos on Thu Jan 03, 2019 3:29 pm, edited 2 times in total.
» myPersonal Banker :: Because you do not need to have a master degree in economics in order to organize your finances!
HanPBF
Enthusiast
Enthusiast
Posts: 562
Joined: Fri Feb 19, 2010 3:42 am

Re: Simple Stacked Bar Chart

Post by HanPBF »

This is really simple -> thanks to PureBasic!

This is a great example -> thanks to thanos!

Thanks a lot!!!
thanos
Enthusiast
Enthusiast
Posts: 422
Joined: Sat Jan 12, 2008 3:25 pm
Location: Greece
Contact:

Re: Simple Stacked Bar Chart

Post by thanos »

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

Thanos
» myPersonal Banker :: Because you do not need to have a master degree in economics in order to organize your finances!
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Simple Stacked Bar Chart

Post by Kwai chang caine »

Nice and simple
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
User avatar
RSBasic
Moderator
Moderator
Posts: 1218
Joined: Thu Dec 31, 2009 11:05 pm
Location: Gernsbach (Germany)
Contact:

Re: Simple Stacked Bar Chart

Post by RSBasic »

Nice :)
Image
Image
thanos
Enthusiast
Enthusiast
Posts: 422
Joined: Sat Jan 12, 2008 3:25 pm
Location: Greece
Contact:

Re: Simple Stacked Bar Chart

Post by thanos »

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

Thanos
» myPersonal Banker :: Because you do not need to have a master degree in economics in order to organize your finances!
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: Simple Stacked Bar Chart

Post by Andre »

Very nice, thank you! :D
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
Post Reply