Is there a simple way to increment the matplotlib color cycle without digging into axes internals?
When plotting interactively a common pattern I use is:
import matplotlib.pyplot as plt
plt.figure()
plt.plot(x,y1)
plt.twinx()
plt.plot(x,y2)
The plt.twinx() in necessary to get different y-scales for y1 and y2 but both plots are drawn with the first color in the default colorcycle making it necessary to manually declare the color for each plot.
There must be a shorthand way to instruct the second plot to increment the color cycle rather than explicitly giving the color. It is easy of course to set color='b' or color='r' for the two plots but when using a custom style like ggplot you would need need to lookup the color codes from the current colorcycle which is cumbersome for interactive use.
You could call
ax2._get_lines.get_next_color()
to advance the color cycler on color. Unfortunately, this accesses the private attribute ._get_lines, so this is not part of the official public API and not guaranteed to work in future versions of matplotlib.
A safer but less direct way of advance the color cycler would be to plot a null plot:
ax2.plot([], [])
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y1 = np.random.randint(10, size=10)
y2 = np.random.randint(10, size=10)*100
fig, ax = plt.subplots()
ax.plot(x, y1, label='first')
ax2 = ax.twinx()
ax2._get_lines.get_next_color()
# ax2.plot([], [])
ax2.plot(x,y2, label='second')
handles1, labels1 = ax.get_legend_handles_labels()
handles2, labels2 = ax2.get_legend_handles_labels()
ax.legend(handles1+handles2, labels1+labels2, loc='best')
plt.show()
Similar to the other answers but using matplotlib color cycler:
import matplotlib.pyplot as plt
from itertools import cycle
prop_cycle = plt.rcParams['axes.prop_cycle']
colors = cycle(prop_cycle.by_key()['color'])
for data in my_data:
ax.plot(data.x, data.y, color=next(colors))
There are several colour schemes available in Pyplot. You can read more on the matplotlib tutorial Specifying Colors.
From these docs:
a "CN" color spec, i.e. 'C' followed by a number, which is an index into the
default property cycle (matplotlib.rcParams['axes.prop_cycle']); the indexing
is intended to occur at rendering time, and defaults to black if the cycle
does not include color.
You can cycle through the colour scheme as follows:
fig, ax = plt.subplots()
# Import Python cycling library
from itertools import cycle
# Create a colour code cycler e.g. 'C0', 'C1', etc.
colour_codes = map('C{}'.format, cycle(range(10)))
# Iterate over series, cycling coloour codes
for y in my_data:
ax.plot(x, y, color=next(color_codes))
This could be improved by cycling over matplotlib.rcParams['axes.prop_cycle'] directly.
Related
I am trying to add a colorbar to the right side of my plot. It should show the color to the current iteration :
the code for my custom colorbar:
BLUE = '#00549F'
LIGHT_BLUE = "#407FB7"
LIGHTER_BLUE = '#8EBAE5'
LIGHTEST_BLUE = '#C7DDF2'
cmap = mcolors.LinearSegmentedColormap.from_list("n", [LIGHTEST_BLUE,LIGHTER_BLUE,LIGHT_BLUE,BLUE])
The plot shows the Force of a machine that repeats the same process like 3000 times. Now I want to color code the iteration number. Pandas offers the .plot(cmap=cmap) function which does that, but I don't know how to add the colorbar as an orientation for the viewer.
Code for the plots:
fig,axs = plt.subplots(2,1,figsize=(10,8))
df_data_blanking_stempel.plot(legend=False,colormap=cmap,ax=axs[0])
axs[0].set_title('Stamp')
axs[0].set_ylabel('Force[Newton]')
df_data_blanking_niederhalter.plot(legend=False,colormap=cmap,ax = axs[1])
axs[1].set_ylabel('Force[Newton]')
axs[1].set_xlabel('Time')
axs[1].set_title('Blankholder')
plt.suptitle(r'\textbf{Force Trajectories}',fontsize=16)
plt.show()
One idea I have, is to generate the colorbar with a heatmap and add adjust and add it later with photoshop. But I am sure there is a better solution.
Custom colorbars can be created from just a colormap (optionally together with a norm). Here is an example (as the question doesn't contain example data, some dummy labels are used):
from matplotlib import pyplot as plt
from matplotlib.cm import ScalarMappable
from matplotlib.colors import LinearSegmentedColormap
import numpy as np
BLUE = '#00549F'
LIGHT_BLUE = "#407FB7"
LIGHTER_BLUE = '#8EBAE5'
LIGHTEST_BLUE = '#C7DDF2'
cmap = LinearSegmentedColormap.from_list("n", [LIGHTEST_BLUE, LIGHTER_BLUE, LIGHT_BLUE, BLUE])
fig, axs = plt.subplots(nrows=2)
for ax in axs:
cbar = plt.colorbar(ScalarMappable(cmap=cmap), ax=ax, ticks=np.linspace(0, 1, 4))
cbar.ax.yaxis.set_ticklabels(['first', 'second', 'third', 'fourth'])
plt.tight_layout()
plt.show()
To create a colorbar similar to the one of the example heatmap, one could use:
plt.colorbar(ScalarMappable(cmap=cmap, norm=plt.Normalize(0, 850000)), ax=ax)
I am using matplotlib to create the plots. I have to identify each plot with a different color which should be automatically generated by Python.
Can you please give me a method to put different colors for different plots in the same figure?
Matplotlib does this by default.
E.g.:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)
plt.show()
And, as you may already know, you can easily add a legend:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)
plt.legend(['y = x', 'y = 2x', 'y = 3x', 'y = 4x'], loc='upper left')
plt.show()
If you want to control the colors that will be cycled through:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
plt.gca().set_color_cycle(['red', 'green', 'blue', 'yellow'])
plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)
plt.legend(['y = x', 'y = 2x', 'y = 3x', 'y = 4x'], loc='upper left')
plt.show()
If you're unfamiliar with matplotlib, the tutorial is a good place to start.
Edit:
First off, if you have a lot (>5) of things you want to plot on one figure, either:
Put them on different plots (consider using a few subplots on one figure), or
Use something other than color (i.e. marker styles or line thickness) to distinguish between them.
Otherwise, you're going to wind up with a very messy plot! Be nice to who ever is going to read whatever you're doing and don't try to cram 15 different things onto one figure!!
Beyond that, many people are colorblind to varying degrees, and distinguishing between numerous subtly different colors is difficult for more people than you may realize.
That having been said, if you really want to put 20 lines on one axis with 20 relatively distinct colors, here's one way to do it:
import matplotlib.pyplot as plt
import numpy as np
num_plots = 20
# Have a look at the colormaps here and decide which one you'd like:
# http://matplotlib.org/1.2.1/examples/pylab_examples/show_colormaps.html
colormap = plt.cm.gist_ncar
plt.gca().set_prop_cycle(plt.cycler('color', plt.cm.jet(np.linspace(0, 1, num_plots))))
# Plot several different functions...
x = np.arange(10)
labels = []
for i in range(1, num_plots + 1):
plt.plot(x, i * x + 5 * i)
labels.append(r'$y = %ix + %i$' % (i, 5*i))
# I'm basically just demonstrating several different legend options here...
plt.legend(labels, ncol=4, loc='upper center',
bbox_to_anchor=[0.5, 1.1],
columnspacing=1.0, labelspacing=0.0,
handletextpad=0.0, handlelength=1.5,
fancybox=True, shadow=True)
plt.show()
Setting them later
If you don't know the number of the plots you are going to plot you can change the colours once you have plotted them retrieving the number directly from the plot using .lines, I use this solution:
Some random data
import matplotlib.pyplot as plt
import numpy as np
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
for i in range(1,15):
ax1.plot(np.array([1,5])*i,label=i)
The piece of code that you need:
colormap = plt.cm.gist_ncar #nipy_spectral, Set1,Paired
colors = [colormap(i) for i in np.linspace(0, 1,len(ax1.lines))]
for i,j in enumerate(ax1.lines):
j.set_color(colors[i])
ax1.legend(loc=2)
The result is the following:
TL;DR No, it can't be done automatically. Yes, it is possible.
import matplotlib.pyplot as plt
my_colors = plt.rcParams['axes.prop_cycle']() # <<< note that we CALL the prop_cycle
fig, axes = plt.subplots(2,3)
for ax in axes.flatten(): ax.plot((0,1), (0,1), **next(my_colors))
Each plot (axes) in a figure (figure) has its own cycle of colors — if you don't force a different color for each plot, all the plots share the same order of colors but, if we stretch a bit what "automatically" means, it can be done.
The OP wrote
[...] I have to identify each plot with a different color which should be automatically generated by [Matplotlib].
But... Matplotlib automatically generates different colors for each different curve
In [10]: import numpy as np
...: import matplotlib.pyplot as plt
In [11]: plt.plot((0,1), (0,1), (1,2), (1,0));
Out[11]:
So why the OP request? If we continue to read, we have
Can you please give me a method to put different colors for different plots in the same figure?
and it make sense, because each plot (each axes in Matplotlib's parlance) has its own color_cycle (or rather, in 2018, its prop_cycle) and each plot (axes) reuses the same colors in the same order.
In [12]: fig, axes = plt.subplots(2,3)
In [13]: for ax in axes.flatten():
...: ax.plot((0,1), (0,1))
If this is the meaning of the original question, one possibility is to explicitly name a different color for each plot.
If the plots (as it often happens) are generated in a loop we must have an additional loop variable to override the color automatically chosen by Matplotlib.
In [14]: fig, axes = plt.subplots(2,3)
In [15]: for ax, short_color_name in zip(axes.flatten(), 'brgkyc'):
...: ax.plot((0,1), (0,1), short_color_name)
Another possibility is to instantiate a cycler object
from cycler import cycler
my_cycler = cycler('color', ['k', 'r']) * cycler('linewidth', [1., 1.5, 2.])
actual_cycler = my_cycler()
fig, axes = plt.subplots(2,3)
for ax in axes.flat:
ax.plot((0,1), (0,1), **next(actual_cycler))
Note that type(my_cycler) is cycler.Cycler but type(actual_cycler) is itertools.cycle.
I would like to offer a minor improvement on the last loop answer given in the previous post (that post is correct and should still be accepted). The implicit assumption made when labeling the last example is that plt.label(LIST) puts label number X in LIST with the line corresponding to the Xth time plot was called. I have run into problems with this approach before. The recommended way to build legends and customize their labels per matplotlibs documentation ( http://matplotlib.org/users/legend_guide.html#adjusting-the-order-of-legend-item) is to have a warm feeling that the labels go along with the exact plots you think they do:
...
# Plot several different functions...
labels = []
plotHandles = []
for i in range(1, num_plots + 1):
x, = plt.plot(some x vector, some y vector) #need the ',' per ** below
plotHandles.append(x)
labels.append(some label)
plt.legend(plotHandles, labels, 'upper left',ncol=1)
**: Matplotlib Legends not working
Matplot colors your plot with different colors , but incase you wanna put specific colors
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
plt.plot(x, x)
plt.plot(x, 2 * x,color='blue')
plt.plot(x, 3 * x,color='red')
plt.plot(x, 4 * x,color='green')
plt.show()
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from skspatial.objects import Line, Vector
for count in range(0,len(LineList),1):
Line_Color = np.random.rand(3,)
Line(StartPoint,EndPoint)).plot_3d(ax,c="Line"+str(count),label="Line"+str(count))
plt.legend(loc='lower left')
plt.show(block=True)
The above code might help you to add 3D lines with different colours in a randomized fashion. Your colored lines can also be referenced with a help of a legend as mentioned in the label="... " parameter.
Honestly, my favourite way to do this is pretty simple: Now this won't work for an arbitrarily large number of plots, but it will do you up to 1163. This is by using the map of all matplotlib's named colours and then selecting them at random.
from random import choice
import matplotlib.pyplot as plt
from matplotlib.colors import mcolors
# Get full named colour map from matplotlib
colours = mcolors._colors_full_map # This is a dictionary of all named colours
# Turn the dictionary into a list
color_lst = list(colours.values())
# Plot using these random colours
for n, plot in enumerate(plots):
plt.scatter(plot[x], plot[y], color=choice(color_lst), label=n)
This is matplotlib version 1.5.0. I cannot seem to set the rcParams in a way that violinpot will obey the facecolors. I've set both the prop_cyle and the facecolor keys for axes and patch respectively to no avail. For example the code below ....
import matplotlib
from cycler import cycler
matplotlib.rcParams['axes.prop_cycle'] = cycler('color', ['pink','purple','salmon'])
matplotlib.rcParams['patch.facecolor'] = 'pink'
matplotlib.rcParams['patch.edgecolor'] = 'blue'
import matplotlib.pyplot as plt
from numpy.random import randn
fig = plt.figure(figsize=(12,6))
X = randn(100)
ax = fig.add_subplot(121)
for i in range(3):
ax.hist(X+2*i)
ax = fig.add_subplot(122)
for i in range(3):
ax.violinplot(X+2*i)
plt.show()
.... produces:
It's hard to discern from the picture, but the edge color does in fact get set to blue in the violinplot. There seems to be a default alpha setting with violinplot which makes this not quite apparent. However, the facecolors obviously remain at the default. Why is this, and can I force it to use the rcParams values? I realize that I can set the facecolors manually after plotting, but I'd rather just have the plots obey the default.
the red and yellow colors are hard-coded in the code for violonplot unfortunately.
bodies += [fill(stats['coords'],
-vals + pos,
vals + pos,
facecolor='y',
alpha=0.3)]
(...)
artists['cmeans'] = perp_lines(means, pmins, pmaxes, colors='r')
I suggest you drop a feature request on the matplotlib github
I have some test data:
import numpy as np
x_data = np.arange(10)
y = np.random.rand(len(x_data))
With different properties
ix1 = x_data < 5
ix2 = x_data >= 5
I want to investigate the differences visually, but am messing the plot up:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_context('poster')
fig, ax = plt.subplots(figsize=(4, 4))
for i, x in enumerate(x_data):
if ix1[i]:
sns.set_palette('rainbow', sum(ix1))
if ix2[i]:
sns.set_palette('coolwarm', sum(ix2))
plt.plot(x, y[i], 'o', label='{}'.format(x))
plt.legend(loc='best', prop={'size': 6})
plt.show()
The result should be points 0-4 are rainbow (red-violet) and points 5-9 are coolwarm (blue-white-red), but instead:
So, two questions:
Is it ok to call sns.set_palette() after calling plt.subplots?
Is there a way to set the palette more than once?
No, because of the way matplotlib works, the color palette is a property of the Axes object and so whatever the currently set palette is at the time an Axes is created is what it's going to use. This is possible to get around if you want to hack on private attributes (see here), but I wouldn't really recommend that.
Here's what I could come up with in your case, using a somewhat different approach that might not be broadly applicable:
pal1 = sns.color_palette('rainbow', sum(ix1))
pal2 = sns.color_palette('coolwarm', sum(ix2))
fig, ax = plt.subplots(figsize=(4, 4))
ax.scatter(x_data[ix1], y[ix1], c=pal1, s=60, label="smaller")
ax.scatter(x_data[ix2], y[ix2], c=pal2, s=60, label="larger")
ax.legend(loc="lower right", scatterpoints=5)
FWIW, this visualization feels pretty complex and hard to process (and the two palettes you've chosen overlap a fair amount and aren't really appropriate for these data) so it might be worth starting with something simpler.
I am using matplotlib to create the plots. I have to identify each plot with a different color which should be automatically generated by Python.
Can you please give me a method to put different colors for different plots in the same figure?
Matplotlib does this by default.
E.g.:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)
plt.show()
And, as you may already know, you can easily add a legend:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)
plt.legend(['y = x', 'y = 2x', 'y = 3x', 'y = 4x'], loc='upper left')
plt.show()
If you want to control the colors that will be cycled through:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
plt.gca().set_color_cycle(['red', 'green', 'blue', 'yellow'])
plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)
plt.legend(['y = x', 'y = 2x', 'y = 3x', 'y = 4x'], loc='upper left')
plt.show()
If you're unfamiliar with matplotlib, the tutorial is a good place to start.
Edit:
First off, if you have a lot (>5) of things you want to plot on one figure, either:
Put them on different plots (consider using a few subplots on one figure), or
Use something other than color (i.e. marker styles or line thickness) to distinguish between them.
Otherwise, you're going to wind up with a very messy plot! Be nice to who ever is going to read whatever you're doing and don't try to cram 15 different things onto one figure!!
Beyond that, many people are colorblind to varying degrees, and distinguishing between numerous subtly different colors is difficult for more people than you may realize.
That having been said, if you really want to put 20 lines on one axis with 20 relatively distinct colors, here's one way to do it:
import matplotlib.pyplot as plt
import numpy as np
num_plots = 20
# Have a look at the colormaps here and decide which one you'd like:
# http://matplotlib.org/1.2.1/examples/pylab_examples/show_colormaps.html
colormap = plt.cm.gist_ncar
plt.gca().set_prop_cycle(plt.cycler('color', plt.cm.jet(np.linspace(0, 1, num_plots))))
# Plot several different functions...
x = np.arange(10)
labels = []
for i in range(1, num_plots + 1):
plt.plot(x, i * x + 5 * i)
labels.append(r'$y = %ix + %i$' % (i, 5*i))
# I'm basically just demonstrating several different legend options here...
plt.legend(labels, ncol=4, loc='upper center',
bbox_to_anchor=[0.5, 1.1],
columnspacing=1.0, labelspacing=0.0,
handletextpad=0.0, handlelength=1.5,
fancybox=True, shadow=True)
plt.show()
Setting them later
If you don't know the number of the plots you are going to plot you can change the colours once you have plotted them retrieving the number directly from the plot using .lines, I use this solution:
Some random data
import matplotlib.pyplot as plt
import numpy as np
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
for i in range(1,15):
ax1.plot(np.array([1,5])*i,label=i)
The piece of code that you need:
colormap = plt.cm.gist_ncar #nipy_spectral, Set1,Paired
colors = [colormap(i) for i in np.linspace(0, 1,len(ax1.lines))]
for i,j in enumerate(ax1.lines):
j.set_color(colors[i])
ax1.legend(loc=2)
The result is the following:
TL;DR No, it can't be done automatically. Yes, it is possible.
import matplotlib.pyplot as plt
my_colors = plt.rcParams['axes.prop_cycle']() # <<< note that we CALL the prop_cycle
fig, axes = plt.subplots(2,3)
for ax in axes.flatten(): ax.plot((0,1), (0,1), **next(my_colors))
Each plot (axes) in a figure (figure) has its own cycle of colors — if you don't force a different color for each plot, all the plots share the same order of colors but, if we stretch a bit what "automatically" means, it can be done.
The OP wrote
[...] I have to identify each plot with a different color which should be automatically generated by [Matplotlib].
But... Matplotlib automatically generates different colors for each different curve
In [10]: import numpy as np
...: import matplotlib.pyplot as plt
In [11]: plt.plot((0,1), (0,1), (1,2), (1,0));
Out[11]:
So why the OP request? If we continue to read, we have
Can you please give me a method to put different colors for different plots in the same figure?
and it make sense, because each plot (each axes in Matplotlib's parlance) has its own color_cycle (or rather, in 2018, its prop_cycle) and each plot (axes) reuses the same colors in the same order.
In [12]: fig, axes = plt.subplots(2,3)
In [13]: for ax in axes.flatten():
...: ax.plot((0,1), (0,1))
If this is the meaning of the original question, one possibility is to explicitly name a different color for each plot.
If the plots (as it often happens) are generated in a loop we must have an additional loop variable to override the color automatically chosen by Matplotlib.
In [14]: fig, axes = plt.subplots(2,3)
In [15]: for ax, short_color_name in zip(axes.flatten(), 'brgkyc'):
...: ax.plot((0,1), (0,1), short_color_name)
Another possibility is to instantiate a cycler object
from cycler import cycler
my_cycler = cycler('color', ['k', 'r']) * cycler('linewidth', [1., 1.5, 2.])
actual_cycler = my_cycler()
fig, axes = plt.subplots(2,3)
for ax in axes.flat:
ax.plot((0,1), (0,1), **next(actual_cycler))
Note that type(my_cycler) is cycler.Cycler but type(actual_cycler) is itertools.cycle.
I would like to offer a minor improvement on the last loop answer given in the previous post (that post is correct and should still be accepted). The implicit assumption made when labeling the last example is that plt.label(LIST) puts label number X in LIST with the line corresponding to the Xth time plot was called. I have run into problems with this approach before. The recommended way to build legends and customize their labels per matplotlibs documentation ( http://matplotlib.org/users/legend_guide.html#adjusting-the-order-of-legend-item) is to have a warm feeling that the labels go along with the exact plots you think they do:
...
# Plot several different functions...
labels = []
plotHandles = []
for i in range(1, num_plots + 1):
x, = plt.plot(some x vector, some y vector) #need the ',' per ** below
plotHandles.append(x)
labels.append(some label)
plt.legend(plotHandles, labels, 'upper left',ncol=1)
**: Matplotlib Legends not working
Matplot colors your plot with different colors , but incase you wanna put specific colors
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
plt.plot(x, x)
plt.plot(x, 2 * x,color='blue')
plt.plot(x, 3 * x,color='red')
plt.plot(x, 4 * x,color='green')
plt.show()
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from skspatial.objects import Line, Vector
for count in range(0,len(LineList),1):
Line_Color = np.random.rand(3,)
Line(StartPoint,EndPoint)).plot_3d(ax,c="Line"+str(count),label="Line"+str(count))
plt.legend(loc='lower left')
plt.show(block=True)
The above code might help you to add 3D lines with different colours in a randomized fashion. Your colored lines can also be referenced with a help of a legend as mentioned in the label="... " parameter.
Honestly, my favourite way to do this is pretty simple: Now this won't work for an arbitrarily large number of plots, but it will do you up to 1163. This is by using the map of all matplotlib's named colours and then selecting them at random.
from random import choice
import matplotlib.pyplot as plt
from matplotlib.colors import mcolors
# Get full named colour map from matplotlib
colours = mcolors._colors_full_map # This is a dictionary of all named colours
# Turn the dictionary into a list
color_lst = list(colours.values())
# Plot using these random colours
for n, plot in enumerate(plots):
plt.scatter(plot[x], plot[y], color=choice(color_lst), label=n)