filled area line plot question

328 views
Skip to first unread message

Teddy Allen

unread,
Apr 16, 2021, 3:52:15 PM4/16/21
to idl-pvwave
Hello,
I am trying to plot a standard anomaly time series with the positive area (Y > 0) colored red and the negative area (Y < 0) colored blue. I have tried using both POLYGON and PLOT functions, but my problem is that I can't seem to get the colors to meet at y = 0. I understand that IDL 8.8 has a new FILLPLOT function, but I have an IDL 8.7 license. 
I am attaching two files: one all yellow filled time series and the same time series coloring only the negative values blue and only the positive values red. As you can see in the latter case, the negative and positive values do not meet at y = 0. 
Does anyone have experience making these plots? I could shift to a barplot, which is easy to color, but I aim to use a line plot. 


Thank you for any insights,
teddy 
test.png
test2.png

Ben C

unread,
Apr 20, 2021, 4:08:51 PM4/20/21
to idl-pvwave
I have experience making these exact plots, but I had hundreds or even thousands of data points so I actually had no idea that my plots were turning out like your plots, which are indeed wrong! It's only when using fairly few points do you notice more easily the polygons do not meet correctly. So thanks for that!

In any case, here is some example code below that corrects the issue. It's far from elegant and due to the heavy use of array concatenation, it could be very slow for "large" datasets. It runs fine in my test up to 1000 points. Maybe someone can improve it. 

;========BEGIN EXAMPLE CODE==========================

ireset,/no

npts = 30

;Example data #1 (random)
x = findgen(npts)
y = randomn(seed,npts)

;Example data #2 (sine wave)
;x = findgen(npts)
;y = sin(x*20*!PI/180)

;Calculate the position of all the locations where the line crosses the X-axis and create new plot data for drawing the polys
xNew = !null
yPos = !null
yNeg= !null
for i=0,n_elements(x)-1 do begin
  if i ne n_elements(x)-1 then begin
     slope = (y[i+1]-y[i])/(x[i+1]-x[i])
    if (y[i] gt 0 and y[i+1] lt 0)  then begin
      xNew=[xNew,x[i],(-y[i]/slope)+x[i]]
      yPos = [yPos,y[i],0]
      yNeg = [yNeg,0,0]
    endif else if (y[i] lt 0 and y[i+1] gt 0) then begin
      xNew=[xNew,x[i],(-y[i]/slope)+x[i]]
      yPos = [yPos,0,0]
      yNeg = [yNeg,y[i],0]
    endif else begin
      xNew = [xNew,x[i]]
      if y[i] gt 0 then yPos = [yPos,y[i]] else yPos = [yPos,0]
      if y[i] gt 0 then yNeg = [yNeg,0] else yNeg=[yNeg,y[i]]
    endelse
  endif else begin
    xNew = [xNew,x[i],x[i]]
    yPos = [yPos,y[i],0]
    yNeg = [yNeg,y[i],0]
  endelse
endfor

;Plot positive values first and fill red
plot1 = plot([xNew,reverse(xNew)],[yPos,intarr(n_elements(xNew))],ytitle='Normalized Anomaly',thick=3,$
font_size=15,yrange=[min(yNeg)-abs(min(yNeg))*.05,max(yPos)*1.05],linestyle=6,/FILL_BACKGROUND,FILL_COLOR='red',dimensions=[1700,800])

;Plot negative values second and fill blue
po1 = polygon([xNew,reverse(xNew)],[yNeg,intarr(n_elements(xNew))],/FILL_BACKGROUND,FILL_COLOR='blue',/DATA,target=plot1)

;Finish the plot with a solid black line and dots
finish = plot(x,y,thick=2,symbol='o',/SYM_FILLED,/overplot)

anom-plot.PNG

Teddy Allen

unread,
Apr 22, 2021, 9:48:14 PM4/22/21
to idl-pvwave
Bravo Ben! Thanks so much. This does the trick. I am glad my frustration alerted you to a hidden problem. But, even more glad that you had an easy solution. Much appreciated.
cheers,
teddy  

Ben C

unread,
Apr 23, 2021, 10:30:46 AM4/23/21
to idl-pvwave

You're welcome, Teddy. I did notice that in my code sometimes the very last data point can cause issues with the shading, depending on how it occurs relative to the points before it. There's a bug somewhere in there, but I wont be fixing it today. Good luck! 
Message has been deleted

Teddy Allen

unread,
Apr 27, 2021, 11:18:54 PM4/27/21
to idl-pvwave
While it may not exactly be "debugging", here is how I fixed the problem... I added 1 extra point to npts and then added a zero to the end of the y array. 

I simplified the above:
y = [karen_B,0.00]  ;karen_B ; this is the variable name for my data
npts = n_elements(karen_B)+1
x = findgen(npts))

Then, I added an xrange parameter to the "finish" plot. xrange=[0,npts-2]. It works. 
On Tuesday, April 27, 2021 at 10:46:45 PM UTC-4 Teddy Allen wrote:
Ah....just noticed this too. I'll try to sleuth it out. Thanks again. 

Ben C

unread,
May 6, 2021, 3:42:58 PM5/6/21
to idl-pvwave
Awesome. Thanks for sharing. I will update my routine for this much needed IDL functionality! 
Reply all
Reply to author
Forward
0 new messages