Related
I'm using matplotlib 3.3.2 to plot some data points. I'd like to plot two different kinds of data with two different marker styles - one with 'o' and one with 'x'. I'd also like to make the size of the points small, around a marker size of .4-.5. However, when I plot my data for a marker size less than about 1.2, the x markers turn into dots that look a lot like the o markers (but are slightly more diamond shaped). I've tried to set the marker style in several different places to be 'x' for that data, but nothing I've tried has worked. How can I plot small points with different marker styles.
Here's an example of code that produces the unexpected behavior:
import matplotlib
matplotlib.use('agg')
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
from matplotlib.legend_handler import HandlerTuple
%matplotlib inline
matplotlib.rcParams['text.usetex'] = True
matplotlib.rcParams['font.size'] = 8
matplotlib.rcParams['savefig.dpi'] = 600
matplotlib.rcParams['text.latex.preamble'] = [r'\usepackage{amsmath}']
matplotlib.rcParams['legend.fontsize'] = 8
x_data = 100 * np.random.rand(100)
o_data = 100 * np.random.rand(100)
xs = np.linspace(0, 100, num = len(x_data))
x_marker, x_size, x_lw = 'x', .5, 1
o_marker, o_size, o_lw = 'o', .5, 1
plt.figure(figsize = (10,10))
plt.loglog(xs, x_data, marker=x_marker, markersize=x_size, linewidth = x_lw, linestyle = 'None')
plt.loglog(xs, o_data, marker=o_marker, markersize=o_size, linewidth = o_lw, linestyle = 'None')
plt.show()
I'm trying to make an animated 3-D scatter plot with the ability to plot a dynamic number of classes as different colors. This is one of the attempts. I've included the whole code in case it is helpful, and marked the trouble spot with a row of stars:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
from random import uniform
x_arr,y_arr,depth_arr,time_arr,ml_arr,cluster_arr = np.loadtxt(data, unpack=5, usecols=(0, 1, 2, 5, 6))
class Point:
def __init__(self,x,y,depth,time,cluster):
self.x=x
self.y=y
self.depth=depth
self.time=time
self.cluster=cluster
points = []
for i in range(0,len(x_arr)):
points.append(Point(x_arr[i],y_arr[i],depth_arr[i],time_arr[i],cluster_arr[i]))
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_xlim(min(x_arr), max(x_arr))
ax.set_ylim(min(y_arr), max(y_arr))
ax.set_zlim(min(depth_arr), max(depth_arr))
colors_1 = plt.cm.jet(np.linspace(0,max(cluster_arr),max(cluster_arr)+1))
colors = colors_1.reshape(-1,4)
def plot_points(time):
x = []
y = []
z = []
clust = []
points_cp = list(np.copy(points))
for i in range(0,(int(max(cluster_arr))+1)):
for event in points_cp:
if event.cluster == i:
if event.time < time:
points_cp.remove(event)
elif event.time <= time + 86400:
x.append(event.x)
y.append(event.y)
z.append(event.depth)
clust.append(event.cluster)
points_cp.remove(event)
# **************************************************************
color_ind = 0
first_ind = 0
last_ind = 0
for i in range(0,len(x)):
if clust[i] != color_ind:
last_ind = i
for i in range(0,len(x)):
ax.scatter(x[first_ind:last_ind],y[first_ind:last_ind],z[first_ind:last_ind],c=colors[int(color_ind)])
color_ind = clust[i]
first_ind = i
time = np.linspace(min(time_arr),max(time_arr),100)
ani = animation.FuncAnimation(fig,plot_points,time)
plt.show()
This gives me a plot with the correct colors, but once a point is plotted, it remains throughout the entire animation.
I have also tried set_x, set_color, etc., but this doesn't work with a loop (it is updated with each iteration, so that only the last class is actually plotted), and I need to use a for loop to accommodate a variable number of classes. I've tried using a colormap with a fixed extent, but have been unsuccessful, as colormapping doesn't work with the plot function, and I haven't been able to get the rest of the code to work with a scatter function.
Thanks in advance for your help, and my apologies if the code is a little wonky. I'm pretty new to this.
for a particular purpose, I want to plot 2-3 different figures using matplotlib and add different graphs to each of these figures. My particular requirement is complex and hard to explain, so I will try to explain with a simpler example.
For example, imagine I have a list of signals called
[signal_1,signal_2,signal_3, .... , signal _40]
where each 'signal_XXX' represents a numpy-array, some of length 5000 and other length 10,000.
I want to plot all these signals in 2 different graphs, depending on their length.
import matplotlib.pyplot as plt
my_signals = [ signal_1,signal_2,....,signal_40]
fig_5000 = plt.figure(1)
fig_10000 = plt.figure(2)
for signal_i in my_signals :
if len(signal_i) == 5000 :
fig_5000.plot(signal_i)
if len(signal_i) == 10000 :
fig_10000.plot(signal_i)
# now I want to individually show these 2 figures
fig_5000.show()
" do something else here "
fig_10000.show()
Obviously the code which I wrote will not work, also on the last part if I use
plt.show() both graphs will show at the same time, which I don't want.
Is there any way to do the stuff which I want to do using matplotlib ? or should I try something else?
EDIT
I include a 'working' code , with suggestion from Diziet Asahi,
import numpy
import matplotlib.pyplot as plt
my_signals = []
for i in range (0,25):
if i//2 == 0 :
my_signals.append( numpy.random.rand(100))
if i//2 == 1 :
my_signals.append( numpy.random.rand(200))
"""numpy.random.rand craetes an array with random numbers of the given shape.
now we have a list of 50 arrays with 100 and 200 lengths """
fig_100 = plt.figure(1)
ax100 = fig_100.add_subplot(111)
plt.title(" length = 100")
fig_200 = plt.figure(2)
plt.title(" length = 200")
ax200 = fig_200.add_subplot(111)
for arrayzz in my_signals :
if len(arrayzz) == 100 :
ax100.plot(arrayzz)
if len(arrayzz) == 200:
ax200.plot(arrayzz)
plt.show()
This fixes the first part of the earlier problem. Still, I can't show them individually.
In addition to creating figures you also need to create axes. You don't say if you want all your signals to be on the same axes, but generally this should do the trick:
import matplotlib.pyplot as plt
my_signals = [ signal_1,signal_2,....,signal_40]
fig_5000 = plt.figure(1)
ax_5000 = fig_5000.add_subplot(111)
fig_10000 = plt.figure(2)
ax_10000 = fig_10000.add_subplot(111)
for signal_i in my_signals :
if len(signal_i) == 5000 :
ax_5000.plot(signal_i)
if len(signal_i) == 10000 :
ax_10000.plot(signal_i)
plt.show()
There is no good solution for this currently. plt.show() shows all open pyplot figures. You can of course close anyThe problem is essentially the same as this one, and of course writing your own GUI for the figure, showing it whenever you want is possible, but cumbersome.
There is an idea to enhance the show function in a future version, see https://github.com/matplotlib/matplotlib/pull/14024, but for now the solution would be
import numpy
import matplotlib.pyplot as plt
def reshow(fig):
import importlib
import matplotlib.backends
import matplotlib.backend_bases
backend_mod = importlib.import_module(f"matplotlib.backends.backend_{plt.get_backend().lower()}")
Backend = type("Backend", (matplotlib.backends._Backend,), vars(backend_mod))
fm = Backend.new_figure_manager_given_figure(1, fig)
matplotlib.backend_bases.Gcf.set_active(fm)
plt.show()
my_signals = []
for i in range (0,25):
if i//2 == 0 :
my_signals.append( numpy.random.rand(100))
if i//2 == 1 :
my_signals.append( numpy.random.rand(200))
fig_100 = plt.figure(1)
ax100 = fig_100.add_subplot(111)
ax100.set_title(" length = 100")
fig_200 = plt.figure(2)
ax200 = fig_200.add_subplot(111)
ax200.set_title(" length = 200")
for arrayzz in my_signals :
if len(arrayzz) == 100 :
ax100.plot(arrayzz)
if len(arrayzz) == 200:
ax200.plot(arrayzz)
# First close all figures
plt.close("all")
#Then (re)show a single figure
reshow(fig_100)
# and the other one
reshow(fig_200)
Similar with: Plot size = 1/{N∗⌈log2N⌉∗[(1/70)/60]} in R?
But with matplotlib in python (I guess it will be better to plot the function with matplotlib):
size = 1/{N∗⌈log_2(N)⌉∗[(a)/60]}
a = [1/70, 1/60, 1/50, 1/40]
How can I plot this function (for every value in a - it should be one graphic) with matplotlib in python?
(⌈⌉= ceil)
For example:
With label "size" for y-axis and "N" for the x-axis.
N >= 2, N is natural Number (2,3,4,5,6,...) (but it is not necessary to implement this... see picture above)
I have tried this one as a first approach:
import matplotlib.pyplot as plt
import numpy as np
n = np.arange(3,50,0.1)
size = (1)/n*np.ceil(np.log2(n))*((1/70)/60))
plt.plot(n,size)
plt.axis([3,50,0,550])
plt.show()
If you are looking to plot all the distinct segments and not as continuous lines, one way would be to look for discontinuities in the derivative. In this case, the slopes should always be increasing as n increases (n > 0), so you can look for when it violates this condition and then split the lines there.
import matplotlib.pyplot as plt
import numpy as np
from numpy import diff
n = np.arange(3,50,0.1)
a = [1/70,1/60,1/50,1/40]
discont = np.ones(len(n)-1) #array to show discontinuities
discont[1] = 0
for i in a:
size = 1/(n*np.ceil(np.log2(n))*(i/60))
derivs = diff(size)
for k in range(len(derivs)-2):
if derivs[k+1] > derivs[k]:
discont[k+2] = 0
segments = np.squeeze(np.asarray(discont.nonzero()))
for j in range(len(segments)-1):
start, stop = segments[j], segments[j+1]
plt.plot(n[start:stop],size[start:stop], 'b')
plt.axis([0,20,0,300])
plt.xlabel('N')
plt.ylabel('Size')
plt.grid()
plt.show()
This will produce the following plot:
How does one set the color of a line in matplotlib with scalar values provided at run time using a colormap (say jet)? I tried a couple of different approaches here and I think I'm stumped. values[] is a storted array of scalars. curves are a set of 1-d arrays, and labels are an array of text strings. Each of the arrays have the same length.
fig = plt.figure()
ax = fig.add_subplot(111)
jet = colors.Colormap('jet')
cNorm = colors.Normalize(vmin=0, vmax=values[-1])
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
lines = []
for idx in range(len(curves)):
line = curves[idx]
colorVal = scalarMap.to_rgba(values[idx])
retLine, = ax.plot(line, color=colorVal)
#retLine.set_color()
lines.append(retLine)
ax.legend(lines, labels, loc='upper right')
ax.grid()
plt.show()
The error you are receiving is due to how you define jet. You are creating the base class Colormap with the name 'jet', but this is very different from getting the default definition of the 'jet' colormap. This base class should never be created directly, and only the subclasses should be instantiated.
What you've found with your example is a buggy behavior in Matplotlib. There should be a clearer error message generated when this code is run.
This is an updated version of your example:
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib.cm as cmx
import numpy as np
# define some random data that emulates your indeded code:
NCURVES = 10
np.random.seed(101)
curves = [np.random.random(20) for i in range(NCURVES)]
values = range(NCURVES)
fig = plt.figure()
ax = fig.add_subplot(111)
# replace the next line
#jet = colors.Colormap('jet')
# with
jet = cm = plt.get_cmap('jet')
cNorm = colors.Normalize(vmin=0, vmax=values[-1])
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
print scalarMap.get_clim()
lines = []
for idx in range(len(curves)):
line = curves[idx]
colorVal = scalarMap.to_rgba(values[idx])
colorText = (
'color: (%4.2f,%4.2f,%4.2f)'%(colorVal[0],colorVal[1],colorVal[2])
)
retLine, = ax.plot(line,
color=colorVal,
label=colorText)
lines.append(retLine)
#added this to get the legend to work
handles,labels = ax.get_legend_handles_labels()
ax.legend(handles, labels, loc='upper right')
ax.grid()
plt.show()
Resulting in:
Using a ScalarMappable is an improvement over the approach presented in my related answer:
creating over 20 unique legend colors using matplotlib
I thought it would be beneficial to include what I consider to be a more simple method using numpy's linspace coupled with matplotlib's cm-type object. It's possible that the above solution is for an older version. I am using the python 3.4.3, matplotlib 1.4.3, and numpy 1.9.3., and my solution is as follows.
import matplotlib.pyplot as plt
from matplotlib import cm
from numpy import linspace
start = 0.0
stop = 1.0
number_of_lines= 1000
cm_subsection = linspace(start, stop, number_of_lines)
colors = [ cm.jet(x) for x in cm_subsection ]
for i, color in enumerate(colors):
plt.axhline(i, color=color)
plt.ylabel('Line Number')
plt.show()
This results in 1000 uniquely-colored lines that span the entire cm.jet colormap as pictured below. If you run this script you'll find that you can zoom in on the individual lines.
Now say I want my 1000 line colors to just span the greenish portion between lines 400 to 600. I simply change my start and stop values to 0.4 and 0.6 and this results in using only 20% of the cm.jet color map between 0.4 and 0.6.
So in a one line summary you can create a list of rgba colors from a matplotlib.cm colormap accordingly:
colors = [ cm.jet(x) for x in linspace(start, stop, number_of_lines) ]
In this case I use the commonly invoked map named jet but you can find the complete list of colormaps available in your matplotlib version by invoking:
>>> from matplotlib import cm
>>> dir(cm)
A combination of line styles, markers, and qualitative colors from matplotlib:
import itertools
import matplotlib as mpl
import matplotlib.pyplot as plt
N = 8*4+10
l_styles = ['-','--','-.',':']
m_styles = ['','.','o','^','*']
colormap = mpl.cm.Dark2.colors # Qualitative colormap
for i,(marker,linestyle,color) in zip(range(N),itertools.product(m_styles,l_styles, colormap)):
plt.plot([0,1,2],[0,2*i,2*i], color=color, linestyle=linestyle,marker=marker,label=i)
plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.,ncol=4);
UPDATE: Supporting not only ListedColormap, but also LinearSegmentedColormap
import itertools
import matplotlib.pyplot as plt
Ncolors = 8
#colormap = plt.cm.Dark2# ListedColormap
colormap = plt.cm.viridis# LinearSegmentedColormap
Ncolors = min(colormap.N,Ncolors)
mapcolors = [colormap(int(x*colormap.N/Ncolors)) for x in range(Ncolors)]
N = Ncolors*4+10
l_styles = ['-','--','-.',':']
m_styles = ['','.','o','^','*']
fig,ax = plt.subplots(gridspec_kw=dict(right=0.6))
for i,(marker,linestyle,color) in zip(range(N),itertools.product(m_styles,l_styles, mapcolors)):
ax.plot([0,1,2],[0,2*i,2*i], color=color, linestyle=linestyle,marker=marker,label=i)
ax.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.,ncol=3,prop={'size': 8})
U may do as I have written from my deleted account (ban for new posts :( there was). Its rather simple and nice looking.
Im using 3-rd one of these 3 ones usually, also I wasny checking 1 and 2 version.
from matplotlib.pyplot import cm
import numpy as np
#variable n should be number of curves to plot (I skipped this earlier thinking that it is obvious when looking at picture - sorry my bad mistake xD): n=len(array_of_curves_to_plot)
#version 1:
color=cm.rainbow(np.linspace(0,1,n))
for i,c in zip(range(n),color):
ax1.plot(x, y,c=c)
#or version 2: - faster and better:
color=iter(cm.rainbow(np.linspace(0,1,n)))
c=next(color)
plt.plot(x,y,c=c)
#or version 3:
color=iter(cm.rainbow(np.linspace(0,1,n)))
for i in range(n):
c=next(color)
ax1.plot(x, y,c=c)
example of 3:
Ship RAO of Roll vs Ikeda damping in function of Roll amplitude A44