I noticed when you plot that the first line is blue, then orange, then green, and so on.
Is there some way to access this list of colours? I've seen a million posts on how to change the colour cycle or access the iterator, but not on how to just get the list of colours that matplotlib cycles through by default.
In matplotlib versions >= 1.5, you can print the rcParam called axes.prop_cycle:
print(plt.rcParams['axes.prop_cycle'].by_key()['color'])
# [u'#1f77b4', u'#ff7f0e', u'#2ca02c', u'#d62728', u'#9467bd', u'#8c564b', u'#e377c2', u'#7f7f7f', u'#bcbd22', u'#17becf']
Or equivalently, in python2:
print plt.rcParams['axes.prop_cycle'].by_key()['color']
In versions < 1.5, this was called color_cycle:
print plt.rcParams['axes.color_cycle']
# [u'b', u'g', u'r', u'c', u'm', u'y', u'k']
Note that the default color cycle changed in version 2.0.0 http://matplotlib.org/users/dflt_style_changes.html#colors-in-default-property-cycle
Often, there is no need to get the default color cycle from anywhere, as it is the default one, so just using it is sufficient.
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
t = np.arange(5)
for i in range(4):
line, = ax.plot(t,i*(t+1), linestyle = '-')
ax.plot(t,i*(t+1)+.3,color = line.get_color(), linestyle = ':')
plt.show()
In case you want to use the default color cycle for something different, there are of course several options.
"tab10" colormap
First it should be mentionned that the "tab10" colormap comprises the colors from the default color cycle, you can get it via cmap = plt.get_cmap("tab10").
Equivalent to the above would hence be
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
t = np.arange(5)
cmap = plt.get_cmap("tab10")
for i in range(4):
ax.plot(t,i*(t+1), color=cmap(i), linestyle = '-')
ax.plot(t,i*(t+1)+.3,color=cmap(i), linestyle = ':')
plt.show()
Colors from color cycle
You can also use the color cycler directly, cycle = plt.rcParams['axes.prop_cycle'].by_key()['color']. This gives list with the colors from the cycle, which you can use to iterate over.
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
t = np.arange(5)
cycle = plt.rcParams['axes.prop_cycle'].by_key()['color']
for i in range(4):
ax.plot(t,i*(t+1), color=cycle[i], linestyle = '-')
ax.plot(t,i*(t+1)+.3,color=cycle[i], linestyle = ':')
plt.show()
The CN notation
Finally, the CN notation allows to get the Nth color of the color cycle, color="C{}".format(i). This however only works for the first 10 colors (N in [0,1,...9])
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
t = np.arange(5)
for i in range(4):
ax.plot(t,i*(t+1), color="C{}".format(i), linestyle = '-')
ax.plot(t,i*(t+1)+.3,color="C{}".format(i), linestyle = ':')
plt.show()
All codes presented here produce the same plot.
The CN notation revisited
I'd like to address a new development of Matplotlib. In a previous answer we read
Finally, the CN notation allows to get the Nth color of the color cycle, color="C{}".format(i). This however only works for the first 10 colors (N in [0,1,...9])
but
import numpy as np
import matplotlib.pyplot as plt
t = np.linspace(0,6.28, 629)
for N in (1, 2):
C0N, C1N = 'C%d'%(N), 'C%d'%(N+10)
plt.plot(t, N*np.sin(t), c=C0N, ls='-', label='c='+C0N)
plt.plot(t, N*np.cos(t), c=C1N, ls='--', label='c='+C1N)
plt.legend() ; plt.grid() ; plt.show()
gives
if you're looking for a quick one-liner to get the RGB colors that matplotlib uses for its lines, here it is:
>>> import matplotlib; print('\n'.join([str(matplotlib.colors.to_rgb(c)) for c in matplotlib.pyplot.rcParams['axes.prop_cycle'].by_key()['color']]))
(0.12156862745098039, 0.4666666666666667, 0.7058823529411765)
(1.0, 0.4980392156862745, 0.054901960784313725)
(0.17254901960784313, 0.6274509803921569, 0.17254901960784313)
(0.8392156862745098, 0.15294117647058825, 0.1568627450980392)
(0.5803921568627451, 0.403921568627451, 0.7411764705882353)
(0.5490196078431373, 0.33725490196078434, 0.29411764705882354)
(0.8901960784313725, 0.4666666666666667, 0.7607843137254902)
(0.4980392156862745, 0.4980392156862745, 0.4980392156862745)
(0.7372549019607844, 0.7411764705882353, 0.13333333333333333)
(0.09019607843137255, 0.7450980392156863, 0.8117647058823529)
Or for uint8:
import matplotlib; print('\n'.join([str(tuple(int(round(v*255)) for v in matplotlib.colors.to_rgb(c))) for c in matplotlib.pyplot.rcParams['axes.prop_cycle'].by_key()['color']]))
(31, 119, 180)
(255, 127, 14)
(44, 160, 44)
(214, 39, 40)
(148, 103, 189)
(140, 86, 75)
(227, 119, 194)
(127, 127, 127)
(188, 189, 34)
(23, 190, 207)
Related
I'm stuck trying to get my colorbar to show the same colorspectrum as my scatterplot. Instead of the pink/purple to black spectrum of my colorgraded datapoints, it shows the default colors of a colorbar. I have read multiple other threads on here to no avail, but please alert me to a similar thread, if I have missed something that could solve my problem.
I have made a short code illustrating my problem:
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng()
arr = np.arange(7000)
rng.shuffle(arr)
r = np.sqrt(np.random.random(7000))
theta = np.random.uniform(high = 2*np.pi, size = 7000)
X = np.array(r*np.cos(theta))
Y = np.array(r*np.sin(theta))
def values_to_colormap(values):
values_scale = values/np.max(values)
(a,) = np.shape(values)
cmap = values_scale.reshape(a,1)*np.array([[0.6, 0.4, 0.6]])
return cmap
points_colors = values_to_colormap(arr)
ps = plt.scatter(X,Y, marker = '.', color = points_colors)
plt.colorbar(ps, orientation='horizontal')
plt.axis('equal')
plt.show();
The colorbar uses the cmap and the norm of the scatter plot. In this case, individual colors are given, and the colorbar falls back to the default colormap ('viridis') and the default norm (as no vmin nor vmax nor explicit color values are given, 0 and 1 are used).
Your values_to_colormap function maps 0 to color (0, 0, 0) and the maximum value to (0.6, 0.4, 0.6). This is equivalent to use a norm with vmin=0, vmax=arr.max() and a LinearSegmentedColormap between the given colors:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
rng = np.random.default_rng()
arr = np.arange(7000)
rng.shuffle(arr)
r = np.sqrt(np.random.random(7000))
theta = np.random.uniform(high=2 * np.pi, size=7000)
X = np.array(r * np.cos(theta))
Y = np.array(r * np.sin(theta))
ps = plt.scatter(X, Y, marker='.', c=arr, vmin=0, vmax=arr.max(),
cmap=LinearSegmentedColormap.from_list('', [(0, 0, 0), (0.6, 0.4, 0.6)]))
plt.colorbar(ps, orientation='horizontal')
plt.axis('equal')
plt.show()
I'm trying to create a scatter plot with 100 data points and three variables: x value, y value, and category. This information is stored in an ndarray.
I can create the scatter plot, but I don't know how to use a different color for each category. I used the following code for the plot, which seems to work fine (although it's not finished):
def my_plot(data, color_map):
f, ax = plt.subplots()
ax.scatter(data.x, data.y, s = 150, edgecolors = "r")
return f
In my function, color_map is a parameter which refers to a dictionary I created to color the different categories (there are four in total). This is the dictionary:
color_map = {"winter":(15, 28, 75), "spring":(92, 57, 32), "summer":(255, 253, 211), "fall":(174, 12, 12)}
What I would like to do is to somehow integrate this color_map in my function so that each dot in my plot receives a different color.
I think this could be done using np.where to create a mask, but I'm not sure how to proceed...
The color values need to be divided by 255 because matplotlib likes them between 0 and 1.
With this dict you can create an array of colors for the categories:
from matplotlib import pyplot as plt
from matplotlib.lines import Line2D
import pandas as pd
import numpy as np
color_map = {"winter": (15, 28, 75), "spring": (92, 57, 32), "summer": (255, 253, 211), "fall": (174, 12, 12)}
color_map = {key: (r / 255, g / 255, b / 255,) for key, (r, g, b) in color_map.items()}
N = 200
data = pd.DataFrame({'x': np.random.uniform(1, 9, N), 'y': np.random.uniform(1, 5, N),
'cat': np.random.choice([*color_map.keys()], N)})
fig, ax = plt.subplots()
ax.scatter(data.x, data.y, s=150, color=[color_map[c] for c in data.cat], ec='r')
handles = [Line2D([], [], marker='o', ls='', color=col, markeredgecolor='r', label=label)
for label, col in color_map.items()]
plt.legend(handles=handles, bbox_to_anchor=[1.02, 1.02], loc='upper left')
plt.tight_layout()
plt.show()
PS: A similar plot can be generated with seaborn, which also automatically adds the corresponding legend. Note that the current version of matplotlib (3.3.1) has a problem with the hue parameter. Normally you would add it as hue='cat' but in this version a workaround via .to_list is needed.
import seaborn as sns
ax = sns.scatterplot(x='x', y='y', hue=data['cat'].to_list(), s=150, palette=color_map, edgecolor='r', data=data)
I am plotting a collection of rectangles with matplotlib.patches. My code is:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig = plt.figure(figsize=(14, 10))
for i in rectangles_list:
ax1 = fig.add_subplot(111, aspect='equal')
ax1.add_patch(patches.Rectangle(
(x[i], y[i]),
width[i],
height[i],
alpha = 1.0,
facecolor = colors_list[i]
)
)
plt.show()
The rectangles may be overlapping, therefore some of them may be completely hidden. Do you know if it is possible to get the colors of the visible rectangles? I mean the colors of the rectangles that are not completely hidden and therefore that can be actually viewed by the user. I was thinking to some function that returns the color of the pixels, but more intelligent ideas are welcome. If possible, I'd prefer to not use PIL. Unfortunately I cannot find any solution on the internet.
Following Vlass Sokolov comment and this Stackoverflow post by Joe Kington, here is how you could get a numpy array containing all the unique colors that are visible on a matplotlib figure:
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
import numpy as np
plt.close('all')
# Generate some data :
N = 1000
x, y = np.random.rand(N), np.random.rand(N)
w, h = np.random.rand(N)/10 + 0.05, np.random.rand(N)/10 + 0.05
colors = np.vstack([np.random.random_integers(0, 255, N),
np.random.random_integers(0, 255, N),
np.random.random_integers(0, 255, N)]).T
# Plot and draw the data :
fig = plt.figure(figsize=(7, 7), facecolor='white')
ax = fig.add_subplot(111, aspect='equal')
for i in range(N):
ax.add_patch(Rectangle((x[i], y[i]), w[i], h[i], fc=colors[i]/255., ec='none'))
ax.axis([0, 1, 0, 1])
ax.axis('off')
fig.canvas.draw()
# Save data in a rgb string and convert to numpy array :
rgb_data = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
rgb_data = rgb_data.reshape((int(len(rgb_data)/3), 3))
# Keep only unique colors :
rgb_data = np.vstack({tuple(row) for row in rgb_data})
# Show and save figure :
fig.savefig('rectangle_colors.png')
plt.show()
I have a list of color values (in either of the formats: hex ('#ffffff') or rgb (255,255,255) if that helps). These colors correspond explicitly with the line segment between points. Currently I plot a line as a collection of line segments via:
import matplotlib.pyplot as plt
import itertools
colors = itertools.cycle('#ffffff', '#ffffff', '#ff0320', '#452143', ...)
t = (0, 1, 2, 3, ...)
var1 = (43, 15, 25, 9, ...)
ax = plt.subplot2grid((3,1), (0,0), colspan=3, rowspan=1)
ps = [(t,var1) for (t,var1) in zip(t, val)]
for start, end in zip(ps[:-1], ps[1:]):
t, var1 = zip(start, end)
c = next(colors)
ax.plot(t, var1, color=c)
However since I have a color for each point I would much prefer to set a cmap for the plot. How might I accomplish converting a list of colors into a cmap which I can use when plotting a line?
As tcaswell says, use a LineCollection for this:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.collections import LineCollection
# a random walk
xy = np.cumsum(np.random.randn(1000, 2), axis=0)
z = np.linspace(0, 1, 1000)
lc = LineCollection(zip(xy[:-1], xy[1:]), array=z, cmap=plt.cm.hsv)
fig, ax = plt.subplots(1, 1)
ax.add_collection(lc)
ax.margins(0.1)
plt.show()
How do I set color to Rectangle for example in matplotlib? I tried using argument color, but had no success.
I have following code:
fig=pylab.figure()
ax=fig.add_subplot(111)
pylab.xlim([-400, 400])
pylab.ylim([-400, 400])
patches = []
polygon = Rectangle((-400, -400), 10, 10, color='y')
patches.append(polygon)
p = PatchCollection(patches, cmap=matplotlib.cm.jet)
ax.add_collection(p)
ax.xaxis.set_major_locator(MultipleLocator(20))
ax.yaxis.set_major_locator(MultipleLocator(20))
pylab.show()
I couldn't get your code to work, but hopefully this will help:
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
rect1 = matplotlib.patches.Rectangle((-200,-100), 400, 200, color='yellow')
rect2 = matplotlib.patches.Rectangle((0,150), 300, 20, color='red')
rect3 = matplotlib.patches.Rectangle((-300,-50), 40, 200, color='#0099FF')
circle1 = matplotlib.patches.Circle((-200,-250), radius=90, color='#EB70AA')
ax.add_patch(rect1)
ax.add_patch(rect2)
ax.add_patch(rect3)
ax.add_patch(circle1)
plt.xlim([-400, 400])
plt.ylim([-400, 400])
plt.show()
produces:
Turns out, you need to do ax.add_artist(Rectangle) to have the color specifications work; when using patches.append(Rectangle), the rectangle is shown in blue (on my PC, at least) ignoring any color specification.
Btw, note that artists — Matplotlib 1.2.1 documentation: class matplotlib.patches.Rectangle states that there is
edgecolor - for stroke color
facecolor - for fill color
... and then there is color - which basically sets both stroke and fill color at the same time.
Here is the modified OP code, which I've tested on Linux (Ubuntu 11.04), python 2.7, matplotlib 0.99.3:
import matplotlib.pyplot as plt
import matplotlib.collections as collections
import matplotlib.ticker as ticker
import matplotlib
print matplotlib.__version__ # 0.99.3
fig=plt.figure() #pylab.figure()
ax=fig.add_subplot(111)
ax.set_xlim([-400, -380]) #pylab.xlim([-400, 400])
ax.set_ylim([-400, -380]) #pylab.ylim([-400, 400])
patches = []
polygon = plt.Rectangle((-400, -400), 10, 10, color='yellow') #Rectangle((-400, -400), 10, 10, color='y')
patches.append(polygon)
pol2 = plt.Rectangle((-390, -390), 10, 10, facecolor='yellow', edgecolor='violet', linewidth=2.0)
ax.add_artist(pol2)
p = collections.PatchCollection(patches) #, cmap=matplotlib.cm.jet)
ax.add_collection(p)
ax.xaxis.set_major_locator(ticker.MultipleLocator(20)) # (MultipleLocator(20))
ax.yaxis.set_major_locator(ticker.MultipleLocator(20)) # (MultipleLocator(20))
plt.show() #pylab.show()
this is the output:
To avoid calling .add_patch() multiple times (often the purpose of using PatchCollection in the first place), you can pass a ListedColormap to the PatchCollection via cmap=.
This looks as follows (modified from fraxel's answer):
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from matplotlib.collections import PatchCollection
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
patches_list = []
color_list = []
patches_list.append(matplotlib.patches.Rectangle((-200,-100), 400, 200))
color_list.append('yellow')
patches_list.append(matplotlib.patches.Rectangle((0,150), 300, 20))
color_list.append('red')
patches_list.append(matplotlib.patches.Rectangle((-300,-50), 40, 200))
color_list.append('#0099FF')
patches_list.append(matplotlib.patches.Circle((-200,-250), radius=90))
color_list.append('#EB70AA')
our_cmap = ListedColormap(color_list)
patches_collection = PatchCollection(patches_list, cmap=our_cmap)
patches_collection.set_array(np.arange(len(patches_list)))
ax.add_collection(patches_collection)
plt.xlim([-400, 400])
plt.ylim([-400, 400])
plt.show()
Result:
cmap_approach_result
I ran into this same issue. Passing in color= to Rectangle() will only work if you specify match_original=True when you create your PatchCollection(). See PatchCollection() for the details.
A simplified version of #Didillysquat's example is
import matplotlib.pyplot as plt
from matplotlib.collections import PatchCollection
fig = plt.figure()
ax = fig.add_subplot(111)
patches_list = []
color_list = []
patches_list.append(matplotlib.patches.Rectangle((-200,-100), 400, 200, color='yellow'))
patches_list.append(matplotlib.patches.Rectangle((0,150), 300, 20, color='red'))
patches_list.append(matplotlib.patches.Rectangle((-300,-50), 40, 200, color='#0099FF'))
patches_list.append(matplotlib.patches.Circle((-200,-250), radius=90, color='#EB70AA'))
# Make sure you use match_original=True
patches_collection = PatchCollection(patches_list, match_original=True)
ax.add_collection(patches_collection)
plt.xlim([-400, 400])
plt.ylim([-400, 400])
plt.show()