PlotlyJS: how to introduce shapes into time series?

Hi, I need to insert shapes into a time series using PlotlyJS, and name them. I know how to do it using Plots or PGFPlotsX. For example, what I want is something similar to the following plot, produced with PGFPlotsX after some raw LaTeX code passed into the script:

This material is for teaching, and the combination of Pluto and PlotlyJS looks perfect due to the interactivity that we may get even in static HTML files. I had no problem replicating the example that is available in the PlotlyJS documentation:

Unfortunately, I have failed to accomplish this particular need in PlotlyJS, even in the more archaic version of my demands (just the shapes). Nevertheless, I also need to name the different shapes (as in the first plot above). My example below is not working as intended because I am not correctly passing the type Date array into shapes, and after many twists, I still do not know how to do it.

MWE:

using PlotlyJS
using Dates
using MonthlyDates

My useless efforts surrounded this piece of code:

period10_5 = QuarterlyDate(1960, 1):Quarter(1):QuarterlyDate(2021,1)
y1 = randn(length(period10_5))
y2 = rand(length(period10_5))
#z = period10_5
	
trace00 = scatter(;x = Date.(period10_5), y = y1, 
		     name = "Shrek", mode="markers+lines",
		     marker_symbol = "circle", marker_size = "5", 
             line_width = 0.3 ,  marker_color = "Blue")
	
trace01 = scatter(;x = Date.(period10_5), y = y2, 
			 name = "Murphy", mode = "markers+lines",
			 marker_symbol = "circle",  marker_size = "5", line_width = 0.3, 
             marker_color = "Red")
	
shapes = rect(["period10_5[50]", "period10_5[70]"], ["period10_5[120]", "period10_5[150]"],
             0, 1 ;  fillcolor = "red", opacity = 0.2, line_width = 0,
             xref = period10_5, yref = "paper")
	
layout00 = Layout(;title_text = "Shapes, my shapes", title_x = 0.5,

			   shapes=shapes,
		
               xaxis = attr(
                	title = "Quarterly obervations",
                	tickformat = "%Y",
                	hoverformat = "%Y-Q%q",
                	tick0 = "1960/01/01",
                	dtick = "M120"),
		
        	    #xaxis_range = [1960, 2020],
        	    yaxis_title = "Percentage points",
        	    #yaxis_range=[-2, 2], 
        	    titlefont_size = 16)
	
plot([trace00, trace01], layout00)

This produces the following plot, but I am unable to get the shapes.

Some help will be very much appreciated. Thanks.

Your rectangle coordinates x0= "period10_5[50]", x1="period10_5[70]", are strings with no significance for plotly.js. They cannot be converted to the corresponding Date.

To get plotted your shapes, replace these strings by Date(period10_5[50]), etc.
But in this case the function rect doesn’t work and the two shapes are overlayed.

Instead,use the default definition of a rectangle https://plotly.com/javascript/reference/layout/shapes/,
i.e. replace your shape definition with:

common_attr = (fillcolor = "red", opacity = 0.2, line_width = 0,
               xref = period10_5, yref = "paper" )
shapes =[attr(type="rect", x0=Date(period10_5[50]), y0=0, x1= Date(period10_5[70]), y1=1; common_attr..., ), 
         attr(type="rect", x0=Date(period10_5[120]), y0=0, x1= Date(period10_5[150]), y1=1; common_attr...,)]

shapes

1 Like

Hi @empet, thank you very much for your quick reply. I could never get close to your solution, no way. It works very well.

In the meantime, I was desperately trying to come up with a way of solving the problem. I found a workaround that works as well, certainly a bit clumsy. It takes one more step than in your code. I have to covert an array of Date types (named as “Quarters”) in “my_df” into an array of strings:

my_strings = my_df[!,:Quarters] = string.(my_df[:,:Quarters])

Then I applied the same logic in the docs’s example, using the strings to define the rectangles I want.

my_strings = my_df[!,:Quarters] = string.(my_df[:,:Quarters]) # Date type into strings
period10_5 = QuarterlyDate(1960, 1):Quarter(1):QuarterlyDate(2021,1)
y1 = randn(length(period10_5))
y2 = rand(length(period10_5))
	
trace00 = scatter(;x = Date.(period10_5), y = y1, 
		      name = "Shrek", mode="markers+lines",
		      marker_symbol="circle", marker_size="5",line_width= 0.3, 
              marker_color = "Blue")
	
trace01 = scatter(;x = Date.(period10_5), y = y2, 
		      name = "Murphy", mode="markers+lines",
		      marker_symbol="circle", marker_size="5",line_width= 0.3, 
              marker_color = "Red")
	
shapes = rect(["1962-07-01", "2010-07-01"], ["1970-01-01", "2018-01-01"],
               0, 1; fillcolor = "gray", opacity = 0.2, line_width = 0,
               xref = my_strings, yref = "paper")
	
layout00 = Layout(; title_text = "Shapes, my shapes", title_x = 0.5,

		       shapes = shapes,
		
		       annotations = [attr(x = "1966-07-01", y = 2.5, showarrow = false,
				                     text = "QE1"), 
			                  attr(x = "2014-03-01", y = 2.5, showarrow = false, 
				                     text = "QE2") ],
		
            	xaxis = attr(
                	title = "Quarterly obervations",
                	tickformat = "%Y",
                	hoverformat = "%Y-Q%q",
                	tick0 = "1960/01/01",
                	dtick = "M120"),
		
                 #xaxis_range = [1960, 2020],
        	     yaxis_title = "Percentage points",
        	     #yaxis_range=[-2, 2], 
        	     titlefont_size = 16)
	
plot([trace00, trace01], layout00)

The plot looks like this:

Thanks a lot.

Sorry for one aside topic. Do you know how can I pass the following information available in the plotylyjs documentation into PlotlyJS:

textfont: {
    family: 'sans serif',
    size: 18,
    color: '#ff7f0e'
  },

I tried this, but it does not work (with many variations on the empty space in “sans serif”)::

textfont = [family = "sans serif",  size = 18, color = "#ff7f0e"],

For the issue above, the size of the textfont is not relevant. But sometimes, I need a larger font, and I do not know if it is possible to insert it into PlotlyJS.

Thanks.

textfont is a Dict:

textfont = Dict{Symbol, Any}(:family=>"sans serif",
                             :size=>18,
                             :color=>"#ff7f0e")

but inside a trace definition you can give it as an attr (attribute):

tr = scatter(x=1:5, y=rand(3:9, 5), mode="markers+text",
             text = ["Aaaa", "Bbbbbb", "Ccc", "abccc", "lmnop"],
             textfont =attr(family="sans serif",
                            size=18,
                            color="#ff7f0e"),
             textposition="top")
pl = plot(tr, Layout(width=600, height=500))
1 Like

@empet, Wonderful. Thank you very much.