I have plotted the grouped bar plot and I want to have spacing between orange and blue bar.
I am not sure how to.
It is the sample image - I want little space between blue and orange bar.
import numpy as np
import matplotlib.pyplot as plt
N=4
a = [63,13,12,45]
b = [22,6,9,9]
ind = np.arange(N)
width=0.35
fig, ax = plt.subplots()
b1 = ax.bar(ind, a, width)
b2 = ax.bar(ind+width, b, width)
ax.set_xticks(ind+width/2)
plt.show()
Just do this:
b2 = ax.bar(ind+ 1.2 * width, b, width)
Just edge processing in ax.bar() creates space.
b1 = ax.bar(ind, a, width, edgecolor="w", linewidth=3)
It's the full code of the modified sample.
import numpy as np
import matplotlib.pyplot as plt
N=4
a = [63,13,12,45]
b = [22,6,9,9]
ind = np.arange(N)
width=0.4
fig, ax = plt.subplots()
b1 = ax.bar(ind, a, width, edgecolor="w", linewidth=3)
b2 = ax.bar(ind+width, b, width, edgecolor="w",linewidth=3)
ax.set_xticks(ind+width/2)
plt.show()
I am unaware of an dedicated option for such a behavior. The reason is that it would indicate inaccurate measures. You would be no longer sure if the blue/orange bars belong to the same value on the x-axis.
Therefore, you need to come up with a small workaround by shifting the data (or rather the two data arrays) around the index on the x-axis. For this, I introduced the variable dist in the code below. Note that it should be larger than half of the width of a bar.
import numpy as np
import matplotlib.pyplot as plt
N=4
a = [63,13,12,45]
b = [22,6,9,9]
ind = np.arange(N)
width = 0.1
dist = 0.08 # should be larger than width/2
fig, ax = plt.subplots()
b1 = ax.bar(ind-dist, a, width)
b2 = ax.bar(ind+dist, b, width)
plt.show()
generic solution
For a somewhat more generic solution, we need first to calculate the width of the grouped bars and than shift the group around the index:
import numpy as np
import matplotlib.pyplot as plt
N=4
a = [63,13,12,45]
b = [22,6,9,9]
ind = np.arange(N) # index / x-axis value
width = 0.1 # width of each bar
DistBetweenBars = 0.01 # distance between bars
Num = 5 # number of bars in a group
# calculate the width of the grouped bars (including the distance between the individual bars)
WithGroupedBars = Num*width + (Num-1)*DistBetweenBars
fig, ax = plt.subplots()
for i in range(Num):
data = np.random.rand(N)
ax.bar(ind-WithGroupedBars/2 + (width+DistBetweenBars)*i,data, width)
plt.show()
Related
My goal is to determine if points lie inside of a shape. Consider the following example:
import numpy as np
from matplotlib import pyplot as plt
import warnings
warnings.filterwarnings('ignore', 'invalid value encountered in sqrt')
r1 = 10
r2 = 4
a = 12 # x shift for circle 2
b = -4 # y shift for circle 2
theta = np.arange(0, 2*np.pi, 0.0006)
r1_complex = r1*np.exp(1j*theta)
r1_x, r1_y = np.real(r1_complex), np.imag(r1_complex)
r2_complex = r2*np.exp(1j*theta)
r2_x, r2_y = np.real(r2_complex) + a, np.imag(r2_complex) + b
fig, ax = plt.subplots()
ax.plot(r1_x, r1_y)
ax.plot(r2_x, r2_y)
ax.set_aspect('equal')
ax.grid()
plt.show()
output
I want to find the points of the blue circle that are inside of the orange circle. It would be best to try and find it without iteration if possible.
For this case, I can easily determine the points that are inside of the orange circle because I know the equation of a circle. Amending the code to this:
import numpy as np
from matplotlib import pyplot as plt
import warnings
warnings.filterwarnings('ignore', 'invalid value encountered in sqrt')
r1 = 10
r2 = 4
a = 12 # x shift for circle 2
b = -4 # y shift for circle 2
theta = np.arange(0, 2*np.pi, 0.0006)
r1_complex = r1*np.exp(1j*theta)
r1_x, r1_y = np.real(r1_complex), np.imag(r1_complex)
r1_inside_y = np.logical_and(r1_y < np.sqrt(r2**2 - (r1_x - a)**2) + b, r1_y > -np.sqrt(r2**2 - (r1_x - a)**2) + b)
r2_complex = r2*np.exp(1j*theta)
r2_x, r2_y = np.real(r2_complex) + a, np.imag(r2_complex) + b
fig, ax = plt.subplots()
ax.plot(r1_x, r1_y)
ax.plot(r2_x, r2_y)
ax.plot(r1_x[r1_inside_y], r1_y[r1_inside_y])
ax.set_aspect('equal')
ax.grid()
plt.show()
output
produces what I'm looking for. Is there a way to get this same result without knowing the equation for a circle? Perhaps an algorithm, or clever way with numpy operations?
edit
What I mean by arbitrary shape is an kind of closed shape with N number of points. Consider this image:
I would like to know the points from the black line that lie inside the bounds of the red line. For this example, there are two points that this algorithm should find, the x4 and x5 points in blue. And the points x1, x2, ... xN would be coordinate points where both shapes share the same origin.
It turns out, this algorithm has already been standardized in the matplotlib.path module. You can produce the same results using the Path class. Consider the following changes to the above code:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import path
r1 = 10
r2 = 4
a = 12 # x shift for circle 2
b = -4 # y shift for circle 2
theta = np.arange(0, 2*np.pi, 0.0006)
r1_complex = r1*np.exp(1j*theta)
r1_x, r1_y = np.real(r1_complex), np.imag(r1_complex)
stacked1 = np.stack((r1_x, r1_y), axis=1) # A list of coordinates
r2_complex = r2*np.exp(1j*theta)
r2_x, r2_y = np.real(r2_complex) + a, np.imag(r2_complex) + b
stacked2 = np.stack((r2_x, r2_y), axis=1) # A list of coordinates
p = path.Path(stacked2)
r1_inside = p.contains_points(stacked1)
fig, ax = plt.subplots()
ax.plot(r1_x, r1_y)
ax.plot(r2_x, r2_y)
ax.plot(r1_x[r1_inside], r1_y[r1_inside])
ax.set_aspect('equal')
ax.grid()
plt.show()
This produces the same image without knowledge of the mathematical properties of the shapes.
I have 4 histograms, lets say A,B,C and D. I would like to plot histograms A and B together, with stacked bars, along with histograms C and D, also with stacked bars, but without stacking the four histograms together. So I would like two stacked histograms in a single histogram with side-by-side bars.
So far, I can plot either A-B-C-D with stacked bars; or A-B and C-D in different stacked histograms, but the bars of both histograms are not side by side. is the code I have:
plot=[A,B,C,D] #values from 0-10
ww=[wA,wB,wC,wD] #weights
All bars stacked:
plt.hist(plot,bins=10,weights=ww,label=['A','B','C','D'],histtype="barstacked")
A-B histogram + C-D histogram, but one histogram hides the other:
plt.hist(plot[0:2],bins=10,weights=ww[0:2],label=['loses','wins'],stacked=True)
plt.hist(plot[2:4],bins=10,weights=ww[2:4],label=['l','w'],stacked=True)
thanks in advance for your help!
you can use the patches list that hist() returns:
import numpy as np
import matplotlib.pyplot as plt
A = np.arange(100)
B = np.arange(100)
C = np.arange(100)
D = np.arange(100)
wA = np.abs(np.random.normal(size=100))
wB = np.abs(np.random.normal(size=100))
wC = np.abs(np.random.normal(size=100))
wD = np.abs(np.random.normal(size=100))
plot=[A,B,C,D] #values from 0-10
ww=[wA,wB,wC,wD] #weights
n, bins, patches = plt.hist(plot[0:2],bins=10,weights=ww[0:2],label=['loses','wins'],stacked=True)
n, bins, patches2 = plt.hist(plot[2:4],bins=10,weights=ww[2:4],label=['l','w'],stacked=True)
for patch in patches:
plt.setp(patch, 'width', 10)
for patch in patches2:
plt.setp(patch, 'width', 5)
plt.show()
update
I found out there's a much better and cleaner way to do this:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
# the data
A = np.arange(10)
B = np.arange(10)
C = np.arange(10)
D = np.arange(10)
wA = np.abs(np.random.normal(size=10))
wB = np.abs(np.random.normal(size=10))
wC = np.abs(np.random.normal(size=10))
wD = np.abs(np.random.normal(size=10))
## necessary variables
width = 0.5 # the width of the bars
## the bars
rects1 = ax.bar(A - width/2, wA, width,
color='blue')
rects2 = ax.bar(B- width/2, wB, width, bottom=wA,
color='green')
rects3 = ax.bar(C + width/2, wC, width,
color='red')
rects4 = ax.bar(D + width/2, wD, width, bottom=wC,
color='yellow')
# axes and labels
ax.set_xlim(-width,len(A)+width)
plt.show()
the results it:
for more details look at this link.
I have tried this and got the result as in the image:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap
cmap = LinearSegmentedColormap.from_list("", ["red","grey","green"])
df = pd.read_csv('t.csv', header=0)
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax = ax1.twiny()
# Scatter plot of positive points, coloured blue (C0)
ax.scatter(np.argwhere(df['real'] > 0), df.loc[df['real'] > 0, 'real'], color='C2')
# Scatter plot of negative points, coloured red (C3)
ax.scatter(np.argwhere(df['real'] < 0), df.loc[df['real'] < 0, 'real'], color='C3')
# Scatter neutral values in grey (C7)
ax.scatter(np.argwhere(df['real'] == 0), df.loc[df['real'] == 0, 'real'], color='C7')
ax.set_ylim([df['real'].min(), df['real'].max()])
index = len(df.index)
ymin = df['prediction'].min()
ymax= df['prediction'].max()
ax1.imshow([np.arange(index),df['prediction']],cmap=cmap,
extent=(0,index-1,ymin, ymax), alpha=0.8)
plt.show()
Image:
I was expecting one output where the color is placed according to the figure. I am getting green color and no reds or greys.
I want to get the image or contours spread as the values are. How I can do that? See the following image, something similar:
Please let me know how I can achieve this. The data I used is here: t.csv
For a live version, have a look at Tensorflow Playground
There are essentially 2 tasks required in a solution like this:
Plot the heatmap as the background;
Plot the scatter data;
Output:
Source code:
import numpy as np
import matplotlib.pyplot as plt
###
# Plot heatmap in the background
###
# Setting up input values
x = np.arange(-6.0, 6.0, 0.1)
y = np.arange(-6.0, 6.0, 0.1)
X, Y = np.meshgrid(x, y)
# plot heatmap colorspace in the background
fig, ax = plt.subplots(nrows=1)
im = ax.imshow(X, cmap=plt.cm.get_cmap('RdBu'), extent=(-6, 6, -6, 6), interpolation='bilinear')
cax = fig.add_axes([0.21, 0.95, 0.6, 0.03]) # [left, bottom, width, height]
fig.colorbar(im, cax=cax, orientation='horizontal') # add colorbar at the top
###
# Plot data as scatter
###
# generate the points
num_samples = 150
theta = np.linspace(0, 2 * np.pi, num_samples)
# generate inner points
circle_r = 2
r = circle_r * np.random.rand(num_samples)
inner_x, inner_y = r * np.cos(theta), r * np.sin(theta)
# generate outter points
circle_r = 4
r = circle_r + np.random.rand(num_samples)
outter_x, outter_y = r * np.cos(theta), r * np.sin(theta)
# plot data
ax.scatter(inner_x, inner_y, s=30, marker='o', color='royalblue', edgecolors='white', linewidths=0.8)
ax.scatter(outter_x, outter_y, s=30, marker='o', color='crimson', edgecolors='white', linewidths=0.8)
ax.set_ylim([-6,6])
ax.set_xlim([-6,6])
plt.show()
To keep things simple, I kept the colorbar range (-6, 6) to match the data range.
I'm sure this code can be changed to suit your specific needs. Good luck!
Here is a possible solution.
A few notes and questions:
What are the 'prediction' values in your data file? They do not seem to correlate with the values in the 'real' column.
Why do you create a second axis? What is represented on the bottom X-axis in your plot? I removed the second axis and labelled the remaining axes (index and real).
When you slice a pandas DataFrame, the index comes with it. You don't need to create a separate index (argwhere and arange(index) in your code). I simplified the first part of the code, where scatterplots are produced.
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap
cmap = LinearSegmentedColormap.from_list("", ["red","grey","green"])
df = pd.read_csv('t.csv', header=0)
print(df)
fig = plt.figure()
ax = fig.add_subplot(111)
# Data limits
xmin = 0
xmax = df.shape[0]
ymin = df['real'].min()
ymax = df['real'].max()
# Scatter plots
gt0 = df.loc[df['real'] > 0, 'real']
lt0 = df.loc[df['real'] < 0, 'real']
eq0 = df.loc[df['real'] == 0, 'real']
ax.scatter(gt0.index, gt0.values, edgecolor='white', color='C2')
ax.scatter(lt0.index, lt0.values, edgecolor='white', color='C3')
ax.scatter(eq0.index, eq0.values, edgecolor='white', color='C7')
ax.set_ylim((ymin, ymax))
ax.set_xlabel('index')
ax.set_ylabel('real')
# We want 0 to be in the middle of the colourbar,
# because gray is defined as df['real'] == 0
if abs(ymax) > abs(ymin):
lim = abs(ymax)
else:
lim = abs(ymin)
# Create a gradient that runs from -lim to lim in N number of steps,
# where N is the number of colour steps in the cmap.
grad = np.arange(-lim, lim, 2*lim/cmap.N)
# Arrays plotted with imshow must be 2D arrays. In this case it will be
# 1 pixel wide and N pixels tall. Set the aspect ratio to auto so that
# each pixel is stretched out to the full width of the frame.
grad = np.expand_dims(grad, axis=1)
im = ax.imshow(grad, cmap=cmap, aspect='auto', alpha=1, origin='bottom',
extent=(xmin, xmax, -lim, lim))
fig.colorbar(im, label='real')
plt.show()
This gives the following result:
I would like to know how I can dynamically update a stacked bar plot in matplotlib.
This question Dynamically updating a bar plot in matplotlib describes how it can be done for a normal bar chart, but not a stacked bar chart.
In a normal bar chart the update can be done via rect.set_height(h) assuming that rects = plt.bar(range(N), x, align='center')
But in a stacked bar chart we also need to set the bottom.
p2 = plt.bar(ind, womenMeans, width, color='y',
bottom=menMeans, yerr=menStd)
How can I dynamically set the bottom? Unfortunately it seems that the 'Rectangle' object has no attribute 'set_bottom'. Is there any alternative way to handle this?
For some reason, the set_bottom() function you want is set_y under patches in the return object from bar. The minimal example, based on the link you suggest would look like,
import numpy as np
import matplotlib.pyplot as plt
def setup_backend(backend='TkAgg'):
import sys
del sys.modules['matplotlib.backends']
del sys.modules['matplotlib.pyplot']
import matplotlib as mpl
mpl.use(backend) # do this before importing pyplot
import matplotlib.pyplot as plt
return plt
N = 5
width = 0.35 # the width of the bars: can also be len(x) sequence
def animate():
# http://www.scipy.org/Cookbook/Matplotlib/Animations
mu, sigma = 100, 15
h = mu + sigma * np.random.randn((N*2))
p1 = plt.bar(np.arange(N), h[:N], width, color='r')
p2 = plt.bar(np.arange(N), h[N:], width, color='b', bottom=h[:N])
assert len(p1) == len(p2)
maxh = 0.
for i in range(50):
for rect1, rect2 in zip(p1.patches, p2.patches):
h = mu + sigma * np.random.randn(2)
#Keep a record of maximum value of h
maxh = max(h[0]+h[1],maxh)
rect1.set_height(h[0])
rect2.set_y(rect1.get_height())
rect2.set_height(h[1])
#Set y limits to maximum value
ax.set_ylim((0,maxh))
fig.canvas.draw()
plt = setup_backend()
fig, ax = plt.subplots(1,1)
win = fig.canvas.manager.window
win.after(10, animate)
plt.show()
Note, I change the height generation using random numbers each iteration so the two arrays of patches can be zipped instead (would get a bit messy otherwise).
I want to plot a true/false or active/deactive binary data similar to the following picture:
The horizontal axis is time and the vertical axis is some entities(Here some sensors) which is active(white) or deactive(black). How can I plot such a graphs using pyplot.
I searched to find the name of these graphs but I couldn't find it.
What you are looking for is imshow:
import matplotlib.pyplot as plt
import numpy as np
# get some data with true # probability 80 %
data = np.random.random((20, 500)) > .2
fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(data, aspect='auto', cmap=plt.cm.gray, interpolation='nearest')
Then you will just have to get the Y labels from somewhere.
It seems that the image in your question has some interpolation in the image. Let us set a few more things:
import matplotlib.pyplot as plt
import numpy as np
# create a bit more realistic-looking data
# - looks complicated, but just has a constant switch-off and switch-on probabilities
# per column
# - the result is a 20 x 500 array of booleans
p_switchon = 0.02
p_switchoff = 0.05
data = np.empty((20,500), dtype='bool')
data[:,0] = np.random.random(20) < .2
for c in range(1, 500):
r = np.random.random(20)
data[data[:,c-1],c] = (r > p_switchoff)[data[:,c-1]]
data[-data[:,c-1],c] = (r < p_switchon)[-data[:,c-1]]
# create some labels
labels = [ "label_{0:d}".format(i) for i in range(20) ]
# this is the real plotting part
fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(data, aspect='auto', cmap=plt.cm.gray)
ax.set_yticks(np.arange(len(labels)))
ax.set_yticklabels(labels)
creates
However, the interpolation is not necessarily a good thing here. To make the different rows easier to separate, one might use colors:
import matplotlib.pyplot as plt
import matplotlib.colors
import numpy as np
# create a bit more realistic-looking data
# - looks complicated, but just has a constant switch-off and switch-on probabilities
# per column
# - the result is a 20 x 500 array of booleans
p_switchon = 0.02
p_switchoff = 0.05
data = np.empty((20,500), dtype='bool')
data[:,0] = np.random.random(20) < .2
for c in range(1, 500):
r = np.random.random(20)
data[data[:,c-1],c] = (r > p_switchoff)[data[:,c-1]]
data[-data[:,c-1],c] = (r < p_switchon)[-data[:,c-1]]
# create some labels
labels = [ "label_{0:d}".format(i) for i in range(20) ]
# create a color map with random colors
colmap = matplotlib.colors.ListedColormap(np.random.random((21,3)))
colmap.colors[0] = [0,0,0]
# create some colorful data:
data_color = (1 + np.arange(data.shape[0]))[:, None] * data
# this is the real plotting part
fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(data_color, aspect='auto', cmap=colmap, interpolation='nearest')
ax.set_yticks(np.arange(len(labels)))
ax.set_yticklabels(labels)
creates
Of course, you will want to use something less strange as the coloring scheme, but that is really up to your artistic views. Here the trick is that all True elements on row n have value n+1 and, and all False elements are 0 in data_color. This makes it possible to create a color map. Naturally, if you want a cyclic color map with two or three colors, just use the modulus of data_color in imshow by, e.g. data_color % 3.