Filling Area Under Curve Based on Value

Filling area under curve based on value

Per @baptiste's comment (since deleted) I would say this is the best answer. It is based on this post by Kohske. It adds new x-y pairs to the dataset at zero crossings, and generates the plot below:

# create some fake data with zero-crossings
yvals = c(2,2,-1,2,2,2,0,-1,-2,2,-2)
d = data.frame(x=seq(1,length(yvals)),y=yvals)

rx <- do.call("rbind",
sapply(1:(nrow(d)-1), function(i){
f <- lm(x~y, d[i:(i+1),])
if (f$qr$rank < 2) return(NULL)
r <- predict(f, newdata=data.frame(y=0))
if(d[i,]$x < r & r < d[i+1,]$x)
return(data.frame(x=r,y=0))
else return(NULL)
}))
d2 <- rbind(d,rx)
ggplot(d2,aes(x,y)) + geom_area(data=subset(d2, y<=0), fill="pink")
+ geom_area(data=subset(d2, y>=0), fill="lightblue") + geom_point()

Generates the following output:
example plot

Filling an area under curve until a x value

Use

plt.fill_between([0, 300, 800, 1800, 2200, 3500], P[:6], step='pre')

Sample Image


Note: it is slightly easier and more flexible if the x-steps were coded in a variable, not hardcoded as they are now in the P_Y list, or the list that calculates G_T. If these values were stored in a variable, you could use xvals[:5] + [3500] instead of the above list (you need the + [3500], since otherwise the last value would be 3600).

Fill area below curve and x-axis based on x-value in gnuplot

You don't write whether you have a function or a datafile.
Well, I was struggeling with limiting the range of the filledcurve.
Something like the following (which I would consider straightforward) doesn't work: (I still don't fully understand why). It gives a message warning: Ignoring sample range in non-sampled data plot and not the expected result (gnuplot 5.2.8).

plot [1950:2020] $Data u 1:2 w filledcurves x1 lc "red", \
[1940:2100] '' u 1:2 w l lw 2 lc "black"

So, instead I used the ternary operator to limit the filled xrange.

Code:

### fill below a part of a curve
reset session

# create some test data
f(x) = 2.5e5*(x-1900)**2
set table $Data
plot sample [1940:2100:5] '+' u 1:(f($1)) w table
unset table

unset key
set grid xtics, ytics front
set xrange [1940:2100]
set style fill solid 0.3

LimitRange(x,x0,x1) = x0<=x && x<=x1 ? x : NaN

plot $Data u (LimitRange($1,1950,2020)):2 w filledcurves x1 lc "red", \
'' u 1:2 w l lw 2 lc "black"
### end of code

Result:

Sample Image

How to fill the area under/above the curve with different colors above and below 0?

OP, what you are observing are the artifacts related to the resolution of your graphics driver and the space between columns. The areas you show are composed of many filled columns next to one another on the x axis. You do not specify the width= argument for geom_col(), so the default value leaves a space between the individual values on the x axis. It's best to illustrate if we take only a section of your data along the x axis:

ggplot(data = df, aes(x = ID, y = SPI)) +
geom_col(data = df[SPI <= 0], fill = "red") +
geom_col(data = df[SPI >= 0], fill = "blue") +
theme_bw() +
xlim(0,100) # just the first part on the left

Sample Image

There's your white lines - it's the space bewtween the columns. When you have the larger picture, the appearance of the white lines has to do with the resolution of your graphics device. You can test this if you save your graphic with ggsave() using different parameters for dpi=. For example, on my computer saving ggsave('filename.png', dpi=72) gives no lines, but ggsave('filename.png', dpi=600) shows the white lines in places.

There's an easy solution to this though, which is to specify the width= argument of geom_col() to be 1. Be default, it's set to 0.75 or 0.8 (not exactly sure), which leaves a gap between the next value (fills ~75 or 80% of the space). If you set this to 1, it fills 100% of the space allotted for that column, leaving no white space in-between:

ggplot(data = df, aes(x = ID, y = SPI)) +
geom_col(data = df[SPI <= 0], fill = "red", width=1) +
geom_col(data = df[SPI >= 0], fill = "blue", width=1) +
theme_bw() +
xlim(0,100)

Sample Image

Filling area under the curve with matplotlib

There is such a function:
matplotlib.pyplot.fill_between()

import matplotlib.pyplot as plt

plt.plot(y, c='red')
plt.fill_between(y.index, y, color='blue', alpha=0.3)

Gradient fill area under curve

The following should be close to what you're looking for. The trick is to use scale_color_identity for the geom_segment, and passing to the color aesthetic an RGB string that represents each wavelength in your data frame.

ggplot(bq, aes(x=w.length, y=s.e.irrad)) +
geom_segment(aes(xend=w.length, yend=0, colour = nm_to_RGB(w.length)),
size = 1) +
geom_line() +
scale_colour_identity()

Sample Image

Or if you want a more muted appearance:

ggplot(bq, aes(x=w.length, y=s.e.irrad)) +
geom_area(fill = "black") +
geom_segment(aes(xend=w.length, yend=0,
colour = nm_to_RGB(w.length)),
size = 1, alpha = 0.3) +
geom_line() +
scale_colour_identity()

Sample Image

The only drawback being that you need to define nm_to_RGB: the function that converts a wavelength of light into a hex-string to represent a color. I'm not sure there's a "right" way to do this, but one possible implementation (that I translated from the javascript function here) would be:

nm_to_RGB <- function(wavelengths){
sapply(wavelengths, function(wavelength) {
red <- green <- blue <- 0
if((wavelength >= 380) & (wavelength < 440)){
red <- -(wavelength - 440) / (440 - 380)
blue <- 1
}else if((wavelength >= 440) & (wavelength<490)){
green <- (wavelength - 440) / (490 - 440)
blue <- 1
}else if((wavelength >= 490) && (wavelength<510)){
green <- 1
blue = -(wavelength - 510) / (510 - 490)
}else if((wavelength >= 510) && (wavelength<580)){
red = (wavelength - 510) / (580 - 510)
green <- 1
}else if((wavelength >= 580) && (wavelength<645)){
red = 1
green <- -(wavelength - 645) / (645 - 580)
}else if((wavelength >= 645) && (wavelength<781)){
red = 1
}
if((wavelength >= 380) && (wavelength<420)){
fac <- 0.3 + 0.7*(wavelength - 380) / (420 - 380)
}else if((wavelength >= 420) && (wavelength<701)){
fac <- 1
}else if((wavelength >= 701) && (wavelength<781)){
fac <- 0.3 + 0.7*(780 - wavelength) / (780 - 700)
}else{
fac <- 0
}
do.call(rgb, as.list((c(red, green, blue) * fac)^0.8))
})
}

Obviously, I don't have your data set, but the following code creates a plausible set of data over the correct ranges:


Data

set.seed(10)

bq <- setNames(as.data.frame(density(sample(rnorm(5, 600, 120)))[c("x", "y")]),
c("w.length", "s.e.irrad"))

bq$s.e.irrad <- bq$s.e.irrad * 1e5

Matplotlib fill area under curve between two x values only

This error occurred because

x > -3 and x < -2

is an ambiguous numpy expression, so it raises the error. Instead you want

(x > -3) & (x < -2)

Other options are to use logical_and or bitwise_and (or even * should work).

Fill area under time series based on factor value

Okay, here is what I did to get the graph shown below if that is what you want.

# -------------------------------------------------------------------------

# load required packages #

library(scales)
library("ggplot2")
library(dplyr)

# -------------------------------------------------------------------------
# load the data to a df #
plot.timeseries <- get(load("TimeSeries_Data.RData"))

# -------------------------------------------------------------------------

# transform the data (my_fill_color will have green and NA values)
my_object <- plot.timeseries %>%
select(Price, Index, Date) %>%
mutate(Index_ord_factor = factor(Index, levels = unique(Index), ordered=TRUE),
my_fill_color = case_when(
Index_ord_factor > 0 ~ "green" # ordered factor enables the '>' operation
))

# -------------------------------------------------------------------------

# Plot your graph using the transformed data

ggplot(my_object, mapping = aes(x=Date, y=Price)) +
geom_line(aes(color = Index, group = 1))+
geom_col(fill =my_object$my_fill_color, width = 1)

# -------------------------------------------------------------------------


Let me know if you need elaboration to understand the script. Attached is the output in my end.
Fill area under time series based on factor value



Related Topics



Leave a reply



Submit