sacrilego666
sacrilego666

Reputation: 51

Plotting DataFrames with Julia StatsPlots

This works:

StatsPlots.@df SYN_MM_BM_df plot(
    :t, 
    [:SYN_MM_BM_5, :SYN_MM_BM_10, :SYN_MM_BM_15, :SYN_MM_BM_30]
)

But this does not:

StatsPlots.@df SYN_MM_BM_df plot(
    :t,
    [Symbol(name) for name in names(SYN_MM_BM_df[2:5])]
)
Error: Cannot convert Symbol to series data for plotting

Although:

[Symbol(name) for name in names(SYN_MM_BM_df)[2:5]] ==
    [:SYN_MM_BM_5, :SYN_MM_BM_10, :SYN_MM_BM_15, :SYN_MM_BM_30

is true.

Can anyone explain why? I'd really like to not type all the symbols individually...

Upvotes: 5

Views: 1502

Answers (2)

Nils Gudat
Nils Gudat

Reputation: 13800

The reason for this is that @df is a macro, not a function, which means that it transforms the code you write into different code before any code is actually run. That is, it operates on the expression [Symbol(name) for name in names(df)[2:5]] before it actually gets evaluated (and thereby turned into [:SYN_MM_BM_5 ...].

To illustrate the difference, you can use @macroexpand (here in conjuction with prettify from MacroTools to make the output a bit more readable:

julia> using DataFrames, StatsPlots, MacroTools

julia> df = DataFrame(a = 1:10, b = 10 .* rand(10), c = 10 .* rand(10));

# Calling macro with symbols written out
julia> prettify(@macroexpand(@df df plot(:a, [:b, :c], colour = [:red :blue])))
:(((crane->begin
          ((rat, zebra, coyote, butterfly, starling), curlew) = (StatsPlots).extract_columns_and_names(crane, :a, :b, :c, :red, :blue)
          (StatsPlots).add_label(["a", "[b, c]"], plot, rat, [zebra, coyote], colour = [butterfly starling])
      end))(df))

# Calling macro with comprehension
julia> prettify(@macroexpand(@df df plot(:a, [x for x ∈ names(df)[2:3]], colour = [:red :blue])))
:(((crane->begin
          ((rat, zebra, coyote), butterfly) = (StatsPlots).extract_columns_and_names(crane, :a, :red, :blue)
          (StatsPlots).add_label(["a", "[x for x = (names(df))[23]]"], plot, rat, [x for x = (names(df))[2:3]], colour = [zebra coyote])
      end))(df))

As you see, the comprehension does not get picked up by the macro, and you therefore end up calling StatsPlots.extract_columns_and_names(df, :a, :red, :blue) instead of StatsPlots.extract_columns_and_names(df, :a, :b, :c, :red, :blue).

I see that Bogumil has already provided the solution to this as I was typing, looks like my StatsPlots was too slow to precompile :)

Upvotes: 4

Bogumił Kamiński
Bogumił Kamiński

Reputation: 69819

To work around the limitation that @Nils Gudat highlighted use cols (it treats its contents as a variable and expands it to columns) to get what you want (and use propertynames on data frame to get its column names as symbols directly):

julia> df = DataFrame(x=1:10, y=rand(10), z=rand(10));

julia> @df df plot(:x, cols(propertynames(df)[2:end]))

gives you: enter image description here

which is what I assume you want.

Upvotes: 4

Related Questions