Very quick question. I would like to change the font family of a legend within the following:
ax.legend(loc='upper left', fontsize='xx-small', fontfamily=???)
However, I know that fontfamily is the wrong keyword argument. My question is, what is the right kwarg to do this?
I'm not sure what the right argument is, or if this is even possible without changing default rc parameters...
I have looked on stack overflow and on a host of other sites and help guides, but nothing specific to this.
Legend has a keyword called prop (which is really for font properties ... why it's not fontprop or something like that I don't know) that you can use to specify font properties with a dictionary. Your line of code would look something like this if you wanted, say, the serif family:
ax.legend(loc='upper left', prop={'family':'serif', 'size':'xx-small'})
Notice you have to move the size specification into the dictionary with the rest, prop will override fontsize.
Related
I created a barh plot including xerr. For the caps of the errorbars I would like round edges. I tried to set the capstyle in the error_kw, which didn't work out.
bars = ax.barh(range(3), [1,2,3],
xerr=[0.5,0.4,0.3],
align='center', color='silver', height=0.5,
capsize=12, error_kw={'elinewidth':1, 'solid_capstyle':'round'})
I also tried to access the Line2D objects afterwards to change the capstyle, which also didn't work out.
bars.errorbar.lines[1][0].set_solid_capstyle('round')
Can someone please give me a hint what I'm doing wrong here?
I found the problem now, I had to access the private attribute of the cap. Instead of the method
cap.set_solid_capstyle('round')
I had to access the private attribute:
cap._marker._capstyle = "round"
Thanks for your comment anyway #tmdavison
Even though I set the plotting style in every plotting script manually right at the beginning of the code, directly after importing the modules, the figure-plotting-style to seaborn-whitegrid, the resulting figures comprise the plain matplotlib.pyplot standard white background without grid display, e.g. like this graph:
Therefore, I assume that setting the style has no effect on my scripts, but I can't tell where it goes wrong, or where the style changes back to default. It'd be practical to print out the currently active plotting style at any given point, e.g. during a debugging session.
This is how I set my plotting style:
import .....
import matplotlib.pyplot as plt
import .....
# * Set the matplotlib.pyplot default template (plotting style and background) *
plt.style.use('seaborn-whitegrid')
# Start of script #
...
I even inserted the line plt.style.use('seaborn-whitegrid') in my plotting-submodules, which the main script calls, but it doesn't seem to have an effect on the output.
EDIT on additional trials:
According to what was suggested below by #Bernardo Trindade, I replaced plt.style.use with mpl.style.use:
# * Set the matplotlib.pyplot default template (plotting style and background) *
mpl_plt_default_template = 'seaborn-whitegrid'
import matplotlib as mpl
mpl.style.use(mpl_plt_default_template)
What I also tried is temporary styling, but with no avail either:
# Set plotting style
with plt.style.context('seaborn-whitegrid'):
# * Instantiate figure
fig, axs = plt.subplots(rows, cols, figsize=(width, height))
....
All of the above has not lead to any difference in the output graphs; still showing the plain standard matplotlib background without grid etc.
System specifics:
Lubuntu 20.04 LTS,
python 3.9x,
VS Code
I don't think there's a variable that stores the name of the stylesheet currently used, as all the style information is kept in a large dictionary whose values are simply updated when calling matplotlib.style.use().
Have you tried:
import matplotlib as mpl
mpl.style.use('seaborn-whitegrid')
Finally I found the culprit:
ax.grid(which='both', alpha=1)
Previously, this line never caused an issue, the grids were displayed just fine.
By contrast, now this setting the grid like this renders the grid invisible.
1) CONCLUSION (short answer)
The easiest way to make it work, i.e. safeguard that the grid appears, is setting either the parameter b to True like so:
ax.grid(b=True, which='both', alpha=1)
Alternatively, the kwarg visible can be set to True like so:
ax.grid(which='both', alpha=1, visible=True)
I recommend using visible=True since the naming of the kwarg is more intuitive as to what it actually does, compared to the optional parameter merely called b.
2) ELABORATE ANSWER
The following information is based on the official matplotlib docs:
The allegedly optional parameter b must be set manually to True or False, because otherwise, it'll be set to None in this context,
even though the current docs state:
b : bool or None, optional
Whether to show the grid lines. If any kwargs are supplied, it is assumed you want the grid on and b will be set to True.
If b is None and there are no kwargs, this toggles the visibility of the lines.
NOTE on boolean parameter "b":
I've tried both True and False to find out that even False delivers a proper grid, which is counterintuitive.
On the contrary, when put explicitely to None, which is equivalent to passing nothing, the grid won't appear:
ax.grid(b=None, which='both', alpha=1)
As mentioned before, the grid is invisible in this context also with the following, which was my original code line:
ax.grid(which='both', alpha=1)
Skimming through the **kwargs revealed an extra visibility kwarg called visible:
NOTE on naming of the visibility kwarg in its docs:
Artist.set_visible(self, b)[source]
It is called b, just like the
optional parameter
of ax.grid().
I confirmed that they actually do the same thing.
The grid appears, when putting the visible-kwarg to True:
ax.grid(b=None, which='both', alpha=1, visible=True)
When put to contradictory values, the following error is thrown:
ValueError: 'b' and 'visible' specify inconsistent grid visibilities
This error is caused when employing one of the following two possibilities:
ax.grid(b=False, which='both', alpha=1, visible=True)
ax.grid(b=True, which='both', alpha=1, visible=False)
Eventually, to make the grid appear successfully, set either the parameter b to True like so:
ax.grid(b=True, which='both', alpha=1)
Alternatively, the kwarg visible can be set to True like so:
ax.grid(which='both', alpha=1, visible=True)
From what I understand of this documentation matplotlib provides 3 ways to change the style parameters for plotting (things like axes.grid). Those ways are: using style sheets to set many parameters at a time; setting specific parameters through matplotlib.rcParams or matplotlib.rc; or using a matplotlibrc file to set defaults.
I would like to understand if all of the parameters are accessible in each of the methods I listed above and where I can find a comprehensive list of all of the parameters.
I have tried to understand this from the linked documentation, but I often fail. A specific example is setting the axis font. I typically use a combination like this:
axis_font = {'fontname':'Arial', 'size':'32'}
ax.set_ylabel('some axis title',**axis_font)
But it is not clear what matplotlib parameter (if any) I have set. Does there exist a parameter for the axis font that could be included in a style file for example?
Other attempts in my code include confusing blocks like:
legend_font = {'fontname':'Arial', 'size':'22'}
#fonts global settings
matplotlib.rc('font',family=legend_font['fontname'])
By the names it seems like it would be changing the legend font, but actually it is clearly setting the parameter for the overall font. And the size is not being used. Are there matplotlib parameters for specifically the legend font and legend size?
The things I've tried are:
Checking the example matplotlibrc at the bottom of the linked page (no sign of axis or legend fonts specifically)
Printing matplotlib.rcParams (no sign of axis or legend fonts)
Checking the axis api (could not match up with example style files e.g. the classic predefined style file has facecolor set, which is mentioned in that page, but it also has edgecolor set which is not mentioned on the page)
The rcParams property which changes the font is font.family it accepts 'serif', 'sans-serif', 'cursive', 'fantasy', and 'monospace' as outlined in the linked sample matplotlibrc file. If text.usetex is False it also accepts any concrete font name or list of font names - which will be tried in the order they are specified until one works.
This method applies the specified font name to the entire figure (and to all figures when done globally). If you want to modify the font family for an individual Text instance (i.e. an axis label) you can use matplotlib.text.Text.set_family() (which is an alias for matplotlib.text.Text.set_fontfamily())
import matplotlib.pyplot as plt
ylabel = plt.ylabel("Y Label")
ylabel.set_family("DejaVu Serif")
plt.xlabel("X Label")
plt.show()
And to set the font family for just a legend instance you can use plt.setp, e.g.
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
ylabel = plt.ylabel("Y Label")
plt.xlabel("X Label")
ylabel.set_family("DejaVu Serif")
legend = plt.legend(handles = [mpatches.Patch(color='grey', label="Label")])
plt.setp(legend.texts, family="EB Garamond")
plt.show()
Note that this method will not work when text.usetex is True.
I am wondering how to set the font of xlabel to be Arial using matplotlib. I checked functions like Axes.set_xlabel but does not see options to change that.
The Axes.set_xlabel and pyplot's xlabel functions can take the same keyword arguments as the Text class. This is noted in the documentation in the Other Parameters section.
One of these arguments is family, which can be used to set the font by family ('serif', 'sans-serif', etc., as shown in the font demo) or by font name. In your case it could be as simple as
plt.xlabel('My Label', family='Arial')
or
ax.set_xlabel('My Label', family='Arial')
# Assuming ax is an instance of Axes.
I have a little Bokeh plot with data points and associated text labels. What I want is for the text labels to only appear when the user selects points with the box select tool. This gets me close:
from bokeh.plotting import ColumnDataSource,figure,show
source = ColumnDataSource(
data=dict(
x=test[:,0],
y=test[:,1],
label=[unquote_plus(vocab_idx[i]) for i in range(len(test))]))
TOOLS="box_zoom,pan,reset,box_select"
p = figure(plot_width=400, plot_height=400,tools=TOOLS)
p.circle(x='x',y='y', size=10, color="red", alpha=0.25,source=source)
renderer = p.text(x='x',y='y',text='label',source=source)
renderer.nonselection_glyph.text_alpha=0.
show(p)
This is close, in that if I draw a box around some points, those text labels are shown and the rest are hidden, but the problem is that it renders all the text labels to start (which is not what I want). The initial plot should have all labels hidden, and they should only appear upon a box_select.
I thought I could start by rendering everything with alpha=0.0, and then setting a selection_glyph parameter, like this:
...
renderer = p.text(x='x',y='y',text='label',source=source,alpha=0.)
renderer.nonselection_glyph.text_alpha=0.
renderer.selection_glyph.text_alpha=1.
...
But this throws an error:
AttributeError: 'NoneType' object has no attribute 'text_alpha'
When trying to access the text_alpha attribute of selection_glyph.
I know I could use a hover effect here or similar, but need the labels to default to not being visible. An alternative, but not ideal, solution would be to have a toggle button that switches the labels on and off, but I'm not sure how to do that either.
What am I doing wrong here?
As of version 0.11.1, the value of selection_glyph is None by default. This is interpreted by BokehJS as "don't do anything different, just draw the glyph as normal". So you need to actually create a selection_glyph. There are two ways to do this, both demonstrated here:
http://docs.bokeh.org/en/latest/docs/user_guide/styling.html#selected-and-unselected-glyphs
Basically, they are
by hand
Create an actual Circle Bokeh model, something like:
selected_circle = Circle(fill_alpha=1, fill_color="firebrick", line_color=None)
renderer.selection_glyph = selected_circle
OR
using glyph method parameters
Alternatively, as a convenience Figure.circle accepts paramters like selection_fill_alpha or selection_color (basically any line or fill or text property, prefixed with selection_) :
p.circle(..., selection_color="firebrick")
Then a Circle will be created automatically and used for renderer.selection_glyph
I hope this is useful information. If so, it highlights that there are two possible ways that the project could be improved:
updating the docs to be explicit and highlight that renderer.selection_glyph is None by default
changing code so that renderer.selection_glyph is just a copy of renderer.glyph by default (then your original code would work)
Either would be small in scope and ideal for a new contributor. If you would be interested in working up a Pull Request to do either of these tasks, we (and other users) would certainly be grateful for the contribution. In which case, please just make an issue first at
https://github.com/bokeh/bokeh/issues
that references this discussion, and we can provide more details or answer any questions.