I'm a massive Rstudio novice so I have scoured the related questions etc. but I am still having trouble with organising my graph properly. I am having trouble getting my graph to show dates in the correct, chronological order. Wondering if I could get someone to have a look at my code and data and see what i'm doing wrong (explained very simply please, I am a novice).
I am currently reading in a CSV file, which is set up like this 1:
AdD = date sample taken, AdT = time sample taken, AdV = Concentration value - these are water samples and only consist of these two samples across the two months (one per month)
and I get the graph:
The graph shows the 5th month first on the x axis, when I want it in chronological order (aka April - 4th month) to appear first.
My code is as follows (please disregard the geom_hline and axis elements blank - this is one of 6 graphs in a facet and those aren't relevant to the date problem I think/hope) :
F1ambH <- read_csv("data 1 Amb.csv")
f1ambH <- ggplot(data=F1ambH, aes(x=AhD, y=AhV))+ geom_point() +theme_bw()+labs(y= "Concentration (µg/L)", x = "Sample Date")
f1ambH <- f1ambH + geom_hline(yintercept=1.1, linetype="dashed", color="steelblue")+ theme(axis.title.x = element_blank())+ theme(axis.title.y = element_text(face = "bold", size = 11))
f1ambH
I have also tried mutating the data like this:
F1ambH <- read_csv("data 1 Amb.csv") %>% mutate(dates = dmy(AhD))
f1ambH <- ggplot(data=dates, aes(x=AhD, y=AhV))+ geom_point() +theme_bw()+labs(y= "Concentration (µg/L)", x = "Sample Date")
which produces this graph:
Which shows the dates correctly, but the two points on the graph don't have a corresponding x axis tick which I need (of which I feel like ive exhausted my options in trying to fix
so if I can fix either problem then that would be amazing.
EDT:
Using the +scale_x_date(breaks=unique(F1ambH$dates)) as suggested by the first comment seems to solve my problem, but the points are now at the opposite side of the graph and look horrendous, is there a way to clean it up?
Figure
Use your second solution, but use
+scale_x_date(breaks=unique(dates))
to specify where you want the breakpoints.
If you make x variable as factor and add it before plot, it keeps the order:
F1ambH$AhD <- factor(F1ambH$AhD,levels=unique(F1ambH$AhD),order=TRUE)
f1ambH <- ggplot(data=F1ambH, aes(x=AhD, y=AhV))+ geom_point() +theme_bw()+labs(y=
"Concentration (µg/L)", x = "Sample Date")
f1ambH <- f1ambH + geom_hline(yintercept=1.1, linetype="dashed", color="steelblue")+
theme(axis.title.x = element_blank())+ theme(axis.title.y = element_text(face =
"bold", size = 11))
f1ambH
Even you can have any order you prefer:
F1ambH$AhD <- factor(F1ambH$AhD,levels=c(your preference order),order=TRUE)
Related
I have the following dataset:-
The images provide details to the dataset. They are the sales of a company and the type column has two entries-Store and Online.
I am supposed to create a line graph and show the sales of the company as two different lines on the same line graph for both store and online sales. However, I am getting erroneous results and cannot understand how to bifurcate the data into two types and then create the graph.
The code I have used thus far is just what I wrote to try and understand what results in what as I am a beginner at R. The following is the code which gives an erroneous line graph:-
figure <-ggplot(Amazing_retail.df, aes(year_month,Sales))+
geom_line(color='blue')+
xlab("Year_Month")+
ylab("Total Sales")+
ggtitle("Monthwise Sales for the Years 2010-11")
figure
Thus, what can I do get the appropriate result i.e. the online and store sales for the company on the same line graph.
[1]: https://i.stack.imgur.com/zjUbj.jpg
Amazing_retail.df <- data.frame( year_month = rep(1:12, 2),
sales_type = c(rep("online", 12), rep("shop", 12)),
Sales = sample(100000:200000, 24))
ggplot(Amazing_retail.df, aes(x = year_month, y = Sales)) +
geom_line(aes(color = sales_type, linetype = sales_type)) +
scale_color_manual(values = c("red", "blue")) +
xlab("Year_Month")+
ylab("Total Sales")+
ggtitle("Monthwise Sales for the Years 2010-11")
I've got a bar graph whose variable labels (a couple of them) need changing. In the specific example here, I've got a variable "Sputum.Throat" which refers to samples which could be either sputum or throat swabs, so the label for this value should really read "Sputum/Throat" or even "Sputum or Throat Swab" (this latter would only work if I can wrap the text). So far, no syntax I've tried can pull this off.
Here's my code:
CultPerf <- data.frame(Blood=ForAnalysis$Cult_lastmo_blood, CSF=ForAnalysis$Cult_lastmo_csf, Fecal=ForAnalysis$Cult_lastmo_fecal, Genital=ForAnalysis$Cult_lastmo_genital, `Sputum-Throat`=ForAnalysis$`Cult_lastmo_sput-throat`, Urine=ForAnalysis$Cult_lastm_urine, `Wound-Surgical`=ForAnalysis$`Cult_lastmo_wound-surg`, Other=ForAnalysis$Cult_lastmo_oth)
CP <- data.table::melt(CultPerf, variable.names("Frequency"))
CP$value <- factor(CP$value, levels=c(">100","50-100","25-50","0-25"))
CP$variable <- factor(CP$variable, levels = c("Other","Wound.Surgical","Urine","Sputum.Throat","Genital","Fecal","CSF","Blood"))
ggplot(data=CP)+
geom_bar(aes(x=variable, fill = value), position="dodge", width = 0.9)+
labs(x="Culture Type", y="Number of Labs", title="Number of Cultures Performed Per Month at Study Hospitals", subtitle="n=140")+
coord_flip()+
theme(legend.title = element_blank(),aspect.ratio = 1.25/1,plot.subtitle=element_text(face="italic",hjust=0.5),plot.title=element_text(hjust=0.5))+
guides(fill = guide_legend(reverse = TRUE))
And for reference, here's a copy of the successful plot which it does produce:
As I mentioned, all I want to do is change those labels of the individual values on the Y axis. Any suggestions will be appreciated!
If you want to just change the axis label for that one category, try adding in this line
scale_x_discrete(labels=c("Sputum.Throat"="Sputum/Throat"))
be sure to add it (+) to your ggplot object.
Using the helpful suggestion from #MrFlick above (with my thanks), I added the following to my ggplot code, which also gave me a word-wrapped label for the second label:
scale_x_discrete(labels=c("Sputum.Throat"="Sputum/Throat", "Wound.Surgical"="Surgical or \n Other Wound"))+
Resultant plot looks like this:
Revised plot
This is a relatively straightforward question, however, I was unable to find an answer. Likewise, I am not used to posting at Stackoverflow so I apologise for any kind of errors.
I currently have a Multiplot Facet that displays the variation in animal activity (Y) and day length on a seasonal level (in this case, two seasons).
As you see on the X axis, there are numbers such as 0.45, 0.47, etc. These represent time in numeric form. The issue is, is that I would like to convert 0.45 and etc to hours (it should be noted that they are not represented as dates). That is, 0.45 should represent 10, 0.47 should represent 10.2 etc. While I attempted to manually do this in excel...the scatter plots are well..not very scattered when plotting them. That is, I simply converted 10:02:00 to 10.2 (therefore, they do not represent actual dates in R)
Is there a way to either
1. manually change the numeric daylength (i.e. 0.45) to the hours that they represent?
2. Shorten the tick marks for the actual hours for both facets so that they do not seemed as scattered?
Likewise, is all of this possible while keeping both facets in place?
Here is the script that I use for the plot:
ii$season = factor(ii$season, levels = c("Winter","Summer"))
ii <- ii%>%
mutate(season = ifelse(month2 %in% c( 6,7, 8), "Winter",
ifelse(month2 %in% c(12,1,2), "Summer","Error")))
Plot <- ggplot(ii, aes(daylength, newavx2)) +
geom_point() + geom_smooth()+
ggtitle("Activity and Daylength by Season") +
xlab("Daylength") + ylab("Activity") +
theme(plot.title = element_text(lineheight=.8, face="bold",size = 20)) +
theme(text = element_text(size=18))
Plot + facet_grid(.~season, scales = "free_x") +
theme(strip.background = element_blank())
It should be noted that for the second plot, the variable daylength is simply replaced by 'hours' Thank you so much for your help
This question already has answers here:
Keep unused levels in bar plot
(4 answers)
Closed 7 years ago.
This is somehow related to R+ggplot+geom_bar+scale_x_continuous+limits: leftmost and rightmost bars not showing on plot but I decided to do a different post because of the different question.
I need to create two different versions of plots from a dataset: one containing all values for a specific column and other with filtered values. I guess it is easier to see that considering my data frame:
consts = paste('"Category","Year","Name","Quantity"\n',
'SHEEP,2003,Alice,10\n',
'SHEEP,2005,Alice,3\n',
'SHEEP,2008,Alice,2\n',
'SHEEP,2009,Alice,1\n',
'SHEEP,2012,Alice,3\n',
'CACTUS,1997,Bob,45\n',
'CHICKEN,1997,Bob,6\n',
'SHEEP,1998,Bob,2\n',
'SHEEP,2005,Bob,5\n',sep = "")
data <- read.csv(text=consts,header = TRUE)
Suppose I need to see how many animals (and vegetables :-) were sheared by year.
To reuse code I wrote a function that receives as parameters the data set and an optional name, and plots the data as a stacked bar with Year as the X axis, Quantity as the Y axis and using Category to create the different parts of the stack. The function is:
# Plot either all data or select by name.
doPlot <- function(data,name=character(0)) {
# If we pass a name as parameter we need to change the output file name, the plot title
# and subset the data.
fname = sprintf("Performance.png")
title = "Performance"
if(length(name)!=0) {
fname = sprintf("Performance-%s.png",name)
title = paste(title," - ",name)
data <- subset(data,Name == name)
}
byYear <- aggregate(Quantity ~ Year+Category, data, sum)
byYear = ddply(byYear, "Year", mutate, label_y = cumsum(Quantity))
png(filename=fname,width = 960, height = 640)
g <- ggplot(byYear, aes(x=Year,y=Quantity))
g <- g + geom_bar(stat="identity",aes(fill=Category), colour="black") +
ggtitle(title) +
scale_fill_discrete("Category",labels=c("Sheep","Cactus","Chicken"),c=45, l=80)+
scale_x_continuous(name="Year", limits=c(1996,2013), breaks=seq(1996,2013,1)) +
mytheme+
geom_text(aes(label=Quantity,y=label_y), vjust=1.3,size=6)
print(g)
dev.off()
}
If you want to reproduce the plots you will also need some constants for the
theme:
# Colors and themes for the plot
goodBlue <- "#7fbfff"
darkBlue <- "#3f5f7f"
mytheme <- theme(plot.title = element_text(color=darkBlue,face="bold",size=20),
axis.title.x = element_text(color=darkBlue,face="bold",size=16),
axis.title.y = element_text(color=darkBlue,face="bold",size=16),
axis.text.x = element_text(color=darkBlue,face="bold",size=14),
axis.text.y = element_text(color=darkBlue,face="bold",size=12),
legend.title = element_text(color=darkBlue,face="bold",size=18),
legend.text = element_text(color=darkBlue,face="bold",size=12))
Calling
doPlot(data)
Gives the following plot:
Not exactly what I want: note that the first category was labeled "Sheep"!
I cannot get the desired results when I filter and plot the data with a call to:
doPlot(data,"Alice")
Here is the plot:
Legends/colors are correct: all Alice ever sheared were sheeps.
What I wanted was:
Ensure that every plot have the same caption, in the order I want
them to appear (Sheeps, Cactus, Chicken) with the correct colors on
the caption and bars;
Ensure that the caption will appear with all entries even if they
are not present in the data being plotted. E.g., in the second plot
I will have the same legend as in the first (readers would notice
that Cactus/Chicken were part of the data but Alice didn't sheared
any).
thanks in advance
EDIT: I can solve item 1 by enforcing an order to the factors:
data$Category <- factor(data$Category, levels = c("SHEEP", "CACTUS", "CHICKEN"))
The first plot then becomes:
Grr, found the answer. Just add DROP=FALSE to the line
scale_fill_discrete("Category",labels=c("Sheep","Cactus","Chicken"),drop=FALSE,c=45, l=80)
Here is the result. Answering myself so hopefully others may benefit.
Main Question
I'm having issues with understanding why the handling of dates, labels and breaks is not working as I would have expected in R when trying to make a histogram with ggplot2.
I'm looking for:
A histogram of the frequency of my dates
Tick marks centered under the matching bars
Date labels in %Y-b format
Appropriate limits; minimized empty space between edge of grid space and outermost bars
I've uploaded my data to pastebin to make this reproducible. I've created several columns as I wasn't sure the best way to do this:
> dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)
> head(dates)
YM Date Year Month
1 2008-Apr 2008-04-01 2008 4
2 2009-Apr 2009-04-01 2009 4
3 2009-Apr 2009-04-01 2009 4
4 2009-Apr 2009-04-01 2009 4
5 2009-Apr 2009-04-01 2009 4
6 2009-Apr 2009-04-01 2009 4
Here's what I tried:
library(ggplot2)
library(scales)
dates$converted <- as.Date(dates$Date, format="%Y-%m-%d")
ggplot(dates, aes(x=converted)) + geom_histogram()
+ opts(axis.text.x = theme_text(angle=90))
Which yields this graph. I wanted %Y-%b formatting, though, so I hunted around and tried the following, based on this SO:
ggplot(dates, aes(x=converted)) + geom_histogram()
+ scale_x_date(labels=date_format("%Y-%b"),
+ breaks = "1 month")
+ opts(axis.text.x = theme_text(angle=90))
stat_bin: binwidth defaulted to range/30. Use 'binwidth = x' to adjust this.
That gives me this graph
Correct x axis label format
The frequency distribution has changed shape (binwidth issue?)
Tick marks don't appear centered under bars
The xlims have changed as well
I worked through the example in the ggplot2 documentation at the scale_x_date section and geom_line() appears to break, label, and center ticks correctly when I use it with my same x-axis data. I don't understand why the histogram is different.
Updates based on answers from edgester and gauden
I initially thought gauden's answer helped me solve my problem, but am now puzzled after looking more closely. Note the differences between the two answers' resulting graphs after the code.
Assume for both:
library(ggplot2)
library(scales)
dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)
Based on #edgester's answer below, I was able to do the following:
freqs <- aggregate(dates$Date, by=list(dates$Date), FUN=length)
freqs$names <- as.Date(freqs$Group.1, format="%Y-%m-%d")
ggplot(freqs, aes(x=names, y=x)) + geom_bar(stat="identity") +
scale_x_date(breaks="1 month", labels=date_format("%Y-%b"),
limits=c(as.Date("2008-04-30"),as.Date("2012-04-01"))) +
ylab("Frequency") + xlab("Year and Month") +
theme_bw() + opts(axis.text.x = theme_text(angle=90))
Here is my attempt based on gauden's answer:
dates$Date <- as.Date(dates$Date)
ggplot(dates, aes(x=Date)) + geom_histogram(binwidth=30, colour="white") +
scale_x_date(labels = date_format("%Y-%b"),
breaks = seq(min(dates$Date)-5, max(dates$Date)+5, 30),
limits = c(as.Date("2008-05-01"), as.Date("2012-04-01"))) +
ylab("Frequency") + xlab("Year and Month") +
theme_bw() + opts(axis.text.x = theme_text(angle=90))
Plot based on edgester's approach:
Plot based on gauden's approach:
Note the following:
gaps in gauden's plot for 2009-Dec and 2010-Mar; table(dates$Date) reveals that there are 19 instances of 2009-12-01 and 26 instances of 2010-03-01 in the data
edgester's plot starts at 2008-Apr and ends at 2012-May. This is correct based on a minimum value in the data of 2008-04-01 and a max date of 2012-05-01. For some reason gauden's plot starts in 2008-Mar and still somehow manages to end at 2012-May. After counting bins and reading along the month labels, for the life of me I can't figure out which plot has an extra or is missing a bin of the histogram!
Any thoughts on the differences here? edgester's method of creating a separate count
Related References
As an aside, here are other locations that have information about dates and ggplot2 for passers-by looking for help:
Started here at learnr.wordpress, a popular R blog. It stated that I needed to get my data into POSIXct format, which I now think is false and wasted my time.
Another learnr post recreates a time series in ggplot2, but wasn't really applicable to my situation.
r-bloggers has a post on this, but it appears outdated. The simple format= option did not work for me.
This SO question is playing with breaks and labels. I tried treating my Date vector as continuous and don't think it worked so well. It looked like it was overlaying the same label text over and over so the letters looked kind of odd. The distribution is sort of correct but there are odd breaks. My attempt based on the accepted answer was like so (result here).
UPDATE
Version 2: Using Date class
I update the example to demonstrate aligning the labels and setting limits on the plot. I also demonstrate that as.Date does indeed work when used consistently (actually it is probably a better fit for your data than my earlier example).
The Target Plot v2
The Code v2
And here is (somewhat excessively) commented code:
library("ggplot2")
library("scales")
dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)
dates$Date <- as.Date(dates$Date)
# convert the Date to its numeric equivalent
# Note that Dates are stored as number of days internally,
# hence it is easy to convert back and forth mentally
dates$num <- as.numeric(dates$Date)
bin <- 60 # used for aggregating the data and aligning the labels
p <- ggplot(dates, aes(num, ..count..))
p <- p + geom_histogram(binwidth = bin, colour="white")
# The numeric data is treated as a date,
# breaks are set to an interval equal to the binwidth,
# and a set of labels is generated and adjusted in order to align with bars
p <- p + scale_x_date(breaks = seq(min(dates$num)-20, # change -20 term to taste
max(dates$num),
bin),
labels = date_format("%Y-%b"),
limits = c(as.Date("2009-01-01"),
as.Date("2011-12-01")))
# from here, format at ease
p <- p + theme_bw() + xlab(NULL) + opts(axis.text.x = theme_text(angle=45,
hjust = 1,
vjust = 1))
p
Version 1: Using POSIXct
I try a solution that does everything in ggplot2, drawing without the aggregation, and setting the limits on the x-axis between the beginning of 2009 and the end of 2011.
The Target Plot v1
The Code v1
library("ggplot2")
library("scales")
dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)
dates$Date <- as.POSIXct(dates$Date)
p <- ggplot(dates, aes(Date, ..count..)) +
geom_histogram() +
theme_bw() + xlab(NULL) +
scale_x_datetime(breaks = date_breaks("3 months"),
labels = date_format("%Y-%b"),
limits = c(as.POSIXct("2009-01-01"),
as.POSIXct("2011-12-01")) )
p
Of course, it could do with playing with the label options on the axis, but this is to round off the plotting with a clean short routine in the plotting package.
I know this is an old question, but for anybody coming to this in 2021 (or later), this can be done much easier using the breaks= argument for geom_histogram() and creating a little shortcut function to make the required sequence.
dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)
dates$Date <- lubridate::ymd(dates$Date)
by_month <- function(x,n=1){
seq(min(x,na.rm=T),max(x,na.rm=T),by=paste0(n," months"))
}
ggplot(dates,aes(Date)) +
geom_histogram(breaks = by_month(dates$Date)) +
scale_x_date(labels = scales::date_format("%Y-%b"),
breaks = by_month(dates$Date,2)) +
theme(axis.text.x = element_text(angle=90))
I think the key thing is that you need to do the frequency calculation outside of ggplot. Use aggregate() with geom_bar(stat="identity") to get a histogram without the reordered factors. Here is some example code:
require(ggplot2)
# scales goes with ggplot and adds the needed scale* functions
require(scales)
# need the month() function for the extra plot
require(lubridate)
# original data
#df<-read.csv("http://pastebin.com/download.php?i=sDzXKFxJ", header=TRUE)
# simulated data
years=sample(seq(2008,2012),681,replace=TRUE,prob=c(0.0176211453744493,0.302496328928047,0.323054331864905,0.237885462555066,0.118942731277533))
months=sample(seq(1,12),681,replace=TRUE)
my.dates=as.Date(paste(years,months,01,sep="-"))
df=data.frame(YM=strftime(my.dates, format="%Y-%b"),Date=my.dates,Year=years,Month=months)
# end simulated data creation
# sort the list just to make it pretty. It makes no difference in the final results
df=df[do.call(order, df[c("Date")]), ]
# add a dummy column for clarity in processing
df$Count=1
# compute the frequencies ourselves
freqs=aggregate(Count ~ Year + Month, data=df, FUN=length)
# rebuild the Date column so that ggplot works
freqs$Date=as.Date(paste(freqs$Year,freqs$Month,"01",sep="-"))
# I set the breaks for 2 months to reduce clutter
g<-ggplot(data=freqs,aes(x=Date,y=Count))+ geom_bar(stat="identity") + scale_x_date(labels=date_format("%Y-%b"),breaks="2 months") + theme_bw() + opts(axis.text.x = theme_text(angle=90))
print(g)
# don't overwrite the previous graph
dev.new()
# just for grins, here is a faceted view by year
# Add the Month.name factor to have things work. month() keeps the factor levels in order
freqs$Month.name=month(freqs$Date,label=TRUE, abbr=TRUE)
g2<-ggplot(data=freqs,aes(x=Month.name,y=Count))+ geom_bar(stat="identity") + facet_grid(Year~.) + theme_bw()
print(g2)
The error graph this under the title "Plot based on Gauden's approach" is due to the binwidth parameter:
... + Geom_histogram (binwidth = 30, color = "white") + ...
If we change the value of 30 to a value less than 20, such as 10, you will get all frequencies.
In statistics the values are more important than the presentation is more important a bland graphic to a very pretty picture but with errors.