I am trying to make a simple animation for a stochastic process (just black and white dots randomly changing their colors). To simulate that, I have basically plotted the dots over a grid. However, the important parameter for me being the rate of black dots, I'd like to draw under this grid a progressive bar showing the rate #blackdots/#totaldots looking approximately like this : [///////////////////////_____] 70% (simply just like a power charge bar).
I tried this but the bars are overlaid, and I don't think that Slider is meant to do such animations.
import numpy as np
import matplotlib.pyplot as plt
import random
from matplotlib.widgets import Slider
t=1500
d=5
n=10
raws = [i for i in range(n)]
config = [[2*random.randrange(2)-1 for i in range(n)] for i in range(n)]
def color(op):
if op == 1:
return 'white'
return 'black'
nbblack = 0
for i in config:
for j in i :
nbblack += (j==-1)
blackrate = nbblack/(n**2)
plt.subplots_adjust(bottom=0.25)
for line in range(n):
colors = [color(config[line][raw]) for raw in raws]
plt.scatter([line]*n,raws,c=colors,edgecolors='black',s=50)
plt.title('t=0',fontdict={'size': 16},x=-0.20,y=25)
samp = Slider(axamp, 'Rate', 0, 1, valinit=blackrate,color='black')
for step in range(t):
plt.pause(0.001)
xpick = random.randrange(n)
ypick = random.randrange(n)
opinion_picked = config[xpick][ypick]
for j in range(d) :
neighboor = random.randrange(n),random.randrange(n)
opinion_neig = config[neighboor[0]][neighboor[1]]
if opinion_neig == opinion_picked :
break
elif j == d-1 :
config[xpick][ypick]=-config[xpick][ypick]
nbblack-=config[xpick][ypick]
blackrate = nbblack/(n**2)
plt.title('t={}'.format(step),fontdict={'size': 16},x=-0.20,y=25)
for line in range(n):
colors = [color(config[line][raw]) for raw in raws]
plt.scatter([line]*n,raws,c=colors,edgecolors='black',s=50)
axamp = plt.axes([0.28, 0.15, 0.48, 0.03])
samp = Slider(axamp, 'Rate', 0, 1, valinit=blackrate,color='black')
plt.show()
I am not very familiar with maplot so please let me know if there is a better way to do things and thanks a lot for your help !
I don't think that Slider is meant to do such animations ... please let me know if there is a better way to do things ...
Maybe using a custom colorbar would work. I adapted from the Discrete Intervals colorbar example.
The following uses the percentage of black dots to decide which portion of the color bar should be black or white.
Here is an example without animation: five successive plots drawn by a loop. I tried to keep it as close to your example as possible.
import matplotlib as mpl
from matplotlib import pyplot as plt
import random
t = 1500
d = 5
n = 10
raws = [i for i in range(n)]
def f(t=t, d=d, n=n, raws=raws):
# try to get more skew in the data
mode = random.random()
config = [[random.triangular(mode=mode) > 0.5 for i in range(n)] for i in range(n)]
config = [[int(item) or -1 for item in row] for row in config]
# config = [[2*random.randrange(2)-1 for i in range(n)] for i in range(n)]
def color(op):
if op == 1:
return "white"
return "black"
nbblack = 0
for i in config:
for j in i:
nbblack += j == -1
blackrate = nbblack / (n ** 2)
fig, ax = plt.subplots()
fig.subplots_adjust(bottom=0.25)
# plt.subplots_adjust(bottom=0.25)
for line in range(n):
colors = [color(config[line][raw]) for raw in raws]
plt.scatter([line] * n, raws, c=colors, edgecolors="black", s=50)
plt.title("t=0", fontdict={"size": 16}, x=-0.20, y=25)
cmap = mpl.colors.ListedColormap(["black", "white"])
bounds = [0, int(blackrate * 100), 100]
norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
fig.colorbar(
mpl.cm.ScalarMappable(cmap=cmap, norm=norm),
# cax=ax,
# boundaries=[0] + bounds + [13], # Adding values for extensions.
# extend='both',
ticks=bounds,
spacing="proportional",
orientation="horizontal",
label="Percentage Black",
)
plt.show()
plt.close()
for _ in range(5):
f()
BoundaryNorm determines how the colors are distributed. The example uses two colors, black/white, and defines two bins between 0 and 100 using the percentage of black dots for the bin edge.
The spacing="proportional" argument to Figure.colorbar ensures the black/white area is proportional to the bins.
The Matplotlib Tutorials are worth investing time in.
Related
Here is needed to plot CDF for 8 different functions in one plot. The problem that it gives just 7 different colors and the 8 one gives just first blue color again. How to make 8 different colors?
Here is the script:
locerror_2d=[Scan_Around[1],Triangle_Around[1],M_shape_Around[1],Hilbert_Around[1],Scan_SbS[1],Triangle_SbS[1],M_shape_SbS[1],Hilbert_SbS[1]]
# N = len(locerror_2d[0]) #same for all ( here, I hope so... )
# N1=len(locerror_2d[2])
H_cent,h_cent1 = np.histogram( locerror_2d[0], bins = 10, normed = True ) # Random Walk Centroid
hy_cent = np.cumsum(H_cent)*(h_cent1[1] - h_cent1[0])
H_1st,h_1st = np.histogram( locerror_2d[1], bins = 10, normed = True ) # Random Walk Weighterd
hy_1st = np.cumsum(H_1st)*(h_1st[1] - h_1st[0])
H_2nd,h_2nd = np.histogram( locerror_2d[2], bins = 10, normed = True ) # Circle Walk Centroid
hy_2nd = np.cumsum(H_2nd)*(h_2nd[1] - h_2nd[0])
H_3rd,h_3rd = np.histogram( locerror_2d[3], bins = 10, normed = True ) # Circle Walk Weighterd
hy_3rd = np.cumsum(H_3rd)*(h_3rd[1] - h_3rd[0])
H_mm,h_mm = np.histogram( locerror_2d[4], bins = 10, normed = True ) # G Walk Centroid
hy_mm = np.cumsum(H_mm)*(h_mm[1] - h_mm[0])
H_shr,h_shr = np.histogram( locerror_2d[5], bins = 10, normed = True ) # G Walk Weighterd
hy_shr = np.cumsum(H_shr)*(h_shr[1] - h_shr[0])
H_s,h_s = np.histogram( locerror_2d[6], bins = 10, normed = True ) # G Walk Weighterd
hy_s = np.cumsum(H_s)*(h_s[1] - h_s[0])
H_sh,h_sh = np.histogram( locerror_2d[7], bins = 10, normed = True ) # G Walk Weighterd
hy_sh = np.cumsum(H_sh)*(h_sh[1] - h_sh[0])
plt.hold(True)
ddd_hist_cent, = plt.plot(h_cent1[1:], hy_cent,label="Scan_Around") # centroid
ddd_hist_1st, = plt.plot(h_1st[1:], hy_1st,label='Triangle_Around') #Gradient
ddd_circ_cent, = plt.plot(h_2nd[1:], hy_cent,label="M_shape_around") # centroid
ddd_circ_wei, = plt.plot(h_3rd[1:], hy_1st,label='Hilbert_Around') #Gradient
ddd_g_cent, = plt.plot(h_mm[1:], hy_cent,label="Scan_SbS") # centroid
ddd_g_wei, = plt.plot(h_shr[1:], hy_1st,label='Triangle_SbS') #Gradient
ddd_g_w, = plt.plot(h_s[1:], hy_cent,label='M_shape_SbS')
ddd_g_we, = plt.plot(h_sh[1:], hy_1st,label='Hilbert_SbS')
plt.hold(False)
plt.rc('legend',**{'fontsize':10})
plt.legend(handles=[ddd_hist_cent, ddd_hist_1st, ddd_circ_cent, ddd_circ_wei, ddd_g_cent,ddd_g_wei, ddd_g_w],loc='center left', bbox_to_anchor=(0.75, 0.18)) #no trilateration here
plt.ylabel('Probability')
plt.xlabel('Localization Error, m')
plt.ylim(ymax = 1.1, ymin = 0)
plt.title('Path Planning Algorithms')
plt.grid()
plt.show()
Thank you
I love to read my colors directly from a colormap with this code
def getColor(c, N, idx):
import matplotlib as mpl
cmap = mpl.cm.get_cmap(c)
norm = mpl.colors.Normalize(vmin=0.0, vmax=N - 1)
return cmap(norm(idx))
Here, c is the name of the colormap (see https://matplotlib.org/examples/color/colormaps_reference.html for a list), N is the number of colors you want in total, and idx is just an index that will yield the specific color.
Then when calling the plot function, just add the color=getColor(c, N, idx) option.
ok. I got it. In the end of plot I just need to show the color.
ddd_hist_cent, = plt.plot(h_cent1[1:], hy_cent,label="Scan_Around", c='yellow')
Easiest solution: Give the last curve a different color:
plt.plot(h_sh[1:], hy_1st,label='Hilbert_SbS', color="orange")
Matplotlib version 1.5 or below has 7 different colors in its color cycle, while matplotlib 2.0 has 10 different colors. Hence, updating matplotlib is another option.
In general, you may of course define your own color cycle which has as many colors as you wish.
Build a cycler from a colormap, as shown in this question:
import matplotlib.pyplot as plt
from cycler import cycler
import numpy as np
N = 8 # number of colors
plt.rcParams["axes.prop_cycle"] = cycler('color', plt.cm.jet(np.linspace(0,1,N)) )
Build a cycler from a list of colors:
import matplotlib.pyplot as plt
from cycler import cycler
colors=["aquamarine","crimson","gold","indigo",
"lime","orange","orchid","sienna"]
plt.rcParams["axes.prop_cycle"] = cycler('color',colors)
I have a set of lines with markers. I want these markers to fade through the colormap, say prism for example, dependant on a function, which gives their temperature. Here is my code:
def virial_temp(M=row1[i][2],z=row1[i][3]):
X = 0.7
Y = 0.3
mu = 1/(2*X + 0.75*Y) #from GL's code
v_v = math.sqrt(G*M*m_sun/(virial_rad(M,z)*1E+3*parsec)) #virial velocity [m/s]
return (mu*m_p*v_v**2/(2*k_b))
line1 = plt.plot([namei - len(row1)*0.5, namej - len(row2)*0.5],[row1[i][3]*10, row2[j][3]*10], c=plt.cm.jet(j), lw=2, marker='o', markerfacecolor=plt.cm.rainbow(virial_temp(M=row1[i][2],z=row2[j][3])), markersize=1.5)
It is only the markerfacecolor part I am struggling with. Lets say if temperature is low (value returned from function is low), the color will the same as the color at the 'first' color on the colormap, and if the tempreture is very high (value returned from function is high), it will be the 'last' color on the colormap. Is there a way to do this?
Any help would be really appreciated as I've been struggling on this for a while now!
Thanks in advance
Check out this answer
Here's a bit of code to demonstrate my suggestion:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pyplot import cm
import random
maximum = 10
n = 10
def pick_color():
closest_match = 10*maximum #arbitrary high number
for item in color_pairs:
if abs(item[0] - num) < closest_match:
closest_match = abs(item[0] - num)
c = item[1]
return c
color = iter(cm.rainbow(np.linspace(0,1,n)))
color_pairs = [(value, c) for value, c in zip(range(n+1), color)]
Xs = [i for i in range(n+1)]
random_list = [random.choice(range(maximum +1)) for i in range(n+1)]
for x, num in zip(Xs,random_list):
c = pick_color()
plt.scatter(x, num, s=50, c=c)
plt.show()
Obviously, you wanted a line, etc, but the principal is the same.
I want to do something with plt.hist2d and plt.colorbar and I'm having real trouble working out how to do it. To explain, I've written the following example:
import numpy as np
from matplotlib import pyplot as plt
x = np.random.random(1e6)
y = np.random.random(1e6)
plt.hist2d(x, y)
plt.colorbar()
plt.show()
This code generates a plot that looks something like the image below.
If I generate a histogram, ideally I would like the colour bar to extend beyond the maximum and minimum range of the data to the next step beyond the maximum and minimum. In the example in this question, this would set the colour bar extent from 9660 to 10260 in increments of 60.
How can I force either plt.hist2d or plt.colorbar to set the colour bar such that ticks are assigned to the start and end of the plotted colour bar?
I think this is what you're looking for:
h = plt.hist2d(x, y)
mn, mx = h[-1].get_clim()
mn = 60 * np.floor(mn / 60.)
mx = 60 * np.ceil(mx / 60.)
h[-1].set_clim(mn, mx)
cbar = plt.colorbar(h[-1], ticks=np.arange(mn, mx + 1, 60), )
This gives something like,
It's also often convenient to use tickers from the matplotlib.ticker, and use the tick_values method of tickers, but for this purpose I think the above is most convenient.
Good luck!
With huge thanks to farenorth, who got me thinking about this in the right way, I came up with a function, get_colour_bar_ticks:
def get_colour_bar_ticks(colourbar):
import numpy as np
# Get the limits and the extent of the colour bar.
limits = colourbar.get_clim()
extent = limits[1] - limits[0]
# Get the yticks of the colour bar as values (ax.get_yticks() returns them as fractions).
fractions = colourbar.ax.get_yticks()
yticks = (fractions * extent) + limits[0]
increment = yticks[1] - yticks[0]
# Generate the expanded ticks.
if (fractions[0] == 0) & (fractions[-1] == 1):
return yticks
else:
start = yticks[0] - increment
end = yticks[-1] + increment
if fractions[0] == 0:
newticks = np.concatenate((yticks, [end]))
elif fractions[1] == 1:
newticks = np.concatenate(([start], yticks))
else:
newticks = np.concatenate(([start], yticks, [end]))
return newticks
With this function I can then do this:
from matplotlib import pyplot as plt
x = np.random.random(1e6)
y = np.random.random(1e6)
h = plt.hist2d(x, y)
cbar = plt.colorbar()
ticks = get_colour_bar_ticks(cbar)
h[3].set_clim(ticks[0], ticks[-1])
cbar.set_clim(ticks[0], ticks[-1])
cbar.set_ticks(ticks)
plt.show()
Which results in this, which is what I really wanted:
Hi Im currently wishing to label my polar bar chart in the form whereby the labels are all rotating by differing amounts so they can be read easily much like a clock. I know there is a rotation in plt.xlabel however this will only rotate it by one amount I have many values and thus would like to not have them all crossing my graph.
This is figuratively what my graph is like with all the orientations in the same way, however I would like something akin to this; I really need this just using matplotlib and pandas if possible. Thanks in advance for the help!
Some example names might be farming, generalists, food and drink if these are not correctly rotated they will overlap the graph and be difficult to read.
from pandas import DataFrame,Series
import pandas as pd
import matplotlib.pylab as plt
from pylab import *
import numpy as np
data = pd.read_csv('/.../data.csv')
data=DataFrame(data)
N = len(data)
data1=DataFrame(data,columns=['X'])
data1=data1.get_values()
plt.figure(figsize=(8,8))
ax = plt.subplot(projection='polar')
plt.xlabel("AAs",fontsize=24)
ax.set_theta_zero_location("N")
bars = ax.bar(theta, data1,width=width, bottom=0.0,color=colours)
I would then like to label the bars according to their names which I can obtain in a list, However there are a number of values and i would like to be able to read the data names.
The very meager beginnings of an answer for you (I was doing something similar, so I just threw a quick hack to go in the right direction):
# The number of labels you'd like
In [521]: N = 5
# Where on the circle it will show up
In [522]: theta = numpy.linspace(0., 2 * numpy.pi, N + 1, endpoint = True)
In [523]: theta = theta[1:]
# Create the figure
In [524]: fig = plt.figure(figsize = (6,6), facecolor = 'white', edgecolor = None)
# Create the axis, notice polar = True
In [525]: ax = plt.subplot2grid((1, 1), (0,0), polar = True)
# Create white bars so you're really just focusing on the labels
In [526]: ax.bar(theta, numpy.ones_like(theta), align = 'center',
...: color = 'white', edgecolor = 'white')
# Create the text you're looking to add, here I just use numbers from counter = 1 to N
In [527]: counter = 1
In [528]: for t, o in zip(theta, numpy.ones_like(theta)):
...: ax.text(t, 1 - .1, counter, horizontalalignment = 'center', verticalalignment = 'center', rotation = t * 100)
...: counter += 1
In [529]: ax.set_yticklabels([])
In [530]: ax.set_xticklabels([])
In [531]: ax.grid(False)
In [531]: plt.show()
I'm trying to do something as seen on the image is given below,
Just setting reverse diagonals white color is left. I couldn't set them as white. The chart takes integer values and I don't know what integer value is corresponding of white color.
Thank!
Edited:
Here is the code;
import math
from matplotlib import pyplot as plt
from matplotlib import cm as cm
import pylab
import numpy as np
from matplotlib.collections import LineCollection
class HeatMap:
def __init__(self, selectedLines):
self.selectedLines = selectedLines
def getHeapMap(self):
figure = plt.figure()
if len(self.selectedLines) != 0:
self.map = self.createTestMapData(len(self.selectedLines), len(self.selectedLines))
maxValueInMap = self.findMaxValueInMap(self.map)
x = np.arange(maxValueInMap + 1)
ys = [x + i for i in x]
ax = figure.add_subplot(111)
ax.imshow(self.map, cmap=cm.jet, interpolation='nearest')
'''
Left side label of the chart is created according to selected values
from a checkbox group.
'''
leftSideLabelSize = len(self.selectedLines)
sideLabels = []
for line in self.selectedLines:
sideLabels.append(line.text())
pos = np.arange(leftSideLabelSize)
'''
Left side labels are set with the code below.
'''
pylab.yticks(pos, sideLabels)
plt.xticks(pos, sideLabels)
self.numrows, self.numcols = self.map.shape
ax.format_coord = self.format_coord
line_segments = LineCollection([zip(x, y) for y in ys],
linewidths=(0.5, 3, 1.5, 2),
linestyles='solid')
line_segments.set_array(x)
axcb = figure.colorbar(line_segments)
return figure
def format_coord(self, x, y):
col = int(x + 0.5)
row = int(y + 0.5)
if col >= 0 and col < self.numcols and row >= 0 and row < self.numrows:
z = self.map[row, col]
return 'x=%1.4f, y=%1.4f, z=%1.4f' % (x, y, z)
else:
return 'x=%1.4f, y=%1.4f' % (x, y)
def createTestMapData(self, xSize, ySize):
resultMap = 10 * np.random.rand(xSize, ySize)
#Setting reverse diagonal is here. Now it is set with zero but it gives blue.
# I want it to be set as white
for index in range(0, int(math.sqrt(resultMap.size))):
resultMap[index][((math.sqrt(resultMap.size) - 1) - index )] = 0
return resultMap
def findMaxValueInMap(self, map):
return np.amax(map)
The values are generated randomly at the moment. The code is above gives a gui like;
You can make your own colormap, or adjust an existing one :)
Here's the code for the above plot, with explainations in the comments:
import matplotlib
from pylab import *
import numpy as np
#Create test data with zero valued diagonal:
data = np.random.random_sample((25, 25))
rows, cols = np.indices((25,25))
data[np.diag(rows, k=0), np.diag(cols, k=0)] = 0
#Create new colormap, with white for zero
#(can also take RGB values, like (255,255,255):
colors = [('white')] + [(cm.jet(i)) for i in xrange(1,256)]
new_map = matplotlib.colors.LinearSegmentedColormap.from_list('new_map', colors, N=256)
pcolor(data, cmap=new_map)
colorbar()
savefig('map.png')
show()
Alternatively, you could mask your data, and set a mask color:
#Create test data:
data = np.random.random_sample((25, 25))
#Create a diagonal mask:
mask = np.diag(np.ones(25))
#Apply mask to data:
masked_data = ma.masked_array(data, mask)
#Set mask color to white:
cm.jet.set_bad(color='white', alpha=None)
#for this to work we use pcolormesh instead of pcolor:
pcolormesh(masked_data, cmap=cm.jet)
colorbar()
show()
This produces essentially the same result, but may suit your needs better as you can set any cell to white, and also the white doesn't show up on the colorbar (see very bottom of above colorbar):
The colormap is defined by the cmap argument in ax.imshow(). You have used the jet colormap so you have cmap=cm.jet, which is just one of many built-in color maps in matplotlib. You may choose one or define your own that suits your taste.