How to change marker border width and hatch width?
Asked Answered
J

4

60

In this example of a marker from my scatter plot, I have set the color to green, and edge color to black, and hatch to "|". For the hatch pattern to show up at all, I must set the edgecolor; however when I do, I get a very thick border around the marker. Two questions:

  1. How can I to set the size of this border (preferably to 0)?

  2. How can I increase the thickness of the hatch lines?

Jesher answered 14/1, 2013 at 20:3 Comment(1)
To 2.: Take a look at How to change the linewidth of hatch in matplotlib?Sidewinder
V
88
  1. You just need to set the linewidth to control the marker border thickness.
  2. You can increase the density of hatching, by repeating symbols (in the example below, the '|' is repeated in the R/H pane; note that to obtain NW->SE diagonal lines the symbol must be escaped so needs twice as many characters to really double it -- '\\\\' is density 2 while '||||' is density 4). However, I don't think the thickness of individual lines within hatching is controllable.

See the code example below to produce scatter plots such as these: example hatching control

import matplotlib.pyplot as plt
# generate some data
x = [1,2,3,4,5,8]
y= [i**2 for i in x]
y2= [60-i**2+3*i for i in x]

# plot markers with thick borders
plt.subplot(121)
plt.scatter(x,y, s=500, marker='s', edgecolor='black', linewidth=3, facecolor='green', hatch='|')
# compare with no borders, and denser hatch.
plt.subplot(122)
plt.scatter(x,y2, s=500, marker='s', edgecolor='black', linewidth=0, facecolor='green', hatch='||||')

plt.show()

matplotlib documentation on collections and scatter.

Varanasi answered 15/1, 2013 at 1:2 Comment(8)
You are correct about not being able to change the width of the hatch lines, it is hard coded to 1 (at least in the aggbackend)Flowering
and adding the ability to tune the size of the hatches looks like a huge undertaking.....Flowering
When dealing with multiples of the character '\', it may be helpful to use the Python string multiplication operator. For example, due to character escaping, for a single '\' character, you would use the string "\\". For n repetitions, you can use n * "\\", e.g., 4 * "\\" would give a string of four '\' characters.Imbed
Surely the correct argument to control the marker border thickness is markeredgewidth (or mew)?Gangplank
It seems to be controlled by markerlinewidth now.Cloakanddagger
edgecolors='none' works for me when calling plot.scatter on a pandas DataFrame (see https://mcmap.net/q/66251/-python-scatter-plot-size-and-style-of-the-marker)Burns
markeredgewidth and mew worked for me, but markerlinewidth and linewidth did not.Rustproof
The current version of matplotlib (3.2.1) doesn't allow linewidth to be a string. It needs to be a number.Whap
R
11

If you're using plt.plot, you'll want to pass argument markeredgewidth.

Randa answered 5/10, 2022 at 17:38 Comment(0)
M
8

This is several years after you asked the question, but the only way I've found to do it is to change the matplotlib.rc.

You can do this either in the actual .rc file or within your python script, e.g.

import matplotlib as mpl

mpl.rc('hatch', color='k', linewidth=1.5)

This will make all of the hatch lines in your script black and thickness 1.5 rather than the default 1.0.

Magnifico answered 5/11, 2018 at 10:56 Comment(0)
S
2

As other answers mentioned, there are two ways to make a scatter plot in matplotlib: One using scatter() and the other using plot() (it's actually a lineplot with markers on certain locations but it's possible to "turn off" lines leaving only the markers).

To set the border/edge width during the scatter() functional call, linewidth= (or lw=) should be used; and to do the same during a plot() functional call, markeredgewidth= (or mew=) should be used (because lw sets the width of the lines which are turned off in this case).

x = [0, 1, 2]

fig, (ax1, ax2) = plt.subplots(1, 2)

# square, blue, size=10 markers with black edges of width=3
ax1.plot(x, 's', ms=10, mec='black', mew=3)
ax2.scatter(x, x, marker='s', s=100, ec='black', lw=3)

img


To change the border/edge width after the plotter functional call, you can use set_* method on the relevant Artist object of each plotter1; plot() defines a lines object while scatter defines a collections object.2

fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.plot(x, 's')
ax2.scatter(x, x)

# make marker edge width = 3
ax1.lines[0].set_mew(3)     
# or
ax1.lines[0].set_markeredgewidth(3)

# make marker edge width = 3
ax2.collections[0].set_linewidth(3)
# or
ax2.collections[0].set_lw(3)

As mentioned above, the properties can be changed using the dedicated set_* method. Moreover, each Artist (e.g. Line2D, PathCollection etc.) defines a set() method that can be used to change its properties as well.

# change markersize, marker, marker edge color, marker face color, marker edge width
ax1.lines[0].set(markersize=22.36, marker='s', markeredgecolor='black', markerfacecolor='green', markeredgewidth=3)

# change marker size, marker edge color, marker face color, hatch, marker edge width
ax2.collections[0].set(sizes=[500], edgecolor='black', facecolor='green', hatch='|', linewidth=3);

1 The list of set_* methods may be found as follows. As can be seen from the following code, scatter plot has a more limited API; for example, marker style cannot be changed after being plotted.

# properties that may be changed
f1 = {a for a in dir(ax1.lines[0]) if a.startswith('set_')}
f2 = {a for a in dir(ax2.collections[0]) if a.startswith('set_')}

2 plot() creates a list of Line2D objects while scatter creates a list of PathCollection objects, which can be verified by checking what's inside .lines/.collections attributes of each method.

x = [0, 1, 2]

fig, (ax1, ax2) = plt.subplots(2)
ax1.plot(x, 'o')

ax1.lines[0]         # <matplotlib.lines.Line2D at 0x23db04f34f0>
ax1.collections      # <---- has no collections


ax2.scatter(x, x)

ax2.lines            # <---- has no lines
ax2.collections[0]   # <matplotlib.collections.PathCollection at 0x23daff962b0>

Knowing which method is used to create a scatter plot is very useful if you need to change markers created by a third-party library that uses matplotlib in the backend.

For example, seaborn uses scatter, so to change the marker edge width, you'll need to use linewidth:

import seaborn as sns
sns.scatterplot(x=x, y=x, s=1000, ec='black', linewidth=3)
 
# or
ax = sns.scatterplot(x=x, y=x, s=1000, ec='black')
ax.collections[0].set_lw(3)

On the other hand, statsmodels' time-series decomposition plotter uses plot, so to change the marker edge width, you'll need to use markeredgewidth:

from statsmodels.tsa.seasonal import seasonal_decompose
import pandas as pd

data = pd.Series(range(366)).sample(frac=1).set_axis(pd.date_range('2022', '2023', freq='D'))
fig = seasonal_decompose(data).plot()
fig.axes[3].lines[0].set(markersize=3, markeredgewidth=0);  # <--- change the marker size and edges of the residual plot
Seen answered 4/8, 2023 at 19:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.