I want to change the colour of the points on a graph using RGB values - colors

I have a code where I can control the colour of using plot.plot but I was wondering is there another function I can use to use RBG values to control the colours of the point so instead of colour=‘w’ to get white i input (100,100,100) to get white points. Here’s the code I have it does what I want but i just want to add that one aspect.
import matplotlib.pyplot as plt
import numpy as np
import cv2
#Number of the shape or plotpoints
nx, ny = (100, 100)
x = np.linspace(50, 100, nx)
y = np.linspace(50, 100, ny)
xv, yv = np.meshgrid(x, y)
xv
array = ([[0. , 1, 1. ],
[0. , 1, 1. ]])
yv
array = ([[5., 5., 5.],
[5., 5., 5.]])
#Turns off axis and outline of the graph
plt.axis('off')
#Controls the size of the figure (Width, Height)
plt.rcParams["figure.figsize"] = (25,20)
#Control the margins around the grid [check back here] [https://www.tutorialspoint.com/how-to-set-the-margins-of-a-matplotlib-figure#:~:text=at%20index%202.-,Plot%20t%20and%20y%20data%20points%20using%20plot()%20method,figure%2C%20use%20show()%20method.]
#plt.margins(x=0.03, y=0.03)
bbox_inches='tight'
#Changes background colour [style references] [https://matplotlib.org/stable/gallery/style_sheets/style_sheets_reference.html])
plt.style.use('dark_background')
plt.plot(xv, yv, marker='s', color='w', linestyle='none', markersize=5)
plt.show()

Related

Is it possible to set (in `matplotlib`) `ax.grid` in such a way that lines will go just to bars instead of going by the whole chart?

Is it possible to set ax.grid in such a way that lines will go just to bars?
Below the regular output("before") and expected("after"):
My code:
fig, ax = plt.subplots(figsize=(15,6))
ax.set_axisbelow(True)
ax = data_test.bar(fontsize=15, zorder=1, color=(174/255, 199/255, 232/255)) # 'zorder' is bar layaut order
for p in ax.patches:
ax.annotate(s=p.get_height(),
xy=(p.get_x()+p.get_width()/2., p.get_height()),
ha='center',
va='center',
xytext=(0, 10),
textcoords='offset points')
ax.spines["right"].set_visible(False)
ax.spines["left"].set_visible(False)
ax.spines["top"].set_visible(False)
ax.spines["bottom"].set_visible(False)
ax.set_xticklabels(
data_test.index,
rotation=34.56789,
fontsize='xx-large'
) # We will set xticklabels in angle to be easier to read)
# The labels are centred horizontally, so when we rotate them 34.56789°
ax.grid(axis='y', zorder=0) # 'zorder' is bar layaut order
plt.ylim([4500, 5300])
plt.show()
You could draw horizontal lines instead of using grid lines.
You forgot to add test data, making it quite unclear of what type data_test could be.
The code below supposes data_test is a pandas dataframe, and that data_test.plot.bar() is called to draw a bar plot. Note that since matplotlib 3.4 you can use ax.bar_label to label bars.
from matplotlib import pyplot as plt
import pandas as pd
import numpy as np
data_test = pd.DataFrame({'height': np.random.randint(1000, 2000, 7).cumsum()},
index=['Alkaid', 'Mizar', 'Alioth', 'Megrez', 'Phecda', 'Merak', 'Dubhe'])
fig, ax = plt.subplots(figsize=(15, 6))
ax.set_axisbelow(True)
data_test.plot.bar(fontsize=15, zorder=1, color=(174 / 255, 199 / 255, 232 / 255), ax=ax)
for container in ax.containers:
ax.bar_label(container, fmt='%.0f', fontsize=15)
for spine in ax.spines.values():
spine.set_visible(False)
ax.set_xticklabels(data_test.index, rotation=34.56789, fontsize='xx-large')
ax.tick_params(length=0) # remove tick marks
xmin, xmax = ax.get_xlim()
ticks = ax.get_yticks()
tick_extends = [xmax] * len(ticks)
# loop through the bars and the ticks; shorten the lines whenever a bar crosses it
for bar in ax.patches:
for j, tick in enumerate(ticks):
if tick <= bar.get_height():
tick_extends[j] = min(tick_extends[j], bar.get_x())
ax.hlines(ticks, xmin, tick_extends, color='grey', lw=0.8, ls=':', zorder=0)
plt.tight_layout()
plt.show()

How to draw vertical average lines for overlapping histograms in a loop

I'm trying to draw with matplotlib two average vertical line for every overlapping histograms using a loop. I have managed to draw the first one, but I don't know how to draw the second one. I'm using two variables from a dataset to draw the histograms. One variable (feat) is categorical (0 - 1), and the other one (objective) is numerical. The code is the following:
for chas in df[feat].unique():
plt.hist(df.loc[df[feat] == chas, objective], bins = 15, alpha = 0.5, density = True, label = chas)
plt.axvline(df[objective].mean(), linestyle = 'dashed', linewidth = 2)
plt.title(objective)
plt.legend(loc = 'upper right')
I also have to add to the legend the mean and standard deviation values for each histogram.
How can I do it? Thank you in advance.
I recommend you using axes to plot your figure. Pls see code below and the artist tutorial here.
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
mu1, sigma1 = 100, 8
mu2, sigma2 = 150, 15
x1 = mu1 + sigma1 * np.random.randn(10000)
x2 = mu2 + sigma2 * np.random.randn(10000)
fig, ax = plt.subplots(1, 1, figsize=(7.2, 7.2))
# the histogram of the data
lbs = ['a', 'b']
colors = ['r', 'g']
for i, x in enumerate([x1, x2]):
n, bins, patches = ax.hist(x, 50, density=True, facecolor=colors[i], alpha=0.75, label=lbs[i])
ax.axvline(bins.mean())
ax.legend()

How can I get the size of subplots from ax in matplotlib? [duplicate]

Given a set of axes in matplotlib, is there a way to determine its size in pixels? I need to scale things according to adjust for larger or smaller figures.
(In particular I want to change the linewidth so it is proportionate for the axes size.)
This gives the width and height in inches.
bbox = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
width, height = bbox.width, bbox.height
That probably suffices for your purpose, but to get pixels, you can multiply by fig.dpi:
width *= fig.dpi
height *= fig.dpi
For example,
import matplotlib.pyplot as plt
def get_ax_size(ax):
bbox = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
width, height = bbox.width, bbox.height
width *= fig.dpi
height *= fig.dpi
return width, height
fig, ax = plt.subplots()
print(get_ax_size(ax))
#(496.0, 384.00000000000006)
ax2 = plt.axes([0.3, 0.3, 0.7, 0.7])
print(get_ax_size(ax2))
# (448.0, 336.0)
To make an image of exactly that figure size, you have to remove whitespace between the figure and the axis:
import numpy as np
import matplotlib.pyplot as plt
def get_ax_size(ax):
bbox = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
width, height = bbox.width, bbox.height
width *= fig.dpi
height *= fig.dpi
return width, height
data = np.arange(9).reshape((3, 3))
fig = plt.figure(figsize=(8,6), dpi=80)
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)
ax.imshow(data, aspect='equal')
print(get_ax_size(ax))
# (640.0, 480.0)
plt.savefig('/tmp/test.png', dpi=80)
% identify /tmp/test.png
/tmp/test.png PNG 640x480 640x480+0+0 8-bit DirectClass 50.5KB 0.020u 0:00.020

Stop axis from expanding matplotlib

I've been using the code from the site bellow to create and use check buttons for my subplot lines:
https://matplotlib.org/gallery/widgets/check_buttons.html
But i can't seem to keep the check button axes (rax) from expanding when i pull on the margins of the figure window, i would like only the plot with lines to expand. I've tried this but it doesn't seem to do the job:
t = np.arange(0.0, 2.0, 0.01)
s0 = np.sin(2*np.pi*t)
s1 = np.sin(4*np.pi*t)
s2 = np.sin(6*np.pi*t)
fig, ax = plt.subplots()
l0, = ax.plot(t, s0, visible=False, lw=2, color='k', label='2 Hz')
l1, = ax.plot(t, s1, lw=2, color='r', label='4 Hz')
l2, = ax.plot(t, s2, lw=2, color='g', label='6 Hz')
plt.subplots_adjust(left=0.2)
lines = [l0, l1, l2]
rax = plt.axes([0.05, 0.4, 0.1, 0.15])
rax.autoscale(enable=FALSE, tight=TRUE) #this is the part i don't want expanding
labels = [str(line.get_label()) for line in lines]
visibility = [line.get_visible() for line in lines]
check = CheckButtons(rax, labels, visibility)
def func(label):
index = labels.index(label)
lines[index].set_visible(not lines[index].get_visible())
plt.draw()
check.on_clicked(func)
plt.show()
Is there a way the do this?
Thanks!
The question can be translated into how to position an axes in figure coordinates with a fixed width and height in absolute (pixel) coordinates. This can be done via setting the axes locator to a
mpl_toolkits.axes_grid1.inset_locator.AnchoredSizeLocator via ax.set_axes_locator.
import matplotlib.pyplot as plt
import matplotlib.transforms as mtrans
from mpl_toolkits.axes_grid1.inset_locator import AnchoredSizeLocator
fig, ax = plt.subplots()
# Create axes, which is positionned in figure coordinates,
# with width and height fixed in inches.
# axes extent in figure coordinates (width & height ignored)
axes_extent = [0.03, 0.5, 0, 0]
# add axes to figure
rax = fig.add_axes(axes_extent)
# create locator: Position at (0.03, 0.5) in figure coordinates,
# 0.7 inches wide and tall, pinned at left center of bbox.
axes_locator = AnchoredSizeLocator(mtrans.Bbox.from_bounds(*axes_extent),
.7, .7, loc="center left",
bbox_transform=fig.transFigure,
borderpad=0)
rax.set_axes_locator(axes_locator)
Now, when the figure size changes, the axes will stay at the same relative position without changing its width and height.

matplotlib box on basemap map

I'm trying to draw a box on a map in relative coordinates (i.e. 0 to 1). The reason is I have a colorbar on my map, but cannot see it clearly. I want a transparent box behind it. I've looked at adding patch Rectangles (see Draw rectangle (add_patch) in pylab mode), but that is in data coordinates, which is not easy to determine on this map. I also found axhspan, which uses relative coordinates for the x span, but data coordinates for the y span.
Is there a way to draw a box in a matplotlib axes object using relative coordinates?
Here's a way to add a boxed text to a relative coordinates:
#!/usr/bin/python3
from matplotlib import pyplot as plt
x = range(5)
y = range(5)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y)
ax.text(0.5, 0.5,
"Relative coords!",
horizontalalignment = 'center',
backgroundcolor = "white",
verticalalignment = 'center',
bbox=dict(facecolor='white', edgecolor='green', alpha=0.65),
transform = ax.transAxes,
)
fig.savefig("mwe.png")
Result:
Edit:
To draw just a box given it's relative coordinates/dimensions with no text in it:
#!/usr/bin/python3
from matplotlib import pyplot as plt
from matplotlib.patches import Rectangle
x = range(5)
y = range(5)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y, zorder=1)
plt.gca().add_patch(Rectangle(
(0.4, 0.4), # lower left point of rectangle
0.2, 0.2, # width/height of rectangle
transform=ax.transAxes,
facecolor="white",
edgecolor='green',
alpha=0.65,
zorder=2,
))
fig.savefig("mwe.png")
Result:

Resources