Electoral bonds data in charts

visualization
R
Author

Asitav Sen

Published

April 6, 2025

Modified

April 6, 2025

Bonds worth ₹ 121 Billion purchase between Apr 2019 and Jan 2024

Data was downloaded from dataful. Rows without reference number or with status Expired are not considered in this analysis. Hence, there may be a variation between the numbers.of excluded data is available below

Code
highchart() |>
    hc_chart(type = "sankey", inverted = FALSE) |>
    hc_add_series(
        data = list_parse(sankey.dat),
        nodes = list_parse(nodes),
        name = "Flow",
        type = "sankey",
        nodeWidth = 20,
        linkOpacity = 0.5,  # Make links semi-transparent
        states = list(
            hover = list(
                linkOpacity = 0.8  # Increase opacity on hover
            )
        )
    ) |>
    hc_plotOptions(
        sankey = list(
            nodePadding = 3,    
            curveFactor = 0.6,
            colors = c("#1f77b4", "#ff7f0e", "#2ca02c"),  # Colors for nodes
            linkColor = "#d3d3d3"  # Default link color (can be rgba for transparency)
        )
    ) |>
    hc_title(
        text = "Flow of Electoral Bonds",
        align = "left",
        style = list(
            textDecoration = "underline",
            color = "#333333",
            fontWeight = "bold"
        )
    ) |>
    hc_subtitle(
        text = "Electoral bond encashment between Apr 16, 2019 and Jan 24, 2024"
    ) |>
    hc_tooltip(
        formatter = JS("
            function() {
                var amount = this.point.weight;
                // Check if it's a node (will have no 'weight' property)
                if (typeof amount === 'undefined') {
                    return '<b>' + this.point.name + '</b>';
                }
                // For links
                if (amount >= 1000000000) {
                    return '<b>' + this.point.from + '</b> to <b>' + 
                           this.point.to + '</b>: ₹' + 
                           (amount/1000000000).toFixed(2) + 'B';
                } else {
                    return '<b>' + this.point.from + '</b> to <b>' + 
                           this.point.to + '</b>: ₹' + 
                           (amount/1000000).toFixed(2) + 'M';
                }
            }
        ")
    ) |>
    hc_credits(
        enabled = TRUE,
        text = "Heteroscedasticity",
        href = "https://asitavsen.com",
        style = list(fontSize = "12px")
    ) |>
    hc_add_theme(custom_theme) |>
    hc_exporting(
        enabled = TRUE,
        filename = "ElectoralBondFlow"
    )

86 % (₹ 105 B) of money went to 5 parties. 91 % (₹ 111 B) of money came from 5 states

Code
##| fig-width: 10

# Plot amount distribution by political party
plot_hc_pie_chart(
  amount_by_party, 
  xval = "standardised_political_party_name", 
  yval = "total_amount",
  series_name = "Amount",
  theme = custom_theme,
  title_text = "Amount by Political Party",
  subtitle_text = "Electoral bond encashment between Apr 16, 2019 and Jan 24, 2024",
  output_filename = "AmountByPoliticalParty"
)
# Plot amount distribution by state
plot_hc_pie_chart(
  amount_by_state, 
  xval = "issue_branch_state", 
  yval = "total_amount",
  series_name = "Amount",
  theme = custom_theme,
  title_text = "Amount by State",
  output_filename = "AmountByState",
  subtitle_text = "Electoral bond encashment between Apr 16, 2019 and Jan 24, 2024"
)
# Create and plot top purchasers chart
plot_hc_pie_chart(
  rbind(
    data.comb[, .(total_amount = sum(amount)), 
              by = .(standardised_purchaser_name)
    ][order(-total_amount)][1:20],
    data.table(
      standardised_purchaser_name = "Others",
      total_amount = data.comb[, .(total_amount = sum(amount)), 
                              by = .(standardised_purchaser_name)
      ][order(-total_amount)][21:.N, sum(total_amount)]
    )
  ),
  xval = "standardised_purchaser_name",
  yval = "total_amount",
  series_name = "Amount",
  theme = custom_theme,
  title_text = "Amount by Purchaser",
  output_filename = "AmountByPurchaser",
  subtitle_text = "Electoral bond encashment between Apr 16, 2019 and Jan 24, 2024"
)

>70% of Purchasers are organizations; contributed 96% amount

Code
# Calculate summary statistics
total_contribution <- sum(data.comb$amount)
total_purchasers <- uniqueN(data.comb$standardised_purchaser_name)

# Calculate organization vs individual statistics
org.ind <- data.comb[, .(
  total_amount = sum(amount),
  contribution_percent = round(100 * sum(amount) / total_contribution, 2),
  purchasers = uniqueN(standardised_purchaser_name),
  transactions = .N,
  avg_contribution = sum(amount) / uniqueN(standardised_purchaser_name),
  avg_transaction_val = sum(amount) / .N
), by = .(organisation_or_individual)]

org.ind.count <- unique(
  data.comb[, .(organisation_or_individual, standardised_purchaser_name)]
)[, .(
  N = .N,
  count_percent = round(100 * .N / total_purchasers, 2)
), by = organisation_or_individual]



highchart() |>
  hc_add_series(
    org.ind,
    "column",
    hcaes(x = organisation_or_individual, y = total_amount),
    name = "Purchase Amount",
    dataLabels = list(enabled = TRUE, align = "right")
  ) |>
  hc_add_series(
    org.ind,
    "pie",
    hcaes(name = organisation_or_individual, y = contribution_percent),
    name = "Share of Purchase",
    dataLabels = list(enabled = TRUE, align = "right")
  ) |>
  hc_plotOptions(
    series = list(showInLegend = FALSE, colorByPoint = TRUE),
    pie = list(
      center = c("70%", "30%"),
      size = 120,
      dataLabels = list(enabled = FALSE)
    )
  ) |>
  hc_yAxis(title = list(text = "Purchase Amount (M)")) |>
  hc_xAxis(categories = org.ind$organisation_or_individual) |>
  hc_tooltip(
    shared = FALSE,
    useHTML = TRUE,
    formatter = JS("
      function() {
        if (this.series.type === 'column') {
          return '<b>' + this.point.name +
                 '</b>: ₹' + 
                 (this.y / 1000000).toFixed(2) + ' M';
        } else if (this.series.type === 'pie') {
          return '<b>' + this.point.name + '</b>: ' + 
                 this.y + '%';
        }
      }
    ")
  ) |>
  hc_title(
    text = "Purchase amount by Individuals and Organization",
    align = "left",
    style = list(
      textDecoration = "underline",
      color = "#333333",
      fontWeight = "bold"
    )
  ) |>
  hc_subtitle(
    text = "Electoral bond encashment between Apr 16, 2019 and Jan 24, 2024"
  ) |>
  hc_credits(
    enabled = TRUE,
    text = "Heteroscedasticity",
    href = "https://blog.asitavsen.com",
    style = list(fontSize = "12px")
  ) |>
  hc_add_theme(custom_theme) |>
  hc_exporting(enabled = TRUE, filename = "OrgvsIndAmt")
Code
# Plot purchaser count distribution
highchart() |>
  hc_add_series(
    org.ind.count,
    "column",
    hcaes(x = organisation_or_individual, y = N),
    name = "Number of Purchasers",
    dataLabels = list(enabled = TRUE, align = "right")
  ) |>
  hc_add_series(
    org.ind.count,
    "pie",
    hcaes(name = organisation_or_individual, y = count_percent),
    name = "Share of Purchasers",
    dataLabels = list(enabled = TRUE, align = "right")
  ) |>
  hc_plotOptions(
    series = list(showInLegend = FALSE, colorByPoint = TRUE),
    pie = list(
      center = c("70%", "30%"),
      size = 120,
      dataLabels = list(enabled = FALSE)
    )
  ) |>
  hc_yAxis(title = list(text = "Number of Purchasers")) |>
  hc_xAxis(categories = org.ind.count$organisation_or_individual) |>
  hc_tooltip(
    shared = FALSE,
    useHTML = TRUE,
    formatter = JS("
      function() {
        if (this.series.type === 'column') {
          return '<b>' + this.point.name + '</b>: ' + 
                 this.y + ' purchasers';
        } else if (this.series.type === 'pie') {
          return '<b>' + this.point.name + '</b>: ' + 
                 this.y + '%';
        }
      }
    ")
  ) |>
  hc_title(
    text = "#Organizational vs Individual purchasers",
    align = "left",
    style = list(
      textDecoration = "underline",
      color = "#333333",
      fontWeight = "bold"
    )
  ) |>
  hc_subtitle(
    text = "Electoral bond encashment between Apr 16, 2019 and Jan 24, 2024"
  ) |>
  hc_credits(
    enabled = TRUE,
    text = "Heteroscedasticity",
    href = "https://blog.asitavsen.com",
    style = list(fontSize = "12px")
  ) |>
  hc_add_theme(custom_theme) |>
  hc_exporting(enabled = TRUE, filename = "Purchasers")

Individuals

Highest encashment by BJP but INC had more purchasers (Individuals). Biggest purchase made by MS S N Mohanty (Encashed by Biju Janta Dal) followed by Lakshmi Niwas Mittal (Encashed by BJP). Most purchases (value) were made in Maharashtra.

Code
# Calculate individual party contributions and statistics
ind_party <- data.comb[
  organisation_or_individual == "Individual", 
  .(
    total_amount = sum(amount),
    count = .N,
    per_count = .N / sum(data.comb[organisation_or_individual == "Individual", .N])
  ), 
  by = standardised_political_party_name
][order(-total_amount)]

# Create combined column and pie chart
highchart() |>
  hc_add_series(
    ind_party,
    "column",
    hcaes(x = standardised_political_party_name, y = total_amount),
    name = "Amount"
  ) |>
  hc_add_series(
    ind_party,
    "pie",
    hcaes(name = standardised_political_party_name, y = count),
    name = "#Purchasers",
    dataLabels = list(enabled = FALSE)
  ) |>
  hc_plotOptions(
    series = list(
      showInLegend = FALSE,
      colorByPoint = TRUE
    ),
    pie = list(
      center = c("75%", "25%"),
      size = 120,
      innerSize = "75%",
      dataLabels = list(enabled = FALSE)
    )
  ) |>
  hc_yAxis(
    title = list(text = "Total Purchase (in millions)"), 
    labels = list(
      formatter = JS("function() { return (this.value / 1000000) + ' M'; }")
    )
  ) |>
  hc_xAxis(categories = ind_party$standardised_political_party_name) |>
  hc_tooltip(
    shared = FALSE,
    useHTML = TRUE,
    formatter = JS("
      function() {
        if (this.series.type === 'column') {
          return '<b>' + this.point.name + '</b>: ₹' + 
                 (this.y / 1000000).toFixed(2) + ' M';
        } else if (this.series.type === 'pie') {
          return '<b>' + this.point.name + '</b>: ' + 
                 this.y + ' contributors';
        }
      }
    ")
  ) |>
  hc_title(
    text = "Electoral Bond Purchases by Organizations (Amount and Purchasers)",
    align = "left",
    style = list(
      textDecoration = "underline",
      color = "#333333",
      fontWeight = "bold"
    )
  ) |>
  hc_subtitle(
    text = "Electoral bond encashment between Apr 16, 2019 and Jan 24, 2024"
  ) |>
  hc_credits(
    enabled = TRUE, 
    text = "Heteroscedasticity",
    href = "https://asitavsen.com",
    style = list(fontSize = "12px")
  ) |>
  hc_add_theme(custom_theme) |>
  hc_exporting(
    enabled = TRUE,
    filename = "Individuals"
  )
Code
# Calculate individual contributions and statistics by party
ind_amount_count_by_party <- data.comb[
  organisation_or_individual == "Individual",
  .(
    total_amount = sum(amount),
    count = uniqueN(standardised_purchaser_name),
    avg = sum(amount) / uniqueN(standardised_purchaser_name)
  ),
  by = standardised_political_party_name
][order(-avg)]

# Calculate individual contributions by party and purchaser
party_ind_top <- data.comb[
  organisation_or_individual == "Individual",
  .(total_amount = sum(amount)),
  by = .(standardised_political_party_name, standardised_purchaser_name)
][, standardised_political_party_name := fct_other(
  standardised_political_party_name,
  keep = c(
    "Indian National Congress",
    "Bharatiya Janata Party",
    "All India Trinamool Congress",
    "Bharat Rashtra Samithi",
    "Biju Janata Dal"
  )
)]

# Get party order by total amount
party_order <- party_ind_top[
  , .(range_diff = sum(total_amount)),
  by = standardised_political_party_name
][order(-range_diff), standardised_political_party_name]

# Create scatter plot
highchart() |>
  hc_add_series(
    data = party_ind_top,
    type = "scatter",
    hcaes(
      x = "standardised_political_party_name", 
      y = "total_amount", 
      group = "standardised_political_party_name"
    )
  ) |>
  hc_xAxis(
    type = "category",
    categories = party_order
  ) |>
  hc_yAxis(
    title = list(text = "Number of Contributors"),
    labels = list(
      formatter = JS("function() { return this.value / 1000000 + 'M'; }")
    )
  ) |>
  hc_title(
    text = "Top individual purchasers by Party",
    align = "left",
    style = list(
      textDecoration = "underline",
      color = "#333333",
      fontWeight = "bold"
    )
  ) |>
  hc_plotOptions(
    scatter = list(
      color = "red",
      marker = list(
        radius = 4,
        symbol = "circle",
        lineWidth = 1
      ),
      jitter = list(x = .2, y = 0)
    )
  ) |>
  hc_legend(enabled = FALSE) |>
  hc_tooltip(
    formatter = JS("
      function() {
        return 'Purchaser: ' + this.point.standardised_purchaser_name + 
               '<br>Contribution: ₹' + (this.point.total_amount/1000000).toFixed(2) + 'M';
      }
    ")
  ) |>
  hc_subtitle(
    text = "Electoral bond encashment between Apr 16, 2019 and Jan 24, 2024"
  ) |>
  hc_credits(
    enabled = TRUE,
    text = "Heteroscedasticity",
    href = "https://asitavsen.com",
    style = list(fontSize = "12px")
  ) |>
  hc_add_theme(custom_theme) |>
  hc_exporting(
    enabled = TRUE,
    filename = "IndividualsTop"
  )
Code
# First apply fct_other, then aggregate properly
party_ind_state <- data.comb[
  organisation_or_individual == "Individual"
][, `:=`(
  issue_branch_state = fct_other(
    issue_branch_state,
    keep = c("Maharashtra", "Delhi", "Odisha", "West Bengal", 
             "Telengana", "Rajasthan", "Gujrat"),
    other_level = "other_states"
  ),
  standardised_political_party_name = fct_other(
    standardised_political_party_name,
    keep = c("Indian National Congress", "Bharatiya Janata Party",
             "All India Trinamool Congress", "Bharat Rashtra Samithi",
             "Biju Janata Dal"),
    other_level = "other_parties"
  )
)][, .(total_amount = sum(amount)), 
   by = .(issue_branch_state, standardised_political_party_name)]  # This will properly aggregate all combinations

# Verify the aggregation
#print(party_ind_state[issue_branch_state == "other_states"])

# Order states by total amount
state_order <- party_ind_state[, 
  .(state_total = sum(total_amount)), 
  by = issue_branch_state
][order(-state_total), issue_branch_state]

# Create ordered stacked column chart
hchart(
  party_ind_state,
  "column", 
  hcaes(x = issue_branch_state, y = total_amount, 
        group = standardised_political_party_name)
) |>
  hc_xAxis(categories = as.character(state_order)) |>
  hc_plotOptions(series = list(stacking = "normal")) |>
  hc_tooltip(
    useHTML = TRUE,
    formatter = JS("
      function() {
        return '<b>' + this.point.issue_branch_state + '</b><br>' +
               this.point.standardised_political_party_name + ': ₹' +
               (this.y / 1000000000).toFixed(2) + 'B';
      }
    ")
  ) |>
  hc_yAxis(
    title = list(text = "Total Contribution (in billions)"),
    labels = list(
      formatter = JS("function() { return '₹' + this.value / 1000000000 + 'B'; }")
    )
  ) |>
  hc_title(
    text = "Purchase in States and parties by Individuals",
    align = "left",
    style = list(
      textDecoration = "underline",
      color = "#333333",
      fontWeight = "bold"
    )
  ) |>
  hc_subtitle(
    text = "Electoral bond encashment between Apr 16, 2019 and Jan 24, 2024"
  ) |>
  hc_credits(
    enabled = TRUE,
    text = "Heteroscedasticity",
    href = "https://asitavsen.com",
    style = list(fontSize = "12px")
  ) |>
  hc_add_theme(custom_theme) |>
  hc_exporting(
    enabled = TRUE,
    filename = "StateIndividuals"
  )
Code
hchart(
  party_ind_state,
  "heatmap",
  hcaes(x = standardised_political_party_name, 
        y = issue_branch_state,
        value = total_amount)
) |>
  hc_colorAxis(
    stops = list(
      list(0, "#FFFFFF"),     # White
      list(0.1, "#FFE5E5"),   # Very light red
      list(0.2, "#FFB3B3"),   # Lighter red
      list(0.3, "#FF8080"),   # Light red
      list(0.4, "#FF4D4D"),   # Medium light red
      list(0.5, "#FF1A1A"),   # Medium red
      list(0.6, "#E60000"),   # Medium dark red
      list(0.7, "#CC0000"),   # Dark red
      list(0.8, "#B30000"),   # Darker red
      list(0.9, "#990000"),   # Very dark red
      list(1, "#800000")      # Deepest red
    ),
    type = "linear",
    min = 1,
    max = max(party_ind_state$total_amount),
    labels = list(
      formatter = JS("
        function() {
          return '₹' + (this.value/1000000000).toFixed(1) + 'B';
        }
      ")
    )
  ) |>
  hc_xAxis(
    categories = sort(unique(party_ind_state$standardised_political_party_name)),  # Alphabetical order
    title = list(text = "Political Party"),
    labels = list(rotation = -45)
  ) |>
  hc_yAxis(
    categories = as.character(state_order),  # Keeping states ordered by amount
    title = list(text = "State"),
    reversed = TRUE
  ) |>
  hc_tooltip(
    formatter = JS("
      function() {
        return '<b>' + this.point.issue_branch_state + 
               '</b><br>' + this.point.standardised_political_party_name + 
               '<br>₹' + (this.point.value/1000000000).toFixed(2) + 'B';
      }
    ")
  ) |>
  hc_title(
    text = "Individual Electoral Bond Purchases: State and Party Distribution",
    align = "left",
    style = list(
      textDecoration = "underline",
      color = "#333333",
      fontWeight = "bold"
    )
  ) |>
  hc_subtitle(
    text = "Electoral bond encashment between Apr 16, 2019 and Jan 24, 2024"
  ) |>
  hc_credits(
    enabled = TRUE,
    text = "Heteroscedasticity",
    href = "https://asitavsen.com",
    style = list(fontSize = "12px")
  ) |>
  hc_legend(
    title = list(text = "Contribution Amount")
  ) |>
  hc_add_theme(custom_theme) |>
  hc_exporting(
    enabled = TRUE,
    filename = "StatePartyHeatmap"
  )

Organizations

Highest encashment by BJP. Highest purchasers also for BJP. Biggest purchase made by Megha Engineering & Infrastructure (Encashed by BJP) followed by Lakshmi Niwas Mittal (Encashed by BJP). Most purchases (value) were made in Telangana.

Code
# Calculate organizational contributions
org_party <- data.comb[
  organisation_or_individual == "Organisation"
][, .(
  total_amount = sum(amount), 
  count = .N
), by = standardised_political_party_name
][order(-total_amount)]

# Create combined visualization
highchart() |>
  hc_add_series(
    org_party,
    "column",
    hcaes(
      x = standardised_political_party_name,
      y = total_amount
    ),
    name = "Amount",
    dataLabels = list(
      enabled = FALSE
    )
  ) |>
  hc_add_series(
    org_party,
    "pie",
    hcaes(
      name = standardised_political_party_name,
      y = count
    ),
    name = "#Contributors",
    dataLabels = list(
      enabled = FALSE
    )
  ) |>
  hc_plotOptions(
    series = list(
      showInLegend = FALSE,
      colorByPoint = TRUE
    ),
    pie = list(
      center = c("75%", "25%"),
      size = 120,
      innerSize = "75%"
    )
  ) |>
  hc_yAxis(
    title = list(text = "Total Contribution (in billions)"), 
    labels = list(
      formatter = JS("
        function() { 
          return '₹' + (this.value/1000000000).toFixed(1) + 'B'; 
        }
      ")
    )
  ) |>
  hc_xAxis(
    categories = org_party$standardised_political_party_name,
    labels = list(rotation = -45)
  ) |>
  hc_tooltip(
    shared = FALSE,
    useHTML = TRUE,
    formatter = JS("
      function() {
        if (this.series.type === 'column') {
          return '<b>' + this.point.standardised_political_party_name + '</b><br>' +
                 'Amount: ₹' + (this.y/1000000000).toFixed(2) + 'B';
        } else if (this.series.type === 'pie') {
          return '<b>' + this.point.name + '</b><br>' +
                 'Contributors: ' + this.y;
        }
      }
    ")
  ) |>
  hc_title(
    text = "Electoral Bond Purchases by Organizations (Amount and Purchasers)",
    align = "left",
    style = list(
      textDecoration = "underline",
      color = "#333333",
      fontWeight = "bold"
    )
  ) |>
  hc_subtitle(
    text = "Electoral bond encashment between Apr 16, 2019 and Jan 24, 2024"
  ) |>
  hc_credits(
    enabled = TRUE, 
    text = "Heteroscedasticity",
    href = "https://asitavsen.com",
    style = list(fontSize = "12px")
  ) |>
  hc_add_theme(custom_theme) |>
  hc_exporting(
    enabled = TRUE,
    filename = "Amt by Organizations"
  )
Code
org_amount_count_by_party <- data.comb[organisation_or_individual == "Organisation"][, .(total_amount = sum(amount), count = length(unique(standardised_purchaser_name))), by = .(standardised_political_party_name)][, `:=`(avg = total_amount / count)][order(-avg)]

party_org_tot <- data.comb[organisation_or_individual == "Organisation"][, .(total_amount = sum(amount)), by = .(standardised_political_party_name, standardised_purchaser_name)]

party_org_top <- party_org_tot |>
  mutate(standardised_political_party_name = fct_other(standardised_political_party_name, keep = c("Indian National Congress", "Bharatiya Janata Party", "All India Trinamool Congress", "Bharat Rashtra Samithi", "Biju Janata Dal", "Dravida Munnetra Kazhagam")))

# Compute range difference without outliers for each party and reorder factor levels
party_order <- party_org_top |>
  group_by(standardised_political_party_name) |>
  summarise(range_diff = sum(total_amount)) |>
  arrange(desc(range_diff)) |>
  pull(standardised_political_party_name)
party_org_top$standardised_political_party_name <- factor(party_org_top$standardised_political_party_name, levels = party_order)

highchart() |>
  hc_add_series(
    data = party_org_top,
    type = "scatter",
    hcaes(x = "standardised_political_party_name", y = "total_amount", group = "standardised_political_party_name")
  ) |>
  hc_xAxis(
    type = "category",
    categories = party_order,
    labels = list(rotation = -45)
  ) |>
  hc_yAxis(
    title = list(text = "Amount (in billions)"), 
    labels = list(
      formatter = JS("function() { return '₹' + (this.value/1000000000).toFixed(1) + 'B'; }")
    )
  ) |>
  hc_title(
    text = "Top purchasers (Organizations) by party",
    align = "left",
    style = list(
      textDecoration = "underline",
      color = "#333333",
      fontWeight = "bold"
    )
  ) |>
  hc_subtitle(
    text = "Electoral bond encashment between Apr 16, 2019 and Jan 24, 2024"
  ) |>
  hc_plotOptions(
    scatter = list(
      color = "red",
      marker = list(
        radius = 4,
        symbol = "circle",
        lineWidth = 1
      ),
      jitter = list(x = .2, y = 0)
    )
  ) |>
  hc_legend(enabled = FALSE) |>
  hc_tooltip(
    formatter = JS("function(){
      return ('Purchaser: ' + this.point.standardised_purchaser_name + 
              '<br>Amount: ₹' + (this.point.total_amount/1000000000).toFixed(2) + 'B')
    }")
  ) |>
  hc_credits(
    enabled = TRUE, 
    text = "Heteroscedasticity",
    href = "https://asitavsen.com",
    style = list(fontSize = "12px")
  ) |>
  hc_add_theme(custom_theme) |>
  hc_exporting(
    enabled = TRUE,
    filename = "ContributorsOrg"
  )
Code
# First apply fct_other, then aggregate properly
party_org_state <- data.comb[
  organisation_or_individual == "Organisation"
][, `:=`(
  issue_branch_state = fct_other(
    issue_branch_state,
    keep = c("Maharashtra", "Delhi", "Odisha", "West Bengal", 
             "Telangana", "Tamil Nadu", "Gujrat","Karnataka"),
    other_level = "other_states"
  ),
  standardised_political_party_name = fct_other(
    standardised_political_party_name,
    keep = c("Indian National Congress", "Bharatiya Janata Party",
             "All India Trinamool Congress", "Bharat Rashtra Samithi",
             "Biju Janata Dal","Dravida Munnetra Kazhagam"),
    other_level = "other_parties"
  )
)][, .(total_amount = sum(amount)), 
   by = .(issue_branch_state, standardised_political_party_name)]  # This will properly aggregate all combinations

# Verify the aggregation
#print(party_org_state[issue_branch_state == "Telangana"])

# Order states by total amount
state_order <- party_org_state[, 
  .(state_total = sum(total_amount)), 
  by = issue_branch_state
][order(-state_total), issue_branch_state]



# Create ordered stacked column chart
hchart(
  party_org_state,
  "column", 
  hcaes(x = issue_branch_state, y = total_amount, 
        group = standardised_political_party_name)
) |>
  hc_xAxis(categories = as.character(state_order)) |>
  hc_plotOptions(series = list(stacking = "normal")) |>
  hc_tooltip(
    useHTML = TRUE,
    formatter = JS("
      function() {
        return '<b>' + this.point.issue_branch_state + '</b><br>' +
               this.point.standardised_political_party_name + ': ₹' +
               (this.y / 1000000000).toFixed(2) + 'B';
      }
    ")
  ) |>
  hc_yAxis(
    title = list(text = "Total Contribution (in billions)"),
    labels = list(
      formatter = JS("function() { return '₹' + this.value / 1000000000 + 'B'; }")
    )
  ) |>
  hc_title(
    text = "Purchase in States and parties by Individuals",
    align = "left",
    style = list(
      textDecoration = "underline",
      color = "#333333",
      fontWeight = "bold"
    )
  ) |>
  hc_subtitle(
    text = "Electoral bond encashment between Apr 16, 2019 and Jan 24, 2024"
  ) |>
  hc_credits(
    enabled = TRUE,
    text = "Heteroscedasticity",
    href = "https://asitavsen.com",
    style = list(fontSize = "12px")
  ) |>
  hc_add_theme(custom_theme) |>
  hc_exporting(
    enabled = TRUE,
    filename = "StateIOrg"
  )
Code
# Create heatmap with more colors and alphabetical party order
hchart(
  party_org_state,
  "heatmap",
  hcaes(x = standardised_political_party_name, 
        y = issue_branch_state,
        value = total_amount)
) |>
  hc_colorAxis(
    stops = list(
      list(0, "#FFFFFF"),     # White
      list(0.1, "#FFE5E5"),   # Very light red
      list(0.2, "#FFB3B3"),   # Lighter red
      list(0.3, "#FF8080"),   # Light red
      list(0.4, "#FF4D4D"),   # Medium light red
      list(0.5, "#FF1A1A"),   # Medium red
      list(0.6, "#E60000"),   # Medium dark red
      list(0.7, "#CC0000"),   # Dark red
      list(0.8, "#B30000"),   # Darker red
      list(0.9, "#990000"),   # Very dark red
      list(1, "#800000")      # Deepest red
    ),
    type = "linear",
    min = 1,
    max = max(party_org_state$total_amount),
    labels = list(
      formatter = JS("
        function() {
          return '₹' + (this.value/1000000000).toFixed(1) + 'B';
        }
      ")
    )
  ) |>
  hc_xAxis(
    categories = sort(unique(party_ind_state$standardised_political_party_name)),  # Alphabetical order
    title = list(text = "Political Party"),
    labels = list(rotation = -45)
  ) |>
  hc_yAxis(
    categories = as.character(state_order),  # Keeping states ordered by amount
    title = list(text = "State"),
    reversed = TRUE
  ) |>
  hc_tooltip(
    formatter = JS("
      function() {
        return '<b>' + this.point.issue_branch_state + 
               '</b><br>' + this.point.standardised_political_party_name + 
               '<br>₹' + (this.point.value/1000000000).toFixed(2) + 'B';
      }
    ")
  ) |>
  hc_title(
    text = "Organisational Electoral Bond Purchases: State and Party Distribution",
    align = "left",
    style = list(
      textDecoration = "underline",
      color = "#333333",
      fontWeight = "bold"
    )
  ) |>
  hc_subtitle(
    text = "Electoral bond encashment between Apr 16, 2019 and Jan 24, 2024"
  ) |>
  hc_credits(
    enabled = TRUE,
    text = "Heteroscedasticity",
    href = "https://asitavsen.com",
    style = list(fontSize = "12px")
  ) |>
  hc_legend(
    title = list(text = "Encashment Value")
  ) |>
  hc_add_theme(custom_theme) |>
  hc_exporting(
    enabled = TRUE,
    filename = "StateindHeatmap"
  )
Code
# Create a new dataframe with reduced parties
data_stream <- data.comb[, .(
    date = floor_date(date_of_encashment, "month"),
    party = fct_other(standardised_political_party_name,
                     keep = as.vector(amount_by_party$standardised_political_party_name[1:6]),
                     other_level = "Other Parties"),
    amount = amount
)]


# Create monthly data using data.table
all_dates <- seq.Date(
    from = floor_date(min(data_stream$date), "month"),
    to = floor_date(max(data_stream$date), "month"),
    by = "month"
)
all_parties <- unique(data_stream$party)

# Create complete grid and merge with data
monthly_data <- CJ(
    date = all_dates,
    party = all_parties
)[
    data_stream[, .(
        amount = sum(amount)
    ), by = .(date, party)],
    on = .(date, party)
][
    is.na(amount), amount := 0
]

# Define colors for parties
party_colors <- c("#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", 
                  "#FFEEAD", "#D4A5A5", "#9B59B6")

# Create the steamgraph
highchart() |>
    hc_chart(type = "streamgraph") |>
    hc_xAxis(
        type = "datetime",
        labels = list(
            format = "{value:%b %Y}"
        )
    ) |>
    hc_yAxis(
        visible = FALSE
    ) |>
    hc_colors(party_colors) |>  # Add distinct colors
    hc_add_series(
        data = monthly_data,
        hcaes(x = date, y = amount, group = party),
        type = "streamgraph"
    ) |>
    hc_plotOptions(
        series = list(
            label = list(
                minFontSize = 8,
                maxFontSize = 16
            )
        )
    ) |>
    hc_title(
        text = "Electoral Bond Encashment Over Time",
        align = "left",
        style = list(
            textDecoration = "underline",
            color = "#333333",
            fontWeight = "bold"
        )
    ) |>
    hc_subtitle(
        text = "Monthly amounts by political party"
    ) |>
    hc_tooltip(
        formatter = JS("
            function() {
                var amount = this.point.y;
                if (amount >= 1000000000) {
                    return '<b>' + this.series.name + '</b><br>' +
                           Highcharts.dateFormat('%b %Y', this.point.x) + '<br>₹' +
                           (amount/1000000000).toFixed(2) + 'B';
                } else {
                    return '<b>' + this.series.name + '</b><br>' +
                           Highcharts.dateFormat('%b %Y', this.point.x) + '<br>₹' +
                           (amount/1000000).toFixed(2) + 'M';
                }
            }
        ")
    ) |>
    hc_credits(
        enabled = TRUE,
        text = "Heteroscedasticity",
        href = "https://asitavsen.com",
        style = list(fontSize = "12px")
    ) |>
    hc_add_theme(custom_theme) |>
    hc_exporting(
        enabled = TRUE,
        filename = "ElectoralBondStream"
    )

Excluded Data

Code
DT::datatable(
    excluded_rows,
    options = list(
        pageLength = 5,          # Show only 5 rows per page
        dom = 'frtip',          # Remove length changing option
        scrollX = TRUE,         # Horizontal scroll if needed
        scrollY = '300px',      # Limit vertical height
        scrollCollapse = TRUE,  # Collapse empty space
        columnDefs = list(      # Limit column width
            list(
                targets = '_all',
                width = '150px'
            )
        )
    ),
    class = 'compact',          # Use compact styling
    rownames = FALSE,           # Remove row numbers
    filter = 'top'              # Add filters at top
) |>
    DT::formatStyle(            # Add compact styling
        columns = 1:ncol(excluded_rows),
        fontSize = '80%',       # Smaller font
        padding = '3px'         # Less padding
    )
Back to top