Matplotlib's violinplot doesn't follow rcParam - python

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

Related

Adding the range of colorbar to a pandas subplot

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)

In matplotlib 2.0, how do I revert colorbar behaviour to that of matplotlib 1.5?

I just upgraded to matplotlib 2.0 and in general, I'm very happy with the new defaults. One thing which I'd like to revert to the 1.5 behaviour is that of plt.colorbar, specifically the yticks. In the old matplotlib, only major ticks were plotted on my colorbars; in the new matplotlib, minor and major ticks are drawn, which I do not want.
Below is shown a comparison of the 1.5 behaviour (left) and the 2.0 behaviour (right) using the same colormap and logarithmic ticks.
What defaults do I need to set in matplotlibrc in order to revert to the 1.5 behaviour shown on the left? If there is no way to do this using matplotlibrc, what other avenues are available for altering this globally beyond downgrading to matplotlib 1.5?
I have tried simply setting cbar.ax.minorticks_off() after every instance of cbar = plt.colorbar(mesh), but that doesn't solve the issue.
It should be sufficient to just set the colorbar locator to a LogLocator from the matplotlib.ticker module, and then call update_ticks() on the colorbar instance.
For example, consider this minimal example which produces the colorbar you are seeing with minor ticks:
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.colors as colors
import numpy as np
fig, ax = plt.subplots(1)
# Some random data in your range 1e-26 to 1e-19
data = 10**(-26. + 7. * np.random.rand(10, 10))
p = ax.imshow(data, norm=colors.LogNorm(vmin=1e-26, vmax=1e-19))
cb = fig.colorbar(p, ax=ax)
plt.show()
If we now add the following two lines before calling plt.show(), we remove the minor ticks:
cb.locator = ticker.LogLocator()
cb.update_ticks()
Alternatively, to achieve the same thing, you can use the ticks kwarg when creating the colorbar, and set that to the LogLocator()
cb = fig.colorbar(p, ax=ax, ticks=ticker.LogLocator())

How do I fill a region with only hatch (no background colour) in matplotlib 2.0

With the recent updates to matplotlib fill_between and hatch (see links here), hatch filled regions are no longer behaving as they did previously. That is, the region is either filled with color, and hatches are black or the region isn't filled with color and hatches aren't visible.
Here is a side-by-side comparison of plots from the same code (from this answer)
import matplotlib.pyplot as plt
import matplotlib as mpl
plt.plot([0,1],[0,1],ls="--",c="b")
plt.fill_between([0,1],[0,1], color="none", hatch="X", edgecolor="b", linewidth=0.0)
plt.show()
is there a way to reproduce the 1.X plot in 2.X? I'm not at all familiar with back-ends but mpl.rcParams['hatch.color'] = 'b' and variations of the keywords color, edgecolor aren't helping.
Thanks in advance for helping to clear this up.
matplotlib > 2.0.1
Since there was a lot of discussion on GitHub about hatching, there were now some changes introduced which make hatching much more intuitive.
The example from the question now works again as expected, if the facecolor argument is used instead of the color argument.
import matplotlib.pyplot as plt
plt.plot([0,1],[0,1],ls="--",c="b")
plt.fill_between([0,1],[0,1], facecolor="none", hatch="X", edgecolor="b", linewidth=0.0)
plt.show()
matplotlib 2.0.0
To keep the original post, which has lead to this issue:
In matplotlib 2.0.0 you can get the old style back by using plt.style.use('classic').
##Classic!
import matplotlib.pyplot as plt
plt.style.use('classic')
plt.rcParams['hatch.color'] = 'b'
plt.plot([0,1],[0,1],ls="--",c="b")
plt.fill_between([0,1],[0,1], color="none", hatch="X", edgecolor="b", linewidth=0.0)
plt.show()
Without setting the old style the following works by not setting the color to none, but instead make it transparent.
## New
import matplotlib.pyplot as plt
plt.rcParams['hatch.color'] = 'b'
plt.plot([0,1],[0,1],ls="--",c="b")
plt.fill_between([0,1],[0,1], hatch="X", linewidth=0.0, alpha=0.0)
plt.show()
Both methods rely on setting the hatch-color via plt.rcParams['hatch.color'] = 'b'.
Unfortunately, there is currently no other way of setting the hatch color in matplotlib 2.0.0.
The matplotlib page that explains the changes states
There is no API level control of the hatch color or linewidth.
There is an issue on this topic open at github and API control may be (re)added in an upcoming version (which is indeed done with version 2.0.1).
With the release of matplotlib 2.0.1 we now have much better control of the hatching.
Currently, the only way I can find to remove the background colour (as asked) is to set color = None, alpha = 0 in the fill_between args. This works as requested but unfortunately results in pretty useless legends.
Thanks to QuLogic pointing out I should be using facecolor = 'none' this now works perfectly.
from matplotlib import pyplot as plt
import numpy as np
def plt_hist(axis, data, hatch, label):
counts, edges = np.histogram(data, bins=int(len(data)**.5))
edges = np.repeat(edges, 2)
hist = np.hstack((0, np.repeat(counts, 2), 0))
outline, = ax.plot(edges,hist,linewidth=1.3)
axis.fill_between(edges,hist,0,
edgecolor=outline.get_color(), hatch = hatch, label=label,
facecolor = 'none') ## < removes facecolor
axis.set_ylim(0, None, auto = True)
h1 = '//'
d1 = np.random.rand(130)
lab1 = 'Rand1'
h2 = '\\\\'
d2 = np.random.rand(200)
lab2 = 'Rand2'
fig, ax = plt.subplots(1)
plt_hist(ax,d1,h1,lab1)
plt_hist(ax,d2,h2,lab2)
ax.legend()

Increment matplotlib color cycle

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.

Seaborn: how to set bar borders' line width or color?

I am trying to draw a barplot with bars with no borders. By default bars has thin black borders. In the devlopment version (0.6) of Seaborn, I could pass kwargs (linewidth, edgecolor) to pyplot.bar() via seaborn.barplot(), but in the current version (0.5.1) this feature seems not yet available. Looking at the returned AxesSubplot object, I could not find the way to set the line width to zero, or the color to fully transparent, although it has many methods, so I still hope there is a way to achieve this.
import matplotlib.pyplot as plt
import seaborn as sns
fig, ax = plt.subplots()
ax = sns.barplot(data = data, x = 'var1', color = '#007b7f')
fig.tight_layout()
fig.savefig('fig.pdf')
After many attempts without success, I asked the question here, and soon I found the solution myself. So here it is: before plotting, the patch.linewidth parameter can be set with seaborn.set_context():
import seaborn as sns
sns.set_context(rc = {'patch.linewidth': 0.0})
ax = sns.barplot(...)
This will work too:
fig, ax = plt.subplots()
ax = sns.barplot(data = data, x = 'var1', color = '#007b7f')
plt.setp(ax.patches, linewidth=0)

Categories