Changing Line Color in Ggplot Based on Slope

Changing line color in ggplot based on slope

You haven't provided sample data, so here's a stylized example. The general idea is that you create a variable that tests whether the slope is greater than zero and then map that to a colour aesthetic. In this case, I use the dplyr chaining operator (%>%) in order to add the slope on the fly within the call to ggplot. (I went to the trouble of calculating the slope, but you could just as well test whether value[t==2] > value[t==1] instead.)

library(dplyr)

# Fake data
set.seed(205)
dat = data.frame(t=rep(1:2, each=10),
pairs=rep(1:10,2),
value=rnorm(20),
group=rep(c("A","B"), 10))

dat$value[dat$group=="A"] = dat$value[dat$group=="A"] + 6

ggplot(dat %>% group_by(pairs) %>%
mutate(slope = (value[t==2] - value[t==1])/(2-1)),
aes(t, value, group=pairs, linetype=group, colour=slope > 0)) +
geom_point() +
geom_line()

Sample Image

UPDATE: Based on your comment, it sounds like you just need to map number to an aesthetic or use faceting. Here's a facetted version using your sample data:

df = data.frame(number, formant, time, val)

# Shift val a bit
set.seed(1095)
df$val = df$val + rnorm(nrow(df), 0, 10)

ggplot (df %>% group_by(formant, number) %>%
mutate(slope=(val[time==99] - val[time==50])/(99-50)),
aes (x = time, y = val, linetype = formant, colour=slope > 0)) +
geom_point()+
geom_line(aes(group=interaction(formant, number))) +
facet_grid(. ~ number)

Sample Image

Here's another option that maps number to the size of the point markers. This doesn't look very good, but is just for illustration to show how to map variables to different "aesthetics" (colour, shape, size, etc.) in the graph.

ggplot (df %>% group_by(formant, number) %>% 
mutate(slope=(val[time==99] - val[time==50])/(99-50)),
aes (x = time, y = val, linetype = formant, colour=slope > 0)) +
geom_point(aes(size=number))+
geom_line(aes(group=interaction(formant, number)))

Changing line color in ggplot based on several factors slope

We can split apart the data, and get what you want:

#calculate slopes for I and II
dat %>%
filter(t != "III") %>%
group_by(pairs) %>%
# use diff to calculate slope
mutate(slope = diff(value)) -> dat12

#calculate slopes for II and III
dat %>%
filter(t != "I") %>%
group_by(pairs) %>%
# use diff to calculate slope
mutate(slope = diff(value)) -> dat23

ggplot()+
geom_line(data = dat12, aes(x = t, y = value, group = pairs, colour = slope > 0,
linetype = group))+
geom_line(data = dat23, aes(x = t, y = value, group = pairs, colour = slope > 0,
linetype = group))+
theme_bw()

Sample Image

Since the data in dat came sorted by t, I used diff to calculate the slope.

GGplot + Shiny changing a line color based off slope of line

Here is one solution, based on duplicating the rows where the current direction of yield changes.

library(data.table)
library(ggplot2)

# Set five_year_display as data.table
setDT(five_year_display)

#Order the five year display, and create an row identifier
five_year_display[order(Animal_ID, Date),rowid:=.I]

# Create a version that duplicates rows when the next row changes direction
fyd <- rbindlist(list(
five_year_display,
five_year_display[five_year_display[,dup_row:=sign(Yeild-shift(Yeild,-1))!=sign(shift(Yeild,1)-Yeild), by = Animal_ID][dup_row==TRUE, rowid]]
),idcol = "src")[order(Animal_ID, Date, src)]

# Function to set the colors, based on yield and rowid
# This function first finds the initial direction of the yield,
# sets the color for that direction, and then
# looks at the changes in row id to determine toggle in colors
find_colors <- function(yield, rowid) {
colors=as.numeric(yield[1]>=yield[2])
for(i in seq(2,length(rowid))) {
if(rowid[i]>rowid[i-1]) colors = c(colors, colors[i-1])
else colors = c(colors, 1-colors[i-1])
}
return(colors)
}

# Use function above to assign colors to each row
fyd[,colors:=find_colors(Yeild,rowid), by=Animal_ID]

# create a colorgrp over animal and color, using rleid
fyd[,colorgrp:=rleid(Animal_ID,colors)]

# plot the fyd using the colorgrp in geom_line, and manually setting the color scale
ggplot(fyd, aes(as.Date(Date), Yeild)) +
geom_point()+
geom_line(aes(group=colorgrp,color=factor(colors, labels=c("Increasing", "Decreasing")))) +
scale_color_manual(values=c("green", "red")) +
labs(x = "Date", color="Slope") +
theme(legend.position="bottom")

Here is the resulting plot

slopes with colors

Line color and width by slope in ggplot2

The trick is to calculate your slope for each line before plotting. To do this you can group by the time and item and then calculate the slope for each line.

data %>% 
tidyr::gather(variable, value, -id) %>%
tidyr::separate(variable, c("item", "time"), sep = "_T") %>%
dplyr::mutate(value = jitter(value, amount = 0.1)) %>% # Y-axis jitter to make points more readable
group_by(id,item) %>%
mutate(slope = (value[time==2] - value[time==1])/(2-1)) %>%
ggplot(aes(x = time, y = value, group = id)) +
geom_point(size = 1, alpha = .2, position = pd) +
geom_line(alpha = .2, position = pd, aes(color = slope)) +
scale_color_viridis_c(option = "inferno")+
ggtitle('Multiple indicator LCS model') +
ylab('Intrinsic motivation scores') +
xlab('Time points') +
facet_wrap("item")

Resulting in:

Sample Image

Line colour based on slope of line

Make the changes based on @Henrik but however create a function to calculate slope and then call it as

color = slope > 0

Your complete code as :-

library(shiny)
library(ggplot2)
ui <- fluidPage(
titlePanel("Creating a database"),
sidebarLayout(
sidebarPanel(
textInput("name", "Company Name"),
numericInput("income", "Income", value = 1),
numericInput("expenditure", "Expenditure", value = 1),
dateInput("date", h3("Date input"),value = Sys.Date() ,min = "0000-01-01",
max = Sys.Date(), format = "dd/mm/yy"),
actionButton("Action", "Submit"),#Submit Button
actionButton("new", "New")),

mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Table", tableOutput("table")),
tabPanel("Download",
textInput("filename", "Enter Filename for download"), #filename
helpText(strong("Warning: Append if want to update existing data.")),
downloadButton('downloadData', 'Download'), #Button to save the file
downloadButton('Appenddata', 'Append')),#Button to update a file )
tabPanel("Plot",
actionButton("filechoose", "Choose File"),
br(),
selectInput("toplot", "To Plot", choices =c("Income" = "inc",
"Expenditure" = "exp",
"Compare Income And
Expenditure" = "cmp",
"Gross Profit" = "gprofit",
"Net Profit" = "nprofit",
"Profit Lost" = "plost",
"Profit Percent" = "pp",
"Profit Trend" = "proftrend"

)),
actionButton("plotit", "PLOT"),
plotOutput("Plot")
)
)

)
)
)
# Define server logic required to draw a histogram
server <- function(input, output){
#Global variable to save the data
Data <- data.frame()
Results <- reactive(data.frame(input$name, input$income, input$expenditure,
as.character(input$date),
as.character(Sys.Date())))

#To append the row and display in the table when the submit button is clicked
observeEvent(input$Action,{
Data <<- rbind(Data,Results()) #Append the row in the dataframe
output$table <- renderTable(Data) #Display the output in the table
})

observeEvent(input$new, {
Data <<- NULL
output$table <- renderTable(Data)
})

observeEvent(input$filechoose, {
Data <<- read.csv(file.choose()) #Choose file to plot
output$table <- renderTable(Data) #Display the choosen file details
})

output$downloadData <- downloadHandler(
filename = function() {
paste(input$filename , ".csv", sep="")}, # Create the download file name
content = function(file) {
write.csv(Data, file,row.names = FALSE) # download data
})

output$Appenddata <- downloadHandler(
filename = function() {
paste(input$filename, ".csv", sep="")},
content = function(file) {
write.table( Data, file=file.choose(),append = T, sep=',',
row.names = FALSE, col.names = FALSE) # Append data in existing
})

observeEvent(input$plotit, {
inc <- c(Data[ ,2])
exp <- c(Data[ ,3])
date <- c(Data[,4])
gprofit <- c(Data[ ,3]- Data[ ,2])
nprofit <- c(gprofit - (gprofit*0.06))
plost <- gprofit - nprofit
pp <- (gprofit/inc) * 100
proftrend <- c(gprofit[2:34]-gprofit[1:33])
slope = c(((proftrend[2:33]-proftrend[1:32])/1),0)
y = input$toplot
switch(EXPR = y ,
inc = output$Plot <- renderPlot(ggplot(data = Data, aes(x= Data[,4], y= inc))+
geom_bar(stat = "identity",
fill = "blue")+xlab("Dates")+
ylab("Income")+
theme(axis.text.x = element_text(angle = 90))),
exp = output$Plot <- renderPlot(ggplot(data = Data, aes(x= Data[,4], y= exp))+
geom_bar(stat = "identity",
fill = "red")+xlab("Dates")+
ylab("Expenditure")+
theme(axis.text.x = element_text(angle = 90))),

cmp = output$Plot <- renderPlot(ggplot()+
geom_line(data = Data, aes(x= Data[,4], y= inc,
group = 1), col = "green")
+ geom_line(data = Data, aes(x= Data[,4], y= exp,
group =1), col = "red")+
xlab("Dates")+ ylab("Income (in lakhs)")+
theme(axis.text.x = element_text(angle = 90))),

gprofit = output$Plot <- renderPlot(ggplot(data = Data, aes(x= Data[,4], y= gprofit))+
geom_bar(stat = "identity",
fill = "blue")+xlab("Dates")+
ylab("Gross Profit (in lakhs)")+
theme(axis.text.x = element_text(angle = 90))),

nprofit = output$Plot <- renderPlot(ggplot(data = Data, aes(x= Data[,4], y= nprofit))
+geom_bar(stat = "identity",
fill = "blue")+xlab("Dates")+
ylab("Net Profit (in lakhs)")+
theme(axis.text.x = element_text(angle = 90))),

plost = output$Plot <- renderPlot(ggplot(data = Data, aes(x= Data[,4], y= plost))
+geom_bar(stat = "identity",
fill = "blue")+xlab("Dates")+
ylab("Profit Lost (in lakhs)")+
theme(axis.text.x = element_text(angle = 90))),

pp = output$Plot <- renderPlot(ggplot(data = Data, aes(x= Data[,4], y= pp))+
geom_bar(stat = "identity",
fill = "blue")+xlab("Dates")+
ylab("Profit Percentage")+
theme(axis.text.x = element_text(angle = 90))),
proftrend = output$Plot <- renderPlot(ggplot()+
geom_line(data = as.data.frame(date[2:34]),
aes(x= Data[c(2:34),4] , y= proftrend,
group = 1, color = slope > 0))+
xlab("Dates")+ ylab("Profit Trend")+
theme(axis.text.x = element_text(angle = 90))
)
)
}
)
}

# Run the application
shinyApp(ui = ui, server = server)

Color regression lines in geom_smooth depending on the slope of the underlying linear models

You could color by slope by mapping the condition slope > 0 on color. As this changes the default grouping we also have to add the group aesthetic to get a regression line for each Sequ:

library(dplyr)
library(ggplot2)

df %>%
group_by(Sequ) %>%
mutate(x = row_number()) %>%
mutate(slope = lm(pp ~ x)$coeff[2]) %>%
ggplot(aes(x = x, y = pp, color = slope > 0, group = factor(Sequ))) +
geom_smooth(method = "lm", se = FALSE) +
facet_wrap(. ~ Q, scales = 'free_x') +
theme(legend.position = "none")
#> `geom_smooth()` using formula 'y ~ x'

Sample Image

Changing the color of a geom_line based on a range. (THIS IS FOR THE PRODUCTION OF RESPIRATORS)

Off the top of my head, it is done quite literally the way you described it.

Add the colour criterion to the aesthetic:

# EDITED to add the group aesthetic
aes(x=SN, y=Actual, colour=(Actual >= 6.5896 & Actual <= 13.7996), group=1 )

Setting group aesthetic puts the points back into the same group, this needed for a continuous line, since the colour aesthetic splits them into two groups.

And then set the colour scale values to your desired values:

scale_colour_manual(values=c('red', 'green'))

TRUE and FALSE are ordered alphabetically when matched to colour values, so FALSE takes the first colour, TRUE takes the second colour

Change line color depending on y value with ggplot2

Calculate the smoothing outside ggplot2 and then use geom_segment:

fit <- loess(Rad_Global_.mW.m2. ~ as.numeric(fecha), data = datos.uvi, span = 0.3)
#note the warnings

new.x <- seq(from = min(datos.uvi$fecha),
to = max(datos.uvi$fecha),
by = "5 min")

new.y <- predict(fit, newdata = data.frame(fecha = as.numeric(new.x)))

DF <- data.frame(x1 = head(new.x, -1), x2 = tail(new.x, -1) ,
y1 = head(new.y, -1), y2 = tail(new.y, -1))
DF$col <- cut(DF$y1, c(-Inf, 250, 500, Inf))

ggplot(data=DF, aes(x=x1, y=y1, xend = x2, yend = y2, colour=col)) +
geom_segment(size = 2)

resulting plot

Note what happens at the cut points. If might be more visually appealing to make the x-grid for prediction very fine and then use geom_point instead. However, plotting will be slow then.



Related Topics



Leave a reply



Submit