Draw a radar in python with multiple scale - python

I try to generate a complexe radar with VEDO in python. I found a example code from stackoverflow and I want to modify it.
My goal is to generate a radar multiple scale on each axes. Here is the code I have:
import numpy as np
import pylab as pl
from matplotlib import pyplot as plt
class Radar(object):
def __init__(self, fig, titles, labels, rect=None):
if rect is None:
rect = [0.05, 0.05, 0.95, 0.95]
self.n = len(titles)
self.angles = np.arange(90, 90+360, 360.0/self.n)
self.angles = [a % 360 for a in self.angles]
self.axes = [fig.add_axes(rect, projection="polar", label="axes%d" % i)
for i in range(self.n)]
self.ax = self.axes[0]
self.ax.set_thetagrids(self.angles, labels=titles, fontsize=14)
for ax in self.axes[0:]:
ax.patch.set_visible(False)
ax.grid("off")
ax.xaxis.set_visible(False)
index = 0
for ax, angle, label in zip(self.axes, self.angles, labels):
ax.set_rgrids(range(1, label.__len__()+1), angle=angle, labels=label)
ax.spines["polar"].set_visible(True)
ax.set_ylim(0, label.__len__())
index+=1
def plot(self, values, *args, **kw):
angle = np.deg2rad(np.r_[self.angles, self.angles[0]])
values = np.r_[values, values[0]]
self.ax.plot(angle, values, *args, **kw)
fig = pl.figure(figsize=(6, 6))
titles = list("ABCDE")
labels = [
list("abc"), list("12345"), list("uvwxy"),
["one", "two", "three", "four", "five"],
list("jklmn")
]
radar = Radar(fig, titles, labels)
radar.plot([2,2,2,2,2], "-", lw=2, color="b", alpha=0.4, label="first")
radar.plot([2.3, 2, 3, 3, 2],"-", lw=2, color="r", alpha=0.4, label="second")
radar.plot([3, 4, 3, 4, 2], "-", lw=2, color="g", alpha=0.4, label="third")
radar.ax.legend()
plt.show()
And the result:
enter image description here
The blue line is not following the good scale on each axe. It seems to correspond to my first axe I think.

Related

How to insert a small square mark somewhere on a generated heatmap plot

I am creating a 2D matplotlib plot (i and j coordinates) which contains 10 subplots. Each subplot contains 150 by 150 grid cell data. How can I insert a small black-colored square mark (3 by 3 ) somewhere fixed (center at coordinates 62 and 62 ) on each generated heatmap sub-plot across those 10 sub-plots? The square mark would therefore contain 10 blocks from 60 to 64 in both x and y direction and contains a written text "Sale 1" centered at x 62 and y 62. My code below does not generate any patches. Any feedback is greatly appreciated.
from matplotlib.patches import Rectangle
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import r2_score, median_absolute_error
import os
import matplotlib.cm as cm
from mpl_toolkits import axes_grid1
import matplotlib.pyplot as plt
#import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import matplotlib.colors
import matplotlib.colors as colors
data = np.random.rand(10, 150, 150)
data = data.reshape(-1, 1)
property = "Sale"
pmin = data.min()
pmax = data.max()
v = np.linspace(round(pmin,3), round(pmax,3),15, endpoint=True)
v = [round(x,3) for x in v]
fig, ax = plt.subplots(2, 5, figsize=(160, 80))
row_count = 0
col_count = 0
for i in range(10):
sub_plot_data = data[(i)*(150*150):(i+1)*150*150]
x = 150
y = 150
#--------------------------- Define the map boundary ----------------------
xmin = 1258096.6
xmax = 1291155.0
ymin = 11251941.6
ymax = 11285000.0
pmin = min(sub_plot_data)
pmax = max(sub_plot_data)
# --------------------------- define color bar for Discrete color
bounds = np.linspace(-1, 1, 10)
Discrete_colors = plt.get_cmap('jet')(np.linspace(0,1,len(bounds)+1))
# create colormap without the outmost colors
cmap = mcolors.ListedColormap(Discrete_colors[1:-1]) #
actual_2d = np.reshape(sub_plot_data,(y,x))
im1 = ax[row_count, col_count].imshow(actual_2d, interpolation=None, cmap=cmap,
extent=(xmin, xmax, ymin, ymax), vmin=pmin, vmax=pmax)
plt.text(actual_2d[62, 62], actual_2d[62, 62], '%s' % 'Sale_1',
horizontalalignment='center', verticalalignment='center', color= 'black', fontsize= 90)
ax[row_count, col_count].set_title("Sale_Stores-%s - L: %s"%(i+1, layer),
fontsize=130, pad=44, x=0.5, y=0.999) # new
ax[row_count, col_count].set_aspect('auto')
ax[row_count, col_count].tick_params(left=False, labelleft=False, top=False,
labeltop=False, right=False, labelright=False, bottom=False, labelbottom=False) # new
#ax[row_count, col_count] = plt.gca()
plt.gca().add_patch(Rectangle((60, 60), 3, 3, edgecolor='black',
facecolor='black',fill=True,lw=2))
ax[row_count, col_count].add_patch(plt.text(62, 62, '%s' % 'Sale_1',
horizontalalignment='center', verticalalignment='center', color= 'black', fontsize= 90))
col_count +=1
if col_count == 5:
row_count +=1
col_count =0
fig.tight_layout(h_pad=10)
plt.subplots_adjust(left=0.02,
bottom=0.1,
right=0.91,
top=0.8,
wspace=0.1,
hspace=0.2)
cbaxes = fig.add_axes([0.94, 0.05, 0.02, 0.8])
cbar = fig.colorbar(im1, ax=ax.ravel().tolist(), ticks=v, extend='both', cax =cbaxes)
cbar.ax.tick_params(labelsize=70)
#cbar.set_ticks(v)
cbar.ax.set_yticklabels([i for i in v], fontsize=120)
output_dir = r"D/test"
plot_dir = os.path.join(output_dir, reservoir_property)
if not os.path.exists(plot_dir):
os.makedirs(plot_dir)
fig.savefig(r"%s/per_allmodel.png"%(plot_dir))
I tried your code and made a couple of modifications: first, the graph size was too huge and caused errors, so I made it smaller; second, I simplified the subplots: axes has a list of subplot objects, so I took them out with axes.flat; third The second is modifying the text as annotations. The graph size has been reduced and the font size and spacing have been adjusted, so please modify it yourself. Finally, tick_params is not set since the color bar ticks are disabled.
fig, axes = plt.subplots(2, 5, figsize=(16, 8))
row_count = 0
col_count = 0
for i,ax in enumerate(axes.flat):
sub_plot_data = data[(i)*(150*150):(i+1)*150*150]
x = 150
y = 150
#--------------------------- Define the map boundary ----------------------
xmin = 1258096.6
xmax = 1291155.0
ymin = 11251941.6
ymax = 11285000.0
pmin = min(sub_plot_data)
pmax = max(sub_plot_data)
# --------------------------- define color bar for Discrete color
bounds = np.linspace(-1, 1, 10)
Discrete_colors = plt.get_cmap('jet')(np.linspace(0,1,len(bounds)+1))
# create colormap without the outmost colors
cmap = mcolors.ListedColormap(Discrete_colors[1:-1]) #
actual_2d = np.reshape(sub_plot_data,(y,x))
#im = ax.imshow(actual_2d, interpolation=None, cmap=cmap, extent=(xmin, xmax, ymin, ymax), vmin=pmin, vmax=pmax)
im = ax.imshow(actual_2d, interpolation=None, cmap=cmap)
ax.text(actual_2d[62, 62], actual_2d[62, 62]-10, '%s' % 'Sale_1',
horizontalalignment='center', verticalalignment='center', color= 'black', fontsize=18)
ax.set_title("Sale_Stores-%s - L: %s"%(i+1, 1), fontsize=14, pad=30, x=0.5, y=0.999)
ax.set_aspect('auto')
ax.add_patch(Rectangle((60, 60), 6, 6, edgecolor='red', facecolor='red', fill=True, lw=2))
ax.text(62, 62, '%s' % 'Sale_1', ha='center', va='center', color='black', fontsize=14)
fig.tight_layout(h_pad=10)
plt.subplots_adjust(left=0.02,
bottom=0.1,
right=0.91,
top=0.8,
wspace=0.1,
hspace=0.5)
cbaxes = fig.add_axes([0.94, 0.05, 0.02, 0.8])
cbar = fig.colorbar(im, ax=axes.flat, ticks=v, extend='both', cax=cbaxes)
cbar.ax.tick_params(labelsize=10)
#cbar.set_ticks(v)
cbar.ax.set_yticklabels([str(i) for i in v], fontsize=12)
#plt.tick_params(left=False, labelleft=False, top=False, labeltop=False, right=False, labelright=False, bottom=False, labelbottom=False)
plt.show()

framing a pie chart in matplotlib

I am desperately trying to add a "dark" border around this pie chart. I have tried the solutions described in plenty of questions here, but none turned out to add anything. You can find part of the attempts in the code:
import matplotlib.pyplot as plt
from cycler import cycler
plt.rc("axes", prop_cycle=cycler("color", ["darkgray", "gray", "lightgray"])
)
plt.rcParams["axes.edgecolor"] = "0.15"
plt.rcParams["axes.linewidth"] = 1.25
labels = ["lab1", "lab2"]
sizes = [2000, 3000]
def make_autopct(values):
def my_autopct(pct):
total = sum(values)
val = int(round(pct*total/100.0))
s = '{p:.2f}%({v:d}%)'.format(p=pct,v=val)
s = f"${val}_{{\\ {pct:.2f}\%}}$"
return s
return my_autopct
fig, ax = plt.subplots(figsize=(10, 3))
ax.pie(sizes, explode=(0,0.02), labels=labels, autopct=make_autopct(sizes))
ax.set_title("title")
ax.patch.set_edgecolor('black')
ax.patch.set_linewidth('1')
plt.savefig("title.png")
If I've understood your question right possible solution is the following:
# pip install matplotlib
import matplotlib.pyplot as plt
import numpy as np
# set chart style
plt.style.use('_mpl-gallery-nogrid')
# set data
x = [5, 2, 3, 4]
# set colors of segments
colors = plt.get_cmap('GnBu')(np.linspace(0.2, 0.7, len(x)))
# plot
fig, ax = plt.subplots()
ax.pie(x, colors=colors, radius=2,
wedgeprops={"linewidth": 2, "edgecolor": "black", 'antialiased': True}, # << HERE
frame=False, startangle=0, autopct='%.1f%%', pctdistance=0.6)
plt.show()
Below, three possibilities:
add a frame around pie patch:
ax.pie(sizes,
explode=(0,0.02),
labels=labels,
autopct=make_autopct(sizes),
frame=True)
add a border using axes coordinates (0, 0) to (1, 1) with fig.add_artist which draw on the fig object:
rect = pt.Rectangle((-0.1, -0.1), 1.2, 1.2,
fill=False, color="blue", lw=3, zorder=-1
transform=ax.transAxes)
fig.add_artist(rect)
add a border using fig coordinates (0, 0) to (1, 1) with fig.add_artist which draw on the fig object:
rect = pt.Rectangle((0.05, 0.05), .9, .9,
fill=False, ec="red", lw=1, zorder=-1,
transform=fig.transFigure)
fig.add_artist(rect)
Result:
Edit This matplotlib's transformations page explains the different coordinate systems

matplotlib remove the ticks (axis) from the colorbar

I want to remove the (ticks) axis with numbers to the right of the colorbar. I am using matplotlib with python as follows:
f = plt.figure()
ax = f.add_subplot(1,1,1)
i = ax.imshow(mat, cmap= 'gray')
cbar = f.colorbar(i)
If you just want to remove the ticks but keep the ticklabels, you can set the size of the ticks to be 0 as following
f = plt.figure()
ax = f.add_subplot(1,1,1)
mat = np.arange(100).reshape((10, 10))
i = ax.imshow(mat, cmap= 'viridis')
cbar = f.colorbar(i)
cbar.ax.tick_params(size=0)
If you want to remove both, the ticks and the labels, you can use set_ticks([]) by passing an empty list.
cbar.set_ticks([])
Another option is to provided a formatter or locator. Here two combinations of:
a formatter which sets any value to an empty sting ('')
a locator that doesn't place a tick.
See the official matplotlib docs for more formatters or locators.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker
from mpl_toolkits.axes_grid1 import make_axes_locatable
fig, ax = plt.subplots(ncols=1)
mat = np.arange(100).reshape((10, 10))
cs = ax.imshow(mat, cmap= 'viridis')
divider = make_axes_locatable(ax)
dvider_kwargs = dict(position="right", size="15%", pad=0.5)
fig.colorbar(cs,
cax=divider.append_axes(**dvider_kwargs),
format = matplotlib.ticker.FuncFormatter(lambda x, pos: ''),
ticks = matplotlib.ticker.FixedLocator([]))
fig.colorbar(cs,
cax=divider.append_axes(**dvider_kwargs),
format = matplotlib.ticker.FuncFormatter(lambda x, pos: ''))
fig.colorbar(cs,
cax=divider.append_axes(**dvider_kwargs))
plt.tight_layout()
With make_axes_locatable and cax=divider.append_axes the colorbars have all the same size.
Another example
# gen data
n = 100000
bins = np.arange(-10, 10, .1)
value = np.random.normal(loc=20.0, scale=10.0, size=n)
samples0 = np.random.multivariate_normal([-2, 0], [[1, 0], [0, 1]], n)
samples1 = np.random.multivariate_normal([4, 4], [[1, -.9], [-.9, 1]], n)
samples2 = np.random.multivariate_normal([4, -4], [[1, .6], [.6, 1]], n)
h0, e = np.histogramdd(samples0, bins=[bins, bins], density=True)
h1, e = np.histogramdd(samples1, bins=[bins, bins], density=True)
h2, e = np.histogramdd(samples2, bins=[bins, bins], density=True)
# create figure
fig, ax = plt.subplots(ncols=1, figsize=(3,2))
kwargs = dict(vmin=0, vmax=.3)
cs0 = plt.pcolormesh(e[0][:-1], e[1][:-1], np.ma.masked_equal(h0, 0), cmap='Blues', **kwargs)
cs1 = plt.pcolormesh(e[0][:-1], e[1][:-1], np.ma.masked_equal(h1, 0), cmap='Greens', **kwargs)
cs2 = plt.pcolormesh(e[0][:-1], e[1][:-1], np.ma.masked_equal(h2, 0), cmap='Reds', **kwargs)
# create colorbars
divider = make_axes_locatable(ax)
divider_kwargs = dict(position="right", size="5%", pad=0.1)
fig.colorbar(cs0, extend='max',
cax=divider.append_axes(**divider_kwargs),
format = matplotlib.ticker.FuncFormatter(lambda x, pos: ''))
fig.colorbar(cs1, extend='max',
cax=divider.append_axes(**divider_kwargs),
format = matplotlib.ticker.FuncFormatter(lambda x, pos: ''))
fig.colorbar(cs2, extend='max',
cax=divider.append_axes(**divider_kwargs),
label='PDF')
# tune plot
ax.set_aspect('equal')
# ax.grid()
plt.tight_layout()

Python Matplotlib, Stem plot not working with FuncAnimation

I am trying to plot live data from incoming data packet. I have four subplots which on one of the subplot, i want to plot data as Stem plot however i am receiving following error:
self.stemlines.set_data(z, y)
AttributeError: 'list' object has no attribute 'set_data'
plt.plot works fine but I am not able to get it to work for plt.steam.
import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
from matplotlib.widgets import TextBox
import matplotlib
class PlotEngine:
def __init__(self, axisChanged):
# plt.style.use('seaborn-whitegrid')
# style.use('fivethirtyeight')
initialMinValue = '14.4'
initialMaxValue = '14.9'
plt.style.use('ggplot')
matplotlib.rc('axes', titlesize=8) # fontsize of the axes title
matplotlib.rc('axes', labelsize=8)
matplotlib.rc('xtick', labelsize=8) # fontsize of the tick labels
matplotlib.rc('ytick', labelsize=8) # fontsize of the tick labels axes.titlesize
matplotlib.rc('figure', titlesize=8)
self.fig, self.ax = plt.subplots(2, 2)
plt.ion()
# plt.subplot(2, 2, 4, polar=True)
self.fig.patch.set_facecolor('gray')
self.axpolar = plt.subplot(2, 2, 4, projection='polar')
self.axpolar.set_facecolor('black')
# self.ax[1, 1] = fig.add_subplot(2, 2, 4, projection='polar')
self.ax[0, 0].set_facecolor('black')
self.ax[0, 1].set_facecolor('black')
self.ax[1, 0].set_facecolor('black')
self.ax[1, 1].set_facecolor('black')
self.axisChanged = axisChanged
self.slider_freq = plt.axes([0.1, 0.01, 0.3, 0.01])
self.slider_azi = plt.axes([0.5, 0.01, 0.3, 0.01])
self.freqAxBoxMin = plt.axes([0.55, 0.33, 0.04, 0.03])
self.freqAxBoxMax = plt.axes([0.55, 0.28, 0.04, 0.03])
self.freqMinValueBox = TextBox(self.freqAxBoxMin, 'Min Freq:', initial=initialMinValue)
self.freqMaxValueBox = TextBox(self.freqAxBoxMax, 'Max Freq:', initial=initialMaxValue)
self.aziAxBoxMin = plt.axes([0.55, 0.18, 0.04, 0.03])
self.aziAxBoxMax = plt.axes([0.55, 0.10, 0.04, 0.03])
self.aziMinValueBox = TextBox(self.aziAxBoxMin, 'Min Dir:', initial='-180')
self.aziMaxValueBox = TextBox(self.aziAxBoxMax, 'Max Dir:', initial='180')
self.zeroOne, = self.ax[0, 1].plot([], [], 'ro')
self.oneOne, = self.axpolar.plot([], [], 'ro')
self.markerline, self.stemlines, self.baseline, = self.ax[1, 0].stem([1], [1], bottom=-140)
self.ax[0, 1].set_xlim([0, 60])
self.ax[0, 1].set_ylim([-140, -40])
self.axpolar.set_yticks(range(-90, -30, 10)) # Define the yticks
# self.axpolar.set_yticklabels(map(str, range(-90, -30, -10))) # Change the labels
self.ax[1, 0].set_xlim([14, 14.8])
self.ax[1, 0].set_ylim([-140, -40])
# self.background = fig.canvas.copy_from_bbox(self.ax.bbox)
def animateZeroOne(self, i, azimuth, rss, freqGhz):
x = azimuth
y = rss
z = freqGhz
self.zeroOne.set_data(x, y)
self.oneOne.set_data(x, y)
self.stemlines.set_data(z, y)
self.markerline.set_data(z, y)
return self.zeroOne, self.oneOne, self.stemlines, self.markerline
According to StemContainer, stemlines is a list (of Line2D), so it does not have attribute set_data, like markerline or baseline (of type Line2D). Maybe you want to apply that function over every member of the list at your animateZeroOne function?:
def animateZeroOne(self, i, azimuth, rss, freqGhz):
x = azimuth
y = rss
z = freqGhz
self.zeroOne.set_data(x, y)
self.oneOne.set_data(x, y)
[x.set_data(z, y) for x in self.stemlines]
self.markerline.set_data(z, y)
return self.zeroOne, self.oneOne, self.stemlines, self.markerline

Radar chart not centered in matplotlib

I'm trying to learn how radar charts work in matplotlib. I'm using the code in this thread, but the plot I'm producing is not rightly centered and there are axis missing. I' ve tried with matplotlib 1.3.1, 1.4.1 and 1.5.1 in case something changed in the last versions.
import numpy as np
import pylab as pl
class Radar(object):
def __init__(self, fig, titles, labels, rect=None):
if rect is None:
rect = [0.05, 0.05, 0.95, 0.95]
self.n = len(titles)
self.angles = np.arange(90, 90+360, 360.0/self.n)
self.axes = [fig.add_axes(rect, projection="polar", label="axes%d" % i)
for i in range(self.n)]
self.ax = self.axes[0]
self.ax.set_thetagrids(self.angles, labels=titles, fontsize=14)
for ax in self.axes[1:]:
ax.patch.set_visible(False)
ax.grid("off")
ax.xaxis.set_visible(False)
for ax, angle, label in zip(self.axes, self.angles, labels):
ax.set_rgrids(range(1, 6), angle=angle, labels=label)
ax.spines["polar"].set_visible(False)
ax.set_ylim(0, 5)
def plot(self, values, *args, **kw):
angle = np.deg2rad(np.r_[self.angles, self.angles[0]])
values = np.r_[values, values[0]]
self.ax.plot(angle, values, *args, **kw)
fig = pl.figure(figsize=(6, 6))
titles = list("ABCDE")
labels = [
list("abcde"), list("12345"), list("uvwxy"),
["one", "two", "three", "four", "five"],
list("jklmn")
]
radar = Radar(fig, titles, labels)
radar.plot([1, 3, 2, 5, 4], "-", lw=2, color="b", alpha=0.4, label="first")
radar.plot([2.3, 2, 3, 3, 2],"-", lw=2, color="r", alpha=0.4, label="second")
radar.plot([3, 4, 3, 4, 2], "-", lw=2, color="g", alpha=0.4, label="third")
radar.ax.legend()
I had the same problem, but I found that the problem was the following part:
self.angles = np.arange(90, 90+360, 360.0/self.n)
So change it to
self.angles = np.arange(0, 360, 360.0/self.n)
and rotate each ax with ax.set_theta_offset(np.deg2rad(90)) instead.
The modified class looks like this:
# Python 3.4
# matplotlib 1.5.3
class Radar(object):
def __init__(self, fig, titles, labels, rotation=0, rect=None):
if rect is None:
rect = [0.05, 0.05, 0.95, 0.95]
self.n = len(titles)
self.angles = np.arange(0, 360, 360.0/self.n)
self.axes = [fig.add_axes(rect, projection="polar", label="axes%d" % i)
for i in range(self.n)]
self.ax = self.axes[0]
self.ax.set_thetagrids(self.angles, labels=titles, fontsize=14)
for ax in self.axes[1:]:
ax.patch.set_visible(False)
ax.grid("off")
ax.xaxis.set_visible(False)
for ax, angle, label in zip(self.axes, self.angles, labels):
ax.set_rgrids(range(1, 6), angle=angle, labels=label)
ax.spines["polar"].set_visible(False)
ax.set_ylim(0, 6)
ax.set_theta_offset(np.deg2rad(rotation))
def plot(self, values, *args, **kw):
angle = np.deg2rad(np.r_[self.angles, self.angles[0]])
values = np.r_[values, values[0]]
self.ax.plot(angle, values, *args, **kw)
Note: I've added the parameter rotation=0 to __init__ and apply the rotation to all ax in the last loop of it.
I know it's been a while since the question was asked, but I assume someone else will stumble upon this.

Categories