Let's assume I have pandas dataframe looking like this:
import pandas as pd
df=pd.DataFrame({'run-1a':[0.3, 0.3, 0.4, 0.4], 'run-1b':[0.3, 0.3, 0.4, 0.5],"run-2a":[0.7, 0.9, 0.8, 0.9],"run-2b":[0.2, 0.3, 0.5, 0.5], "Person":["person1","person2","person3","person4"]})
df
and now I make a bar out of it:
import matplotlib.pyplot as plt
color_list = ['b','lightskyblue', 'g','lightgreen']
ax = df.plot(x='Person',y=['run-1a','run-1b','run-2a','run-2b'], kind='bar', color=color_list)
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.xticks(rotation="horizontal")
plt.show()
and the result looks like this:
However I'd like to group run-1a with run1b and run2a with run2b for each of the persons. When I googled some solutions, I found only how to make grouped bars looking like my plot above, which I don't need.
This is sketch how my plot should look like:
Is there an option how to group it like that for each person,please?
Thank you very much.
If I understood correctly, You can just add empty bar between other bars, so that You will get 4 columns, where each two bars are separated.
import pandas as pd
df=pd.DataFrame({'':[0,0,0,0],'run-1a':[0.3, 0.3, 0.4, 0.4], 'run-1b':[0.3, 0.3, 0.4, 0.5],"run-2a":[0.7, 0.9, 0.8, 0.9],"run-2b":[0.2, 0.3, 0.5, 0.5], "Person":["person1","person2","person3","person4"]})
color_list = ['b','lightskyblue','w', 'g','lightgreen']
ax = df.plot(x='Person',y=['run-1a','run-1b','','run-2a','run-2b'], kind='bar', color=color_list)
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.xticks(rotation="horizontal")
plt.show()
Related
I am creating subplots in matplotlib but not all xticks and yticks are being displayed. I have tried everything from setting xlim and ylim, chainging figure size etc. The thing is this is a handson on hackerrnak and they are evaluating my output against their expected output. The 0.0 in xaxis and 1.0 on yaxis are simply not matching up. What am I doing wrong here.
Here is the code,
import matplotlib.pyplot as plt
import numpy as np
def test_generate_figure2():
np.random.seed(1000)
x = np.random.rand(10)
y = np.random.rand(10)
z = np.sqrt(x**2 + y**2)
fig = plt.figure(figsize=(8,6))
axes1 = plt.subplot(2, 2, 1, title="Scatter plot with Upper Triangle Markers")
axes1.set_xticks([0.0, 0.4, 0.8, 1.2])
axes1.set_yticks([-0.2, 0.2, 0.6, 1.0])
axes1.set_ylim(-0.2,1.0) #Doing this still doesnot get the expected output
axes1.set_xlim(0.0,1.2)
print(axes1.get_yticks())
axes1.scatter(x, y, marker="^", s=80, c=z)
axes2 = plt.subplot(2, 2, 2, title="Scatter plot with Plus Markers")
axes2.set_xticks([0.0, 0.4, 0.8, 1.2])
axes2.set_yticks([-0.2, 0.2, 0.6, 1.0])
axes2.scatter(x, y, marker="+", s=80, c=z)
axes3 = plt.subplot(2, 2, 3, title="Scatter plot with Circle Markers")
axes3.set_xticks([0.0, 0.4, 0.8, 1.2])
axes3.set_yticks([-0.2, 0.2, 0.6, 1.0])
axes3.scatter(x, y, marker="o", s=80, c=z)
axes4 = plt.subplot(2, 2, 4, title="Scatter plot with Diamond Markers")
axes4.set_xticks([0.0, 0.4, 0.8, 1.2])
axes4.set_yticks([-0.2, 0.2, 0.6, 1.0])
axes4.scatter(x, y, marker="d", s=80,c=z)
plt.tight_layout()
plt.show()
test_generate_figure2()
My Output,
Expected Output,
Your set_xlim & set_ylim approach works. You just need to set it for every subplot:
https://akuiper.com/console/5vaLIq0ZC_KO
import matplotlib.pyplot as plt
import numpy as np
def test_generate_figure2():
np.random.seed(1000)
x = np.random.rand(10)
y = np.random.rand(10)
z = np.sqrt(x**2 + y**2)
fig = plt.figure(figsize=(8,6))
axes1 = plt.subplot(2, 2, 1, title="Scatter plot with Upper Triangle Markers")
axes1.set_xticks([0.0, 0.4, 0.8, 1.2])
axes1.set_yticks([-0.2, 0.2, 0.6, 1.0])
axes1.set_ylim(-0.2,1.0) #Doing this still doesnot get the expected output
axes1.set_xlim(0.0,1.2)
print(axes1.get_yticks())
axes1.scatter(x, y, marker="^", s=80, c=z)
axes2 = plt.subplot(2, 2, 2, title="Scatter plot with Plus Markers")
axes2.set_xticks([0.0, 0.4, 0.8, 1.2])
axes2.set_yticks([-0.2, 0.2, 0.6, 1.0])
axes2.set_ylim(-0.2,1.0) #Doing this still doesnot get the expected output
axes2.set_xlim(0.0,1.2)
axes2.scatter(x, y, marker="+", s=80, c=z)
axes3 = plt.subplot(2, 2, 3, title="Scatter plot with Circle Markers")
axes3.set_xticks([0.0, 0.4, 0.8, 1.2])
axes3.set_yticks([-0.2, 0.2, 0.6, 1.0])
axes3.set_ylim(-0.2,1.0) #Doing this still doesnot get the expected output
axes3.set_xlim(0.0,1.2)
axes3.scatter(x, y, marker="o", s=80, c=z)
axes4 = plt.subplot(2, 2, 4, title="Scatter plot with Diamond Markers")
axes4.set_xticks([0.0, 0.4, 0.8, 1.2])
axes4.set_yticks([-0.2, 0.2, 0.6, 1.0])
axes4.set_ylim(-0.2,1.0) #Doing this still doesnot get the expected output
axes4.set_xlim(0.0,1.2)
axes4.scatter(x, y, marker="d", s=80,c=z)
plt.tight_layout()
plt.show()
test_generate_figure2()
I have some 2D data with x and y coordinates both within [0,1], plotted using pcolormesh.
Now I want to symmetrize the plot to [-0.5, 0.5] for both x and y coordinates. In Matlab I was able to achieve this by changing x and y from e.g. [0, 0.2, 0.4, 0.6, 0.8] to [0, 0.2, 0.4, -0.4, -0.2], without rearranging the data. However, with pcolormesh I cannot get the desired result.
A minimum example is shown below, with data represented simply by x+y:
import matplotlib.pyplot as plt
import numpy as np
x,y = np.mgrid[0:1:5j,0:1:5j]
fig,(ax1,ax2,ax3) = plt.subplots(1,3,figsize=(9,3.3),constrained_layout=1)
# original plot spanning [0,1]
img1 = ax1.pcolormesh(x,y,x+y,shading='auto')
# shift x and y from [0,1] to [-0.5,0.5]
x = x*(x<0.5)+(x-1)*(x>0.5)
y = y*(y<0.5)+(y-1)*(y>0.5)
img2 = ax2.pcolormesh(x,y,x+y,shading='auto') # similar code works in Matlab
# for this specific case, the following is close to the desired result, I can just rename x and y tick labels
# to [-0.5,0.5], but in general data is not simply x+y
img3 = ax3.pcolormesh(x+y,shading='auto')
fig.colorbar(img1,ax=[ax1,ax2,ax3],orientation='horizontal')
The corresponding figure is below, any suggestion on what is missed would be appreciated!
Let's look at what you want to achieve in a 1D example.
You have x values between 0 and 1 and a dummy function f(x) = 20*x to produce some values.
# x = [0, .2, .4, .6, .8] -> [0, .2, .4, -.4, -.2] -> [-.4, .2, .0, .2, .4])
# fx = [0, 4, 8, 12, 16] -> [0, 4, 8, 12, 16] -> [ 12, 16, 0, 4, 8]
# ^ only flip and shift x not fx ^
You could use np.roll() to achieve the last operation.
I used n=14 to make the result better visible and show that this approach works for arbitrary n.
import numpy as np
import matplotlib.pyplot as plt
n = 14
x, y = np.meshgrid(np.linspace(0, 1, n, endpoint=False),
np.linspace(0, 1, n, endpoint=False))
z = x + y
x_sym = x*(x <= .5)+(x-1)*(x > .5)
# array([[ 0. , 0.2, 0.4, -0.4, -0.2], ...
x_sym = np.roll(x_sym, n//2, axis=(0, 1))
# array([[-0.4, -0.2, 0. , 0.2, 0.4], ...
y_sym = y*(y <= .5)+(y-1)*(y > .5)
y_sym = np.roll(y_sym, n//2, axis=(0, 1))
z_sym = np.roll(z, n//2, axis=(0, 1))
# array([[1.2, 1.4, 0.6, 0.8, 1. ],
# [1.4, 1.6, 0.8, 1. , 1.2],
# [0.6, 0.8, 0. , 0.2, 0.4],
# [0.8, 1. , 0.2, 0.4, 0.6],
# [1. , 1.2, 0.4, 0.6, 0.8]])
fig, (ax1, ax2) = plt.subplots(1, 2)
img1 = ax1.imshow(z, origin='lower', extent=(.0, 1., .0, 1.))
img2 = ax2.imshow(z_sym, origin='lower', extent=(-.5, .5, -.5, .5))
Using matplotlib, python3.6. I am trying to create some quiverkeys for a quiver plot but having a hard time getting the label colors to match certain arrows. Below is a simplified version of the code to show the issue. When I use the same color (0.3, 0.1, 0.2, 1.0 ) for a vector at (1,1) and as 'labelcolor' of a quiverkey I see 2 different colors.
q=plt.quiver([1, 2,], [1, 1],
[[49],[49]],
[0],
[[(0.6, 0.8, 0.5, 1.0 )],
[(0.3, 0.1, 0.2, 1.0 )]],
angles=[[45],[90]])
plt.quiverkey(q, .5, .5, 7, r'vector2', labelcolor=(0.3, 0.1, .2, 1),
labelpos='S', coordinates = 'figure')
Supposedly you meant to be using the color argument of quiver to set the actual colors.
import matplotlib.pyplot as plt
q=plt.quiver([1, 2,], [1, 1], [5,0], [5,5],
color=[(0.6, 0.8, 0.5, 1.0 ), (0.3, 0.1, 0.2, 1.0 )])
plt.quiverkey(q, .5, .5, 7, r'vector2', labelcolor=(0.3, 0.1, .2, 1),
labelpos='S', coordinates = 'figure')
plt.show()
Else, the C argument is interpreted as the values to map to colors according to the default colormap. Since you only have two arrows, only the first two values from the 8 numbers in the array given to the C argument are taken into account. But the colormap normalization uses all of those values, such that it ranges between 0.1 and 1.0. The call
q=plt.quiver([1, 2,], [1, 1], [5,0], [5,5],
[(0.6, 0.8, 0.5, 1.0 ), (0.3, 0.1, 0.2, 1.0 )])
is hence equivalent to
q=plt.quiver([1, 2,], [1, 1], [5,0], [5,5],
[0.6, 0.8], norm=plt.Normalize(vmin=0.1, vmax=1))
resulting in the first arrows color to be the value of 0.6 in the viridis colormap normalized between 0.1 and 1.0, and the second arrow to 0.8 in that colormap.
This becomes apparent if we add plt.colorbar(q, orientation="horizontal"):
I'd like to plot errorbars with categorical X variable. The error bars (upper and lower) are on Y values only.
For example, the code
import numpy as np
import matplotlib.pyplot as plt
x = ["4", "10", "50"]
y = [3, 2, 1]
yerr = np.matrix([[1.5, 1.1, 0.9], [1.3, 1.2, 0.8]])
fig, ax = plt.subplots(1, 1)
ax.errorbar(x, y, yerr=yerr)
plt.show()
plt.close()
gives the following error:
ValueError: In safezip, len(args[0])=3 but len(args[1])=1
The error you get has nothing to do with categorical axis.
You just cannot use a matrix. Use a numpy array,
yerr = np.array([[1.5, 1.1, 0.9], [1.3, 1.2, 0.8]])
or simply a list, there is no need to use numpy here,
yerr = [[1.5, 1.1, 0.9], [1.3, 1.2, 0.8]]
I want to construct a 1d numpy array a, and I know each a[i] has several possible values. Of course, the numbers of the possible values of any two elements of a can be different. For each a[i], I want to set it be the minimum value of all the possible values.
For example, I have two array:
idx = np.array([0, 1, 0, 2, 3, 3, 3])
val = np.array([0.1, 0.5, 0.2, 0.6, 0.2, 0.1, 0.3])
The array I want to construct is following:
a = np.array([0.1, 0.5, 0.6, 0.1])
So does there exist any function in numpy can finish this work?
Here's one approach -
def groupby_minimum(idx, val):
sidx = idx.argsort()
sorted_idx = idx[sidx]
cut_idx = np.r_[0,np.flatnonzero(sorted_idx[1:] != sorted_idx[:-1])+1]
return np.minimum.reduceat(val[sidx], cut_idx)
Sample run -
In [36]: idx = np.array([0, 1, 0, 2, 3, 3, 3])
...: val = np.array([0.1, 0.5, 0.2, 0.6, 0.2, 0.1, 0.3])
...:
In [37]: groupby_minimum(idx, val)
Out[37]: array([ 0.1, 0.5, 0.6, 0.1])
Here's another using pandas -
import pandas as pd
def pandas_groupby_minimum(idx, val):
df = pd.DataFrame({'ID' : idx, 'val' : val})
return df.groupby('ID')['val'].min().values
Sample run -
In [66]: pandas_groupby_minimum(idx, val)
Out[66]: array([ 0.1, 0.5, 0.6, 0.1])
You can also use binned_statistic:
from scipy.stats import binned_statistic
idx_list=np.append(np.unique(idx),np.max(idx)+1)
stats=binned_statistic(idx,val,statistic='min', bins=idx_list)
a=stats.statistic
I think, in older scipy versions, statistic='min' was not implemented, but you can use statistic=np.min instead. Intervals are half open in binned_statistic, so this implementation is safe.