Bar chart with rotated x label for each bar

I’m having a hard time plotting a simple bar chart with Plots.jl that has a label below each bar. The data are stored in a DataFrame that looks like this:

julia> merged[:, [1,5,6]]
85×3 DataFrame
│ Row │ naics │ % of total estabs │ industry           │
│     │ Int64 │ Float64           │ String             │
├─────┼───────┼───────────────────┼────────────────────┤
│ 1   │ 113   │ 0.00112943        │ Forestry and Lo... │
│ 2   │ 114   │ 0.000362778       │ Fishing, Huntin... │
│ 3   │ 115   │ 0.00142785        │ Support Activit... │
│ 4   │ 211   │ 0.000947334       │ Oil and Gas Ext... │
⋮
│ 81  │ 721   │ 0.00863121        │ Accommodation      │
│ 82  │ 722   │ 0.0822932         │ Food Services a... │
│ 83  │ 811   │ 0.0277618         │ Repair and Main... │
│ 84  │ 812   │ 0.0297605         │ Personal and La... │
│ 85  │ 813   │ 0.0399547         │ Religious, Gran... │

I can achieve a plot that has vertical labels, but the labels don’t show up for every bar and there are other issues with the plot:

The other issues are that there is a space to the left and right of the first/last bars that I would like to eliminate and the labels aren’t centered under the bars.

The code to produce the above is:

bar(string.(merged[:, 1]), merged[:, 4], xrotation=90, legend=:topleft)

Any ideas?

Thanks!!

1 Like

Try setting xticks manually. I think something like xticks=minimum(df.naics):maximum(df.naics) (assuming that’s the column that provides the x values. Compare:

julia> df = DataFrame(idx=1:20, val = rand(20), label = [randstring(4) for _ in 1:20]);

julia> bar(df.idx, df.val)

julia> bar(df.idx, df.val, legend=false)

to

bar(df.idx, df.val, legend=false, xticks=1:20)

You can also set the labels to be strings:

bar(df.idx, df.val, legend=false, xticks=(1:20, df.label), xrotation=90)

As for centering text, I’m guessing it’s something with xfontvalign or xfonthalign, but I can’t figure it out. And for removing the spaces, take a look at the various framestyles, and I think there are arguments involving margins, but I don’t know for sure. See the bottom of this page for all the attributes you can play with.

Would be nice if the possible arguments for all of those attributes lived somewhere in the docs too.

3 Likes

This worked (except for the label alignment), thanks!

bar(
    string.(merged[:, 1]),
    merged[:, 4],
    xrotation=90,
    legend=:topleft,
    fillalpha=0.25,
    label="% of total estabs",
    xticks=(1:size(merged)[1], merged.naics)
)

I’m not sure that all the arguments listed as supported actually work. I’ve tried using the bottom_margin argument, for example, to no avail.

FYI, I was able to align the ticks to the center of the bars by doing this:

bar(
    string.(merged[:, 1]),
    merged[:, 4],
    xrotation=45, # changing the rotation to 45 degrees makes the labels look centered
    legend=:topleft,
    fillalpha=0.25,
    label="% of total estabs",
    xticks=(0.5:size(merged)[1], merged.naics) # notice I changed 1 to 0.5
)

For the labels, the 45-degree rotation isn’t an ideal solution, but it’ll do for now. :smiley:

3 Likes

If so, might be worth opening an issue.

Here is the VegaLite.jl version:

df |> @vlplot(:bar, x="idx:n", y=:val)

And that produces:
example

The trick is to configure the x axis as a nominal, not quant, scale by adding :n to the column name. For a nominal scale, it will print all values.

2 Likes