Changing the Shapes of Points in Scatter Plot

Update marker shape of a scatter plot

A scatter plot returns a path collection, it contains the paths of the markers. In order to change the marker shape you need to set the path to the new marker path.

For built-in markers, these paths can be obtained from the MarkerStyle class. For custom markers see my SO answer here.

Example - scatter plot with dot markers later changed to plus markers:

from matplotlib import pyplot as plt
from matplotlib.markers import MarkerStyle

sp = plt.scatter([1,2],[1,2], marker='.')

new_marker = MarkerStyle("+")
sp.set_paths((new_marker.get_path(),))
sp.set_sizes([8])

plt.show()

Sample Image

The only caveat is that you need to set the marker size too, by default the new markers are plotted rather big.

How to access/change properties of individual points on matplotlib scatter plot

SOLVED

Answer is setting mask of numpy.core.ma.MaskedArray that lies under sc._offsets.mask property of matplotlib scatter plot.
This can be done in the following way both during plot generation and after plot has been generated, in interactive mode:

#before change:
#sc._offsets.mask = [[False, False], [False, False], [False, False], [False, False], [False, False]]

sc._offsets.mask = [[1, 1], [1, 1], [1, 1], [0, 0], [0, 0]]

#after change:
#sc._offsets.mask = [[True, True], [True, True], [True, True], [False, False], [False, False]]

#then re-draw plot
sc.figure.canvas.draw() #docs say that it's better to use draw_idle() but I don't see difference

Setting to True value coressponding with index of point you would like to exclude from plot, removes that particular point from the plot. It does not "deletes" it. Points can be restored by setting bool values back to "False". Note that it is 2D array so passing simple: [1, 1, 1, 0, 0]
will not do and you need to take into account both x and y coordinates of the plot.

Consult numpy docs for details:
https://numpy.org/doc/stable/reference/maskedarray.generic.html#accessing-the-mask

I'll edit if something comes up.
Thank you all for help.

Changing the shape of one point or few points in a scatter plot in R

How is this?

Create a new column using dplyr::mutate, which is conditional upon the x-coordinates (for example, but it could be anything). Then, use this column within aes to control the shape size.

Also, you can use scale_shape_manual and scale_colour_manual to manually control the shape and colours. It's not clear to me what shape you want but you would just need to change the arguments in scale_shape_manual.

EDIT:

Since you specifically need a different symbol, then you need to use geom_text instead.

df %>% 
dplyr::mutate(z = ifelse(x >= 5, "-", "+")) %>%
ggplot(aes(x, y)) +
geom_text(size = 12, aes(colour=z, label=z)) +
scale_x_continuous(breaks = 1:7, expand = expansion(add = c(0, 1)))+
scale_y_continuous(breaks = 1:7, expand = expansion(add = c(0, 1)))+
coord_fixed(xlim = c(0, 7), ylim = c(0, 7), clip = "off")+
geom_segment(data = df_arrow, aes(x = x, xend = xend, y = y, yend = yend), size = 0.75, colour = "black",
arrow = arrow(angle = 20, length = unit(3, "mm"), ends = "last", type = "closed"), linejoin = "mitre") +
annotate("text", x = c(7.8, 0.3), y = c(0.3, 7.8), label = c("italic(x)", "italic(y)"), parse = TRUE, size = 6, family = "Times New Roman")+
labs(x = NULL,
y = NULL)+
theme_bw()+
theme(panel.grid.major = element_line(colour = "gray80"),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
axis.ticks.length = unit(1, "mm"),
text = element_text(size = 18, family = "Times New Roman")) +
scale_shape_manual(values=c(8, 9)) +
scale_colour_manual(values = c('red', 'blue'))

Sample Image

Changing the shapes of points in scatter plot

A ScatterRenderer inherits getItemShape() from AbstractRenderer. You can override getItemShape() to supply your own shapes.

Addendum: One advantage to this approach is that you can specify a Shape for each item in each series.

Addendum: To use ShapeUtilities.createDiagonalCross(), do something like this:

Shape cross = ShapeUtilities.createDiagonalCross(3, 1);
plot = (XYPlot) chart.getPlot();
renderer = plot.getRenderer();
renderer.setSeriesShape(0, cross);

Addendum: Just switch to setSeriesShape(). Also, skip the XYDotRenderer and Math.round().

Scatter Plot Demo

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Shape;
import java.util.*;
import javax.swing.JPanel;
import org.jfree.chart.*;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
import org.jfree.util.ShapeUtilities;

public class SPlotfinal extends ApplicationFrame {

public SPlotfinal(String s) {
super(s);
JPanel jpanel = createDemoPanel();
jpanel.setPreferredSize(new Dimension(640, 480));
add(jpanel);
}

public static JPanel createDemoPanel() {
JFreeChart jfreechart = ChartFactory.createScatterPlot(
"Scatter Plot Demo", "X", "Y", samplexydataset2(),
PlotOrientation.VERTICAL, true, true, false);
Shape cross = ShapeUtilities.createDiagonalCross(3, 1);
XYPlot xyPlot = (XYPlot) jfreechart.getPlot();
xyPlot.setDomainCrosshairVisible(true);
xyPlot.setRangeCrosshairVisible(true);
XYItemRenderer renderer = xyPlot.getRenderer();
renderer.setSeriesShape(0, cross);
renderer.setSeriesPaint(0, Color.red);
return new ChartPanel(jfreechart);
}

private static XYDataset samplexydataset2() {
int cols = 20;
int rows = 20;
double[][] values = new double[cols][rows];
XYSeriesCollection xySeriesCollection = new XYSeriesCollection();
XYSeries series = new XYSeries("Random");
Random rand = new Random();
for (int i = 0; i < values.length; i++) {
for (int j = 0; j < values[i].length; j++) {
double x = rand.nextGaussian();
double y = rand.nextGaussian();
series.add(x, y);
}
}
xySeriesCollection.addSeries(series);
return xySeriesCollection;
}

public static void main(String args[]) {
SPlotfinal scatterplotdemo4 = new SPlotfinal("Scatter Plot Demo 4");
scatterplotdemo4.pack();
RefineryUtilities.centerFrameOnScreen(scatterplotdemo4);
scatterplotdemo4.setVisible(true);
}
}

Changing the shape of one point or few points in a scatter plot in R based off of character values

You need to map your sample number to the shape aesthetic:

ggplot(nd, aes(εNd, `stratigraphic column`)) + 
geom_point(size = 4, aes(shape = `sample number`)) +
ggtitle(expression(epsilon*"Neodymium in Manitoba Escarpment")) +
xlab(~epsilon*"Nd") +
theme_light()

Sample Image


Data in reproducible form as taken from question

nd <- structure(list(`Sample Name` = c("B8", "B7B8", "MO2400", "SHARK 2", 
"M.FISH", "MO2376", "ABOVE UPPER", "NIO 38", "NIO 39", "T-4 TO T-5",
"T-2 TO T-3", "T1 TO T0"), eNd = c(-4.887223024, -5.723139056,
-6.639290394, -6.349256446, -6.100998712, -7.689046402, -8.306593254,
-8.90688489, -7.243909917, -7.700379025, -8.532019275, -6.894687774
), `stratigraphic column` = c(8.34, 8.27, 7.2, 7, 7.1, -6, -6.53,
-8.07, -8.16, -12, -12.47, -13.1), `sample number` = c("ND",
"ND", "M", "M", "M", "M", "ND", "ND", "ND", "ND", "ND", "ND")),
class = "data.frame", row.names = c(NA, -12L))

How can I change the shape of points in a scatter chart?

PointSeries only supports the shapes listed in PointShape enumeration.

As of now, rendering any custom images is not supported with LCJS accelerated rendering.



Related Topics



Leave a reply



Submit