How to add text labels to a scatterplot? - plot

Is there a way to add text labels to the points on a scatterplot? Each point has a string associated with it as its label. I like to label only as many points as it can be done withour overlapping?
df = DataFrame(x=rand(100), y=rand(100), z=randstring.(fill(5,100)))
scatter(df.x, df.y)
annotate!(df.x, df.y, text.(df.z))

using StatisticalGraphics package:
using InMemoryDatasets
using StatisticalGraphics
using Random
ds=Dataset(x=rand(100), y=rand(100), z=randstring.(fill(5,100)))
sgplot(ds, Scatter(x=:x,y=:y,labelresponse=:z))

Here is something I wrote for Makie.jl that suited my needs:
Non-overlapping labels for scatter plots
It works best for single line, short text labels, and where all labels have similar lengths with one another. It is still WIP, as I am working to improve it for placement of longer text labels.
Here are some samples of what it can do:
Essentially, you call function viz to plot a scatter chart on your (x, y) data set:
resolution = (600, 600) # figure size (pixels) -- need not be a equal dimension
fontpt = 12 # label font size (points)
flabel = 1.5 # inflate the label size to create some margins
fdist = 0.3 # inflate the max. distance between a label and its
# anchor point before a line is drawn to connect. them.
# Smaller values would create more connecting lines.
viz(x, y, labels; resolution=resolution, flabel=flabel, fdist=fdist, fontpt=fontpt)
where labels is a list containing the text labels for every pair of (x, y) point.

You can use the extra named argument series_annotations in the scatter function. Here us an example where I use "1", "2", etc. as labels:
using Plots
x = collect(0:0.1:2)
y = sinpi.(x)
scatter(x, y, series_annotations = text.(1:length(x), :top))
Avoiding overlaps is more difficult. You could customize your label with empty "" for duplicates where the points are the same, or see for Makie: Makie: Non-overlapping label placement algorithm for scatter plots

Related

Printing text on plot in a specific position Stata

I am trying to print a text in the botton right of some plots. I know that I can use the coordinates to do that in the option text of a plot, but given that I have to plot around 50 charts that change a lot in terms of the axis magnitude, I´m looking if there is a way to do this by default.
clear all
set obs 100
gen x = runiformint(1, 100)
gen y = runiformint(100, 200)
egen z = seq(), f(1) t(100)
scatter x z, text(1 100 "XXXX")
scatter y z, text(1 100 "XXXX")
In this code I can print the text in the first scatter but not in the second one.
Suppose you want to put text in the bottom right-hand corner of plot. Consider using a title option:
sysuse auto, clear
scatter mpg weight, subtitle("frog", pos(5) ring(0))
scatter length weight, subtitle("toad", pos(5) ring(0))
See for discussion https://www.stata-journal.com/article.html?article=gr0051
Warning: Nothing rules out such a title obscuring point, line or area elements that represent data.

Plot piecewise data, x-axis limits

I use Julia with Plots , to generate my plots.
I want to plot data (A,B) and i know that all interesting data lies in two region of A. The two regions should be plotted between each other in one plot.
My A-data is evenly spaced. So what i did was cutting out my interesting pieces and glued them into one object.
My problem is that i don't know how to manipulate the scale on the x-axis.
When I just plot the B data against their array index, I basically get the form I want. I just need the numbers from A on the x-axis.
I give here a toy example
using Plots
N=5000
B=rand(N)
A=(1:1:N)
xl_1=100
xu_1=160
xl_2=600
xu_2=650
A_new=vcat(A[xl_1:xu_1],A[xl_2:xu_2])
B_new=vcat(B[xl_1:xu_1],B[xl_2:xu_2])
plot(A_new,B_new) # This leaves the spacing between the data explicit
plot(B_new) # This creats basically the right spacing, but
# without the right x axis grid
I did not find anything how one can use two successive xlims, therefore i try it this way.
You can't pass two successive xlims, because you can't have a break in the axis. That is by design in Plots.
So your possibilities are: 1) to have two subplots with different parts of the plot, or 2) to plot with the index, and just change the axis labels.
The second approach would use a command like xticks = ([1, 50, 100, 150], ["1", "50", "600", "650"], but I'd recommend the first as it's strictly speaking a more correct way of displaying the data:
plot(
plot(A[xl_1:xu_1], B[xl_1:xu_1], legend = false),
plot(A[xl_2:xu_2], B[xl_2:xu_2], yshowaxis = false),
link = :y
)

How to send parameter to Geom.histogram when using Geom.subplot_grid in Gadfly?

I am trying to plot several histograms for the same data set, but with different numbers of bins. I am using Gadfly.
Suppose x is just an array of real values, plotting each histogram works:
plot(x=x, Geom.histogram(bincount=10))
plot(x=x, Geom.histogram(bincount=20))
But I'm trying to put all the histograms together. I've added the number of bins as another dimension to my data set:
x2 = vcat(hcat(10*ones(length(x)), x), hcat(20*ones(length(x)), x)
df = DataFrame(Bins=x2[:,1], X=x2[:,2])
Is there any way to send the number of bins (the value from the first column) to Geom.histogram when using Geom.subplot_grid? Something like this:
plot(df, x="X", ygroup="Bins", Geom.subplot_grid(Geom.histogram(?)))
I think you would be better off not using subplot grid at that point, and instead just combine them with vstack or hstack. From the docs
Plots can also be stacked horizontally with ``hstack`` or vertically with
``vstack``. This allows more customization in regards to tick marks, axis
labeling, and other plot details than is available with ``subplot_grid``.

panel.text xyplot R

I am adding text to different panels of a xyplot in lattice and was wondering if anyone knows a way to not specify a x and y coordinates or is there something similar to legend where you can say upper left or upper right,etc?
I ask because I want to use scales=free in the plotting code, but when I do the text in the mytext code ends up covering up parts of the graph and doesn't make for a good plot. I would like to have a way to plot the graphs without making individual plots because in my real dataset I have up to 10 grouping factor levels (sams in the code). The example provided is not as extreme as the real data.
Example data
d_exp<-data.frame(sams=c(rep("A",6),rep("B",6),rep("C",6)),
gear=c(rep(1:2,9)),
fraction=c(.12,.61,.23,.05,.13,.45,0.3,.5,.45,.20,.35,.10,.8,.60,.10,.01,.23,.03),
interval=c(rep(c(0,10,20),6)))
d_exp<-d_exp[order(d_exp$sams,d_exp$gear,d_exp$interval),]
Plot with scales=same. mytext x and y coordinates are specified.
mytext<-c("N=3","N=35","N=6")
panel.my <- function(...) {
panel.superpose(col=c("red","blue"),lwd=1.5,...)
panel.text(x=2.5,y=0.5,labels=mytext[panel.number()],cex=.8)
}
xyplot(fraction~interval | sams, data=d_exp,groups=gear,type="l",
scales=list(relation="same",y=list(alternating=1,cex=0.8),x=list(alternating=1,cex=.8,abbreviate=F)),
strip = strip.custom(bg="white", strip.levels = T),drop.unused.levels=T,as.table=T,
par.strip.text=list(cex=0.8),panel=panel.my)
Same thing with scales=free. Text is in odd places because all text has the same coordinates.
xyplot(fraction~interval | sams, data=d_exp,groups=gear,type="l",
scales=list(relation="free",y=list(alternating=1,cex=0.8),x=list(alternating=1,cex=.8,abbreviate=F)),
strip = strip.custom(bg="white", strip.levels = T),drop.unused.levels=T,as.table=T,
par.strip.text=list(cex=0.8),panel=panel.my)
Thanks for any help.
You can use grid.text() to specify units in a range-independent way. For example
library(grid)
panel.my <- function(...) {
panel.superpose(col=c("red","blue"),lwd=1.5,...)
grid.text(x=.5,y=.8,label=mytext[panel.number()])
}
With grid.text the x and y values use npc units by default which range from 0 to 1. So x=.5 means centered and y=.8 means 80% of the way to the top.

R histogram with numbers under bars

I had some problems while trying to plot a histogram to show the frequency of every value while plotting the value as well. For example, suppose I use the following code:
x <- sample(1:10,1000,replace=T)
hist(x,label=TRUE)
The result is a plot with labels over the bar, but merging the frequencies of 1 and 2 in a single bar.
Apart from separate this bar in two others for 1 and 2, I also need to put the values under each bar.
For example, with the code above I would have the number 10 under the tick at the right margin of its bar, and I needed to plot the values right under the bars.
Is there any way to do both in a single histogram with hist function?
Thanks in advance!
Calling hist silently returns information you can use to modify the plot. You can pull out the midpoints and the heights and use that information to put the labels where you want them. You can use the pos argument in text to specify where the label should be in relation to the point (thanks #rawr)
x <- sample(1:10,1000,replace=T)
## Histogram
info <- hist(x, breaks = 0:10)
with(info, text(mids, counts, labels=counts, pos=1))

Resources