Stylizing only some boxes with boxplots in matplotlib - matplotlib

How would you go about changing the style of only some boxes in a matplotlib boxplot? Below, you can see an example of styling, but I would like the style to only apply to one of the boxes.

The same question has been asked for seaborn boxplots already. For matplotlib boxplots this is even easier, since the boxplot directly returns a dictionary of the involved artists, see boxplot documentation.
This means that if bplot = ax.boxplot(..) is your boxplot, you may access the boxes via bplot['boxes'], select one of them and set its linestyle to your desire. E.g.
bplot['boxes'][2].set_linestyle("-.")
Modifying the boxplot_color example
import matplotlib.pyplot as plt
import numpy as np
# Random test data
np.random.seed(19680801)
all_data = [np.random.normal(0, std, size=100) for std in range(1, 4)]
labels = ['x1', 'x2', 'x3']
fig, ax = plt.subplots()
# notch shape box plot
bplot = ax.boxplot(all_data, vert=True, patch_artist=True, labels=labels)
# Loop through boxes and colorize them individually
colors = ['pink', 'lightblue', 'lightgreen']
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
# Make the third box dotted
bplot['boxes'][2].set_linestyle("-.")
plt.show()

Related

Is there a way to draw shapes on a python pandas plot

I am creating shot plots for NHL games and I have succeeded in making the plot, but I would like to draw the lines that you see on a hockey rink on it. I basically just want to draw two circles and two lines on the plot like this.
Let me know if this is possible/how I could do it
Pandas plot is in fact matplotlib plot, you can assign it to variable and modify it according to your needs ( add horizontal and vertical lines or shapes, text, etc)
# plot your data, but instead diplaying it assing Figure and Axis to variables
fig, ax = df.plot()
ax.vlines(x, ymin, ymax, colors='k', linestyles='solid') # adjust to your needs
plt.show()
working code sample
import pandas as pd
import matplotlib.pyplot as plt
import seaborn
from matplotlib.patches import Circle
from matplotlib.collections import PatchCollection
df = seaborn.load_dataset('tips')
ax = df.plot.scatter(x='total_bill', y='tip')
ax.vlines(x=40, ymin=0, ymax=20, colors='red')
patches = [Circle((50,10), radius=3)]
collection = PatchCollection(patches, alpha=0.4)
ax.add_collection(collection)
plt.show()

how to change color of axis in 3d matplotlib figure?

The color of the axis (x, y, z) in a 3d plot using matplotlib is black by default. How do you change the color of the axis? Or better yet, how do you make them invisible?
%matplotlib inline
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.xaxis.set_visible(False) # doesn't do anything
And there doesn't seem to be a ax.xaxis.set_color function. Any thoughts on how to make the axis invisible or change the color?
You can combine your method with the approach provided here. I am showing an example that affects all three axes. In Jupyter Notebook, using tab completion after ax.w_xaxis.line., you can discover other possible options
ax.w_xaxis.line.set_visible(False)
ax.w_yaxis.line.set_color("red")
ax.w_zaxis.line.set_color("blue")
To change the tick colors, you can use
ax.xaxis._axinfo['tick']['color']='r'
ax.yaxis._axinfo['tick']['color']='g'
ax.zaxis._axinfo['tick']['color']='b'
To hide the ticks
for line in ax.xaxis.get_ticklines():
line.set_visible(False)

Python - Rearrange Order of Labels in Pie Chart

I'm trying to do something pretty simple, but I'm a novice Python user so this has proven a little difficult for me. I'm trying to make pie charts and the labels for the charts are appearing for the wrong slices of pie.
Here is my code:
import matplotlib.pyplot as plt
# Data to plot
labels = data['Category'].unique()
sizes = (data['Category'].value_counts()/data['Category'].value_counts().sum())*100
# Plot
plt.pie(sizes, labels=labels,
autopct='%1.1f%%', shadow=True, startangle=140)
plt.axis('equal')
plt.legend(labels, loc="best")
plt.tight_layout()
plt.show()
This code produces a pie chart, but the labels in the legend do not match the labels on the chart. I've identified that this is due to the order with which the values of 'Category' appear in the data differ from the order of the values in the line where I define "sizes".
Does anyone know how to sync sizes and labels so the appropriate label is shown on the pie chart?
Any help would be appreciated! Thank you!
You can use labels = sizes.index so both will have the same order. If you want the labels sorted, you could first call sizes = sizes.sort_index(). Or, to have them sorted by value: sizes = sizes.sort_values(). Default, they would be sorted in order of appearance.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
data = pd.DataFrame({'Category': np.random.choice(list('abcdefghij'), 500)})
sizes = data['Category'].value_counts().sort_index() / data['Category'].value_counts().sum() * 100
plt.pie(sizes, labels=sizes.index,
autopct='%1.1f%%', shadow=True, startangle=140)
plt.axis('equal')
plt.legend(sizes.index, loc="best")
plt.tight_layout()
plt.show()

changing the size of subplots with matplotlib

I am trying to plot multiple rgb images with matplotlib
the code I am using is:
import numpy as np
import matplotlib.pyplot as plt
for i in range(0, images):
test = np.random.rand(1080, 720,3)
plt.subplot(images,2,i+1)
plt.imshow(test, interpolation='none')
the subplots appear tiny though as thumbnails
How can I make them bigger?
I have seen solutions using
fig, ax = plt.subplots()
syntax before but not with plt.subplot ?
plt.subplots initiates a subplot grid, while plt.subplot adds a subplot. So the difference is whether you want to initiate you plot right away or fill it over time. Since it seems, that you know how many images to plot beforehand, I would also recommend going with subplots.
Also notice, that the way you use plt.subplot you generate empy subplots in between the ones you are actually using, which is another reason they are so small.
import numpy as np
import matplotlib.pyplot as plt
images = 4
fig, axes = plt.subplots(images, 1, # Puts subplots in the axes variable
figsize=(4, 10), # Use figsize to set the size of the whole plot
dpi=200, # Further refine size with dpi setting
tight_layout=True) # Makes enough room between plots for labels
for i, ax in enumerate(axes):
y = np.random.randn(512, 512)
ax.imshow(y)
ax.set_title(str(i), fontweight='bold')

Matplotlib: Discrete colorbar fails for custom labels

I faced a serious problem when I was trying to add colorbar to scatter plot which indicates in which classes individual sample belongs to. The code works perfectly when classes are [0,1,2] but when the classes are for example [4,5,6] chooses colorbar automatically color values in the end of colormap and colorbar looks blue solid color. I'm missing something obvious but I just can't figure out what it is.
Here is the example code about the problem:
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(1 , figsize=(6, 6))
plt.scatter(datapoints[:,0], datapoints[:,1], s=20, c=labels, cmap='jet', alpha=1.0)
plt.setp(ax, xticks=[], yticks=[])
cbar = plt.colorbar(boundaries=np.arange(len(classes)+1)-0.5)
cbar.set_ticks(np.arange(len(classes)))
cbar.set_ticklabels(classes)
plt.show()
Variables can be for example
datapoints = np.array([[1,1],[2,2],[3,3],[4,4],[5,5],[6,6],[7,7]])
labels = np.array([4,5,6,4,5,6,4])
classes = np.array([4,5,6])
Correct result is got when
labels = np.array([0,1,2,0,1,2,0])
In my case I want it to work also for classes [4,5,6]
The buoundaries need to be in data units. Meaning, if your classes are 4,5,6, you probably want to use boundaries of 3.5, 4.5, 5.5, 6.5.
import matplotlib.pyplot as plt
import numpy as np
datapoints = np.array([[1,1],[2,2],[3,3],[4,4],[5,5],[6,6],[7,7]])
labels = np.array([4,5,6,4,5,6,4])
classes = np.array([4,5,6])
fig, ax = plt.subplots(1 , figsize=(6, 6))
sc = ax.scatter(datapoints[:,0], datapoints[:,1], s=20, c=labels, cmap='jet', alpha=1.0)
ax.set(xticks=[], yticks=[])
cbar = plt.colorbar(sc, ticks=classes, boundaries=np.arange(4,8)-0.5)
plt.show()
If you wanted to have the boundaries determined automatically from the classes, some assumption must me made. E.g. if all classes are subsequent integers,
boundaries=np.arange(classes.min(), classes.max()+2)-0.5
In general, an alternative would be to use a BoundaryNorm, as shown e.g. in Create a discrete colorbar in matplotlib
or How to specify different color for a specific year value range in a single figure? (Python) or python colormap quantisation (matplotlib)