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:
Filling an area under curve until a x value
Use
plt.fill_between([0, 300, 800, 1800, 2200, 3500], P[:6], step='pre')
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:
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
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)
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()
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()
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.
Related Topics
Number of Significant Digits in Dplyr Summarise
How to Show Only Part of the Plot Area of Polar Ggplot with Facet
Install Rtools on R Version 3.0.2
How to Reorder a Legend in Ggplot2
Aggregate() Puts Multiple Output Columns in a Matrix Instead
Most Frequent Value (Mode) by Group
Ggplot, Drawing Multiple Lines Across Facets
Rbind Data Frames Based on a Common Pattern in Data Frame Name
From Data Table, Randomly Select One Row Per Group
Add Secondary X Axis Labels to Ggplot with One X Axis
Switch Displayed Traces via Plotly Dropdown Menu
How Convert Decimal to Posix Time
Get X-Value Given Y-Value: General Root Finding for Linear/Non-Linear Interpolation Function
How to Make Dodge in Geom_Bar Agree with Dodge in Geom_Errorbar, Geom_Point