Bar Charts in Julia

How to make Bar Charts in Julia with Plotly.


Bar chart with DataFrames

When creating bar charts using DataFrames, each row of the DataFrame is represented as a rectangular mark.

using PlotlyJS, CSV, DataFrames

df = dataset(DataFrame, "gapminder")
df_canada = df[df.country .== "Canada", :]

plot(df_canada, x=:year, y=:pop, kind="bar")

Bar chart with Long Format Data

Long-form data has one row per observation, and one column per variable. This is suitable for storing and displaying multivariate data i.e. with dimension greater than 2. This format is sometimes called "tidy".

using PlotlyJS, CSV, DataFrames

df = dataset(DataFrame, "medals")
long_df = stack(df, Not([:nation]), variable_name="medal", value_name="count")

plot(long_df, kind="bar", x=:nation, y=:count, color=:medal, Layout(title="Long-Form Input", barmode="stack"))
long_df

9 rows × 3 columns

nationmedalcount
StringStringInt64
1South Koreagold24
2Chinagold10
3Canadagold9
4South Koreasilver13
5Chinasilver15
6Canadasilver12
7South Koreabronze11
8Chinabronze8
9Canadabronze12

Bar chart with Wide Format Data

Wide-form data has one row per value of one of the first variable, and one column per value of the second variable. This is suitable for storing and displaying 2-dimensional data.

This form of data is less-well supported in Plotly"s Julia library. In order to use wide-form data, we reccomend constructing individual traces, one for each column:

using PlotlyJS, CSV, DataFrames

df = dataset(DataFrame, "medals")

plot(
    [bar(df, x=:nation, y=y, name=String(y)) for y in [:gold, :silver, :bronze]],
    Layout(title="Wide-Form Input")
)
df

3 rows × 4 columns

nationgoldsilverbronze
StringInt64Int64Int64
1South Korea241311
2China10158
3Canada91212

<!– ### Bar chart in Dash –>

Customize bar chart

The bar plot can be customized using keyword arguments.

using PlotlyJS, CSV, DataFrames

df = dataset(DataFrame, "gapminder")
df_canada = df[df.country .== "Canada", :]

plot(
    df_canada, x=:year, y=:pop, kind="bar",
    marker=attr(showscale=true, coloraxis="coloraxis", color=:lifeExp),
    Layout(
        yaxis_title_text="population of Canada",
        height=400,
        coloraxis_colorbar_title="life expectancy"
    )
)

When several rows share the same value of x (here Female or Male), the rectangles are grouped together by default

using PlotlyJS, CSV, DataFrames
df = dataset(DataFrame, "tips")
plot(df, x=:sex, y=:total_bill, color=:time, kind="bar")

Using the Layout.barmode property you can switch to stacked mode:

using PlotlyJS, CSV, DataFrames
df = dataset(DataFrame, "tips")
plot(df, x=:sex, y=:total_bill, color=:time, kind="bar", Layout(barmode="stack"))

Or you can choose to represent each observation as a small rectangle, stacked to form a larger bar using Layout.barmode = "relative"

using PlotlyJS, CSV, DataFrames
df = dataset(DataFrame, "tips")
plot(df, x=:sex, y=:total_bill, color=:time, kind="bar", Layout(barmode="relative"))

Basic Bar Chart with Julia arrays

If your data is not in a DataFrame, you can also use native Julia arrays to construct your bar charts

using PlotlyJS
animals = ["giraffes", "orangutans", "monkeys"]
plot(bar(x=animals, y=[20, 14, 23]))

Grouped Bar Chart

You can use relayout! to update the grouping behavior

using PlotlyJS
animals = ["giraffes", "orangutans", "monkeys"]

p = plot([
    bar(name="SF Zoo", x=animals, y=[20, 14, 23]),
    bar(name="LA Zoo", x=animals, y=[12, 18, 29])
])
relayout!(p, barmode="group")
p

Stacked Bar Chart

You can also set Layout.barmode when constructing the figure. Below is an example of stacked bars:

using PlotlyJS
animals = ["giraffes", "orangutans", "monkeys"]

p = plot([
    bar(name="SF Zoo", x=animals, y=[20, 14, 23]),
    bar(name="LA Zoo", x=animals, y=[12, 18, 29])
], Layout(barmode="stack"))

Bar Chart with Hover Text

using PlotlyJS

x = ["Product A", "Product B", "Product C"]
y = [20, 14, 23]
text = ["$x% market share" for x in [27, 25, 19]]
plot(bar(
    x=x, y=y, hovertext=text,
    marker=attr(color="rgb(158,202,225)", line_color="rgb(8,48,107)", line_width=1.5, opacity=0.6)
), Layout(title_text="January 2013 Sales Report"))

Bar Chart with Direct Labels

using PlotlyJS

x = ["Product A", "Product B", "Product C"]
y = [20, 14, 23]

# Use textposition="auto" for direct text
plot(bar(x=x, y=y, text=y, textposition="auto"))

Controlling text fontsize with uniformtext

If you want all the text labels to have the same size, you can use the uniformtext layout parameter. The minsize attribute sets the font size, and the mode attribute sets what happens for labels which cannot fit with the desired fontsize: either hide them or show them with overflow. In the example below we also force the text to be outside of bars with textposition.

using PlotlyJS, CSV, DataFrames

df = dataset(DataFrame, "gapminder")
df_smaller = df[(df.continent .== "Europe") .& (df.year .== 2007) .& (df.pop .> 2e6), :]
plot(
    df_smaller,
    y=:pop, x=:country, text=:pop, kind="bar",
    texttemplate="%{text:.2s}", textposition="outside",
    Layout(uniformtext_minsize=8, uniformtext_mode="hide")
)

Rotated Bar Chart Labels

using PlotlyJS, Random

months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
          "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]

plot([
     bar(x=months, y=rand(10:20, 12), name="Primary Product", marker_color="indianred"),
     bar(x=months, y=rand(0:30, 12), name="Secondary Product", marker_color="lightsalmon")
], Layout(barmode="group", xaxis_tickangle=-45))

Customizing Individual Bar Colors

using PlotlyJS

color_vec = fill("lightslategray", 5)
color_vec[2] = "crimson"

plot(
    bar(x='A':'E', y=[20, 14, 23, 25, 22], marker_color=color_vec),
    Layout(title_text="Least Used Feature")
)

Customizing Individual Bar Widths

using PlotlyJS

plot(bar(
    x=[1, 2, 3, 5.5, 10],
    y=[10, 8, 6, 4, 2],
    width=[0.8, 0.8, 0.8, 3.5, 4] # customize width here
))

Bar charts with custom widths can be used to make mekko charts (also known as marimekko charts, mosaic plots, or variwide charts).

using PlotlyJS

labels = ["apples","oranges","pears","bananas"]
widths = [10, 20, 20, 50]

data = Dict(
    "South" => [50,80,60,70],
    "North" => [50,20,40,30]
)

function make_trace(key)
    bar(
        name=key, y=data[key], x=cumsum(widths)-widths, width=widths,
        offset=0,
        customdata=permutedims([labels widths .* data[key]]),
        texttemplate="%{y} x %{width} =<br>%{customdata[1]}",
        textposition="inside",
        textangle=0,
        textfont_color="white",
        marker_line=attr(color="white", width=0.5),
        hovertemplate=join([
            "label: %{customdata[0]}",
            "width: %{width}",
            "height: %{y}",
            "area: %{customdata[1]}",
        ], "<br>")
    )
end
plot(
    make_trace.(keys(data)),
    Layout(
        title_text="Marimekko Chart",
        barmode="stack",
        uniformtext=attr(mode="hide", minsize=10),
        xaxis=attr(
            range=[0, 100], showgrid=true,
            tickvals=cumsum(widths) - widths / 2,
            ticktext=["$l<br>$w" for (l, w) in zip(labels, widths)],
        ),
        yaxis=attr(range=[0, 100], showgrid=true)
    )
)

Customizing Individual Bar Base

using PlotlyJS

years = 2016:2018
plot([
    bar(x=years, y=500:100:700, base=[-500, -600, -700], marker_color="crimson", name="expenses")
    bar(x=years, y=[300, 400, 700], base=0, marker_color="lightslategrey", name="revenue")
])

Bar Chart with Relative Barmode

With "relative" barmode, the bars are stacked on top of one another, with negative values below the axis, positive values above.

using PlotlyJS
x = [1, 2, 3, 4]

plot([
    bar(x=x, y=[1, 4, 9, 16])
    bar(x=x, y=[6, -8, -4.5, 8])
    bar(x=x, y=[-15, -3, 4.5, -8])
    bar(x=x, y=[-1, 3, -3, -4])
], Layout(barmode="relative", title_text="Relative Barmode"))

Bar Chart with Sorted or Ordered Categories

Set categoryorder to "category ascending" or "category descending" for the alphanumerical order of the category names or "total ascending" or "total descending" for numerical order of values. categoryorder for more information. Note that sorting the bars by a particular trace isn"t possible right now - it"s only possible to sort by the total values. Of course, you can always sort your data before plotting it if you need more customization.

This example orders the bar chart alphabetically with categoryorder: "category ascending"

using PlotlyJS

x = ["b", "a", "c", "d"]
plot([
    bar(x=x, y=[2,5,1,9], name="Montreal"),
    bar(x=x, y=[1, 4, 9, 16], name="Ottawa"),
    bar(x=x, y=[6, 8, 4.5, 8], name="Toronto"),
], Layout(barmode="stack", xaxis_categoryorder="category ascending"))

This example shows how to customise sort ordering by defining categoryorder to "array" to derive the ordering from the attribute categoryarray.

x = ["b", "a", "c", "d"]
plot([
    bar(x=x, y=[2,5,1,9], name="Montreal"),
    bar(x=x, y=[1, 4, 9, 16], name="Ottawa"),
    bar(x=x, y=[6, 8, 4.5, 8], name="Toronto"),
], Layout(barmode="stack", xaxis=attr(categoryorder="array", categoryarray=["d", "a", "c", "b"])))

This example orders the bar chart by descending value with categoryorder: "total descending"

using PlotlyJS

x = ["b", "a", "c", "d"]
plot([
    bar(x=x, y=[2,5,1,9], name="Montreal"),
    bar(x=x, y=[1, 4, 9, 16], name="Ottawa"),
    bar(x=x, y=[6, 8, 4.5, 8], name="Toronto"),
], Layout(barmode="stack", xaxis_categoryorder="total descending"))

Horizontal Bar Charts

See examples of horizontal bar charts here.

Bar Charts With Multicategory Axis Type

If your traces have arrays for x or y, then the axis type is automatically inferred to be multicategory.

using PlotlyJS
x = [
    ["BB+", "BB+", "BB+", "BB", "BB", "BB"],
    [16, 17, 18, 16, 17, 18,]
]
plot([
    bar(x=x, y=[1, 2, 3, 4, 5, 6]),
    bar(x=x, y=[6, 5, 4, 3, 2, 1]),
], Layout(barmode="relative"))