Adapting code from Plots into PlotlyJS

Hi,

Using Plots, I have a simple old piece of code to plot a function with a parameter assuming different values. I want to plot it using PlotlyJS. I know how to do it trace-by-trace, but that is ugly and inefficient. Help would be very much appreciated. In the example below, I can do without the LaTeXStrings output.

The MWE using Plots can be found below and its output.
Thanks

using Plots
using LaTeXStrings

f(c,σ) = (-1 + c^(1-σ))/(1-σ); 
util = plot(); 
    for σ = [0.1, 0.4, 0.8, 0.99, 1.5]
        plot!(util, [f(c, σ) for c ∈ 1:1:15]) 
    end
pC = plot(util, 
	label = [L"\sigma=0.1" L"\sigma=0.4" L"\sigma=0.8" L"\sigma=1" L"\sigma=1.5"], 
    	fg_legend = :transparent, legend = :top, 
    	xlabel = L"Consumption", ylabel = L"Utility")

aaa

This is a PlotlyJS version of your code:

using PlotlyJS
using LaTeXStrings
f(c,σ) = (-1 + c^(1-σ))/(1-σ)
x=1:15
σ = [0.1, 0.4, 0.8, 0.99, 1.5]

label = [L"\sigma=0.1", L"\sigma=0.4", L"\sigma=0.8",  L"\sigma=1", L"\sigma=1.5"] 
fig = Plot(Layout(width=700, legend=attr( x=0.35, y=0.95),
                  xaxis_title="Consumption",
                  yaxis_title="Utility"))
for (k, s)  in enumerate(σ)
    addtraces!(fig, scatter(x=x, y=f.(x, s), hovertemplate="consumption: %{x}<br>utility: %{y:.2f}<extra></extra>",
                            name=label[k], mode="lines"))
end 
display(fig)
1 Like

@empet, thank you so much for your help.

Your code works with perfection in Atom and VScode. Unfortunately, this is for teaching, and I need to use it inside Pluto. Pluto does not throw out any error, but the plot is nowhere to be seen. I am using @disberd turnaround to use PlotlyJS with Pluto. Thanks for your code; the problem rests with Pluto.

Yeah there are some conflicts between Pluto MathJax and Plotly MathJax, with more than one issue on the Pluto Repo.
Plotly started supporting MathJax 3 very recently but I have been doing some testing and it’s not so straightforward to make it work nicely with Pluto.

I am trying to find a fix and will post back if/when I manage :smiley:

1 Like

@disberd, thanks for your concerns. But do not worry; it is not very important. Actually, I know how to do it with individual traces.

The sad part of this story is that it seems complicated to understand why Pluto can use most plotting packages, but not PlotlyJS. PlotlyJS is currently one of the best plotting packages in the Julia environment. Not being available in Pluto’s plotting capabilities, it does not look like a good option as far as Julia is concerned. Without your contributions (which I find amazing), we could not use this package in an IDE … strictly developed for Julia.

@VivMendes you can now use PlutoPlotly.jl as replacement for PlotlyJS or PlotlyBase when directly working in Pluto.

This package basically creates a custom struct PlutoPlot that takes a Plot object from PlotlyBase/PlotlyJS as input and displays nicely and efficiently inside Pluto.

By using PlutoPlotly that is also in the General Registry, you don’t have to rely on pasting the original plotly hack from some time back on discourse, which is also quite outdated at the moment :smiley:

The package also exports a function that can force MathJax in Pluto to cache fonts locally, fixing the problem with latex not showing correctly from plolty inside Pluto.

That is not enabled by default, so if you want to use LaTeX you have to create a cell with the code force_pluto_mathjax_local(true).

Here is a picture of your example working almost unmodified inside a Pluto notebook:

And here is the notebook code for direct pasting for testing:

# ╔═╡ 403d5270-af5e-11ec-02ab-71b6376887cc
begin
	using PlutoPlotly
	using LaTeXStrings
end

# ╔═╡ 97c1c5d1-da17-4f00-8882-b72dcbba30b4
force_pluto_mathjax_local(true)

# ╔═╡ 705007d9-99c8-483c-900f-cab4e9682dc0
begin
f(c,σ) = (-1 + c^(1-σ))/(1-σ)
x=1:15
σ = [0.1, 0.4, 0.8, 0.99, 1.5]

label = [L"\sigma=0.1", L"\sigma=0.4", L"\sigma=0.8",  L"\sigma=1", L"\sigma=1.5"] 
fig = Plot(Layout(width=700, legend=attr( x=0.35, y=0.95),
                  xaxis_title="Consumption",
                  yaxis_title="Utility"))
for (k, s)  in enumerate(σ)
    addtraces!(fig, scatter(x=x, y=f.(x, s), hovertemplate="consumption: %{x}<br>utility: %{y:.2f}<extra></extra>",
                            name=label[k], mode="lines"))
end 
PlutoPlot(fig)
end
3 Likes

Great news. That is awesome. I have tested it already, and it looks beautiful and fast. Just a minor question: can we keep the general syntax of PlotlyJS (via PlotlyBase), or do we have to change it from case to case. For example, how do we save a plot? The old method:

import PlotlyJS:savefig plus savefig(my_plot, "my_plot.svg")

throws out:

MethodError: no method matching savefig(::PlutoPlotly.PlutoPlot, ::String)

Thanks for your contribution. As usual, great stuff.

For the moment add a cell with

PlotlyJS.savefig(p::PlutoPlot, args...) = savefig(p.Plot, args...) 

And your code should work, I’ll have to add saving functionality directly in PlutoPlotly in the next days