Matplotlib fade line behind transparent text box - text

I would like to place a text box directly over a line plot that would cause the line at that point to 'fade', for legibility. My first thought is to change alpha of the text box. However that requires me to set a background colour, which I do not want (the plot background is currently transparent, which I would like to keep). There may be other elements of various shapes/colours that would be similarly stacked under the text. Ideally, what I want is a semi-opaque text box that has no colour of its own, but which would cause elements underneath the text box to be half-hidden. Alpha seems to be not the way to go, but is there another attribute that I can modify?
import matplotlib.pyplot as plt
import pandas as pd
pd.set_option("display.mpl_style", 'default')
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
ax1.plot((0,1),(0.5,0.5), "--",lw=2);
ax1.plot((0,0.25,0.5,0.75,1),(0,0.25,0.5,0.75,1), "go--",markersize=20)
ax1.text(0.25, 0.5, "HardToRead", fontsize=12,ha="center",va="center", bbox=dict(boxstyle="square,pad=0.1", fc='white', ec="white", lw=1,alpha=0.1))
ax1.text(0.75, 0.5, "EasyToRead", fontsize=12,ha="center",va="center", bbox=dict(boxstyle="square,pad=0.1", fc='white', ec="white", lw=1,alpha=0.9))
ax1.text(0.5, 0.5, "CrossTalk", fontsize=12,ha="center",va="center", rotation=90, bbox=dict(boxstyle="square,pad=0.1", fc='white', ec="white", lw=1,alpha=0.6))

Related

Putting text from one corner to the opposite one

I'd like my plot to have a background text to be stretched from one corner (say lower left) to the opposite corner. The x and y dimensions are not isometric and it's not a square plot, so a fixed angle of 45 degrees will not work.
So far I have the text starting in the correct corner. How can the text be rotated and stretched so it spans the entire plot?
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
# plot command not shown
ax.text(ax.get_xlim()[0], ax.get_ylim()[0] , 'PRELIMINARY' , rotation=45 )
To position something with respect to the subplot (the ax), it helps to work in axes coordinates. These go from 0,0 in the lower left to 1,1 in the top right. Putting the text at 0.5,0.5 would set it nicely centered.
To calculate the angle, one could divide the subplot's height in pixels by its width, then take the arc tangent, and convert from radians to degrees.
The optimal size for the text is harder to calculate. One would need to render it, measure it, change the font size and render it again. Or just manually try a few sizes until it looks OK.
Note that when the window size gets changed interactively, the text will stay nicely in the center, but the rotation will get a bit off.
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.text(0.5, 0.5, 'PRELIMINARY', transform=ax.transAxes, size=50,
rotation=np.degrees(np.arctan(ax.get_window_extent().height / ax.get_window_extent().width)),
ha='center', va='center')
plt.show()

How to change the font weight of individual colorbar labels?

I would like to have different font weights for each of my colorbar labels.
I have tried to let LaTeX format the labels in the following way:
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
im = ax.imshow(np.random.rand(50, 50)/20)
cbar = ax.figure.colorbar(im, ticks=np.arange(0, 0.05, 0.01))
cbar.ax.set_yticklabels([r'{\fontsize{50pt}{3em}\selectfont{}{0}}',
r'{\fontsize{40pt}{3em}\selectfont{}{0.01}}',
r'{\fontsize{30pt}{3em}\selectfont{}{0.03}}',
r'{\fontsize{20pt}{3em}\selectfont{}{0.03}}',
r'{\fontsize{10pt}{3em}\selectfont{}{0.04}}',
r'{\fontsize{1pt}{3em}\selectfont{}{0.05}}', ])
but this only updates the text of the labels to the whole string (e.g., {\fontsize{50pt}{3em}\selectfont{}{0}}). The pyplot TeX demo works for me. Even if this solution would work it would not be ideal as I would probably need to specify everything manually.
Much more convenient would be something like in this question. There, I learned that the font size of single labels of the regular x and y axis can be updated by calling
label = axes.yaxis.get_major_ticks()[2].label
label.set_fontsize(size)
replacing set_fontsize by set_fontweight correctly updates the weight of the selected label.
Unfortunately I could not find the equivalent of axes.yaxis.get_major_ticks()[2].label for the colorbar.
Is it possible to change the font weight of individual labels of the colorbar directly? With directly I mean without using a workaround like plotting some new text above existing labels.
If this is not possible a solution plotting text above existing labels which automatically uses the position and content the previous labels and only adjusts the font weight would also be appreciated.
Thanks!
As pointed out by #ImportanceOfBingErnest , set_fontweight works for setting the weight of single colorbar labels too.
I had to try a couple of things to find which call would give me the text objects defining the colorbar labels. They are accessible in cbar.ax.get_yticklabels().
The code snippet below now properly changes the weight of the second colorbar label:
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
im = ax.imshow(np.random.rand(50, 50)/20)
cbar = ax.figure.colorbar(im, ticks=np.arange(0, 0.05, 0.01))
cbar.ax.get_yticklabels()[1].set_fontweight(1000)
plt.show()
Output of code (not enough reputation for inline images)

Change the automatic color of matplotlib to hex colors automatically python3

I created a pie chart using matplotlib and I'd like to change the default colors to more softer colors, such as the hex RGB or RGBA string colors. I have the below script so far:
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
explode = ((0.05,)*(len(annotation_df.index)))
fig1, ax1 = plt.subplots()
ax1.pie(annotation_df['count'], labels=annotation_df['annotation'], autopct='%1.1f%%', startangle=90, pctdistance=0.85, explode=explode,colors=colors) #colors=colors,
# draw circle
centre_circle = plt.Circle((0, 0), 0.70, fc='white')
fig = plt.gcf()
fig.gca().add_artist(centre_circle)
# Equal aspect ratio ensures that pie is drawn as a circle
ax1.axis('equal')
plt.tight_layout()
plt.show()
The problem is I need the colors to be set automatically, and I don't want specifically write the colors, as written above in the script.
Anyone knows how to do it?
You may define a color cycler to contain the colors you want to use.
import matplotlib.pyplot as plt
plt.rcParams['axes.prop_cycle'] = plt.cycler('color',
['#ff9999', '#66b3ff', '#99ff99', '#ffcc99'])
fig1, ax1 = plt.subplots()
ax1.pie([1,2,3], labels=list("ABC"), autopct='%1.1f%%')
ax1.axis('equal')
plt.tight_layout()
plt.show()
If you have less wedges than colors in the cycler only the those colors needed are used. If you have more wedges than colors in the cycler, they would be repeated. You can put as many colors as you like into the color cycler.

better piechart color scheme

I am trying to create a pie chart, as follows:
import matplotlib.pyplot as plt
import pandas as pd
# make a square figure and axes
plt.figure(1, figsize=(10,10))
plt.axes([0.01, 0.1, 0.6, 0.6])
# plt.style.use('fivethirtyeight')
# The slices will be ordered and plotted counter-clockwise.
labels = 'foo1', 'foo2', 'foo3', 'foo4'
fracs = pd.Series([10,30, 50,10],index=labels)
fracs.plot(kind='pie', labels=None, autopct='%1.0f%%')
plt.legend(bbox_to_anchor=(0.95, .9), loc=2, borderaxespad=0.,labels=labels)
plt.title('pie chart demo which should be center aligned not left', bbox={'facecolor':'0.8', 'pad':5})
plt.show()
Which is yeilding a piechart as:
But, I am facing two problem:
1) I dont like the color scheme. I would like a color scheme more inline with (I need 12 colors)
2) Titel is centered at the pie chart only. The legend is somehow out. I am trying to get the title centered over the chart and the legend.
Can someone kindly help?
I think that is a ggplot colorscheme that you are trying to emulate.
And your plt.axes command is what is displacing your chart to the left.
Try this:
import matplotlib.pyplot as plt
plt.style.use('ggplot')
plt.figure(1, figsize=(10,10))
labels = 'foo1', 'foo2', 'foo3', 'foo4'
sizes = [10,30, 50,10]
plt.pie(sizes, labels=labels)
plt.show()

Responsive text in Matplotlib in Python

I am developing a simple graph visualizer using networkX and Matplotlib in Python. I also have some buttons plotted with text in them. As a whole the design is responsive which means that the graph and the buttons scale when I resize the window. However, the text size remains the same which makes the whole visualizer look very bad when not resized enough. Do you know how I can make the text also responsive?
Thank you in advance!!!
You update the fontsize of a matplotlib.text.Text using text.set_fontsize(). You can use a "resize_event" to call a function that sets a new fontsize. In order to do this with every text in a plot, it might be helpful to define a class that stores initial figure height and fontsizes and updates the fontsizes once the figure is resized, scaled by the new figure height divided by the initial one.
You may then also define a minimal readable fontsize, below which the text should not be resized.
A full example:
import matplotlib.pyplot as plt
import numpy as np
class TextResizer():
def __init__(self, texts, fig=None, minimal=4):
if not fig: fig = plt.gcf()
self.fig=fig
self.texts = texts
self.fontsizes = [t.get_fontsize() for t in self.texts]
_, self.windowheight = fig.get_size_inches()*fig.dpi
self.minimal= minimal
def __call__(self, event=None):
scale = event.height / self.windowheight
for i in range(len(self.texts)):
newsize = np.max([int(self.fontsizes[i]*scale), self.minimal])
self.texts[i].set_fontsize(newsize)
fontsize=11
text = plt.text(0.7, 0.6, "Some text", fontsize=fontsize,
bbox={'facecolor':'skyblue', 'alpha':0.5, 'pad':10})
cid = plt.gcf().canvas.mpl_connect("resize_event", TextResizer([text]))
plt.show()

Resources