Dears,
I have the following csv file
depth
lst
dol
Anhd
sst
50
20
40
80
100
100
25
50
85
100
150
15
35
75
100
I take the data from csv to draw subplot contains four curves in the same subplot, I have filled by red color from left edge to first curve, also I have filled by blue color from last curve to right edge, I want to fill between entire curves in between first and last curve and make color legend.
the table is equal to csv file
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import pandas as pd
import re
import json
test = r'D:\python\TEST-COMPOSITION.csv'
test =pd.read_csv(test)
mineral_names = test.drop(['depth'],axis=1)
mineral_names = list(mineral_names.columns.values)
colors = ["green", "gray"]
fig = plt.figure(figsize=(15, 12), dpi=100, tight_layout=True)
gs = gridspec.GridSpec(nrows=1, ncols=10, wspace=0)
fig.add_subplot(gs[0, 1])
for i in range(len(mineral_names)-1):
plt.plot(test[mineral_names[i]],test['depth'],linewidth=2, color='black')
for i in range(len(mineral_names)-1):
if i == 0:
left_col_value = 0
right_col_value = 100
span = abs(left_col_value - right_col_value)
cmap = plt.get_cmap('hot_r')
color_index = np.arange(left_col_value, right_col_value, span / 100)
for index in sorted(color_index):
index_value = (index - left_col_value) / span
plt.fill_betweenx(test['depth'],test[mineral_names[0]], left_col_value, where=test[mineral_names[i]] >= index, color="red")
if i == range(len(mineral_names)-1)[-1]:
left_col_value = 0
right_col_value = 100
span = abs(left_col_value - right_col_value)
cmap = plt.get_cmap('hot_r')
color_index = np.arange(left_col_value, right_col_value, span / 100)
for index in sorted(color_index):
index_value = (index - left_col_value) / span
plt.fill_betweenx(test['depth'],test[mineral_names[i]], right_col_value, where=test[mineral_names[i]] >= index, color="blue")
#if i ==1:
#plt.fill_betweenx(test['depth'], test[mineral_names[i+1]], test[mineral_names[i]],color = "green", alpha=0.4)
plt.gca().invert_yaxis()
plt.show()```
Here is an approach looping through the curves, and using a variable previous_curve which contains the position of the previous curve. At the start, the previous curve is all zeros. Similarly, the name of the previous curve can be saved and used as a label for the fill. All labels will appear in the default legend.
The example code below uses a gridspec with only 4 columns, to make the example plot a bit clearer.
import matplotlib.pyplot as plt
from matplotlib import gridspec
import pandas as pd
import numpy as np
test = pd.DataFrame({'depth': [50, 100, 150],
'lst': [20, 25, 15],
'dol': [40, 50, 35],
'Anhd': [80, 85, 75],
'sst': [100, 100, 100]})
mineral_names = test.columns[1:]
fig = plt.figure(figsize=(15, 12), dpi=100, tight_layout=True)
gs = gridspec.GridSpec(nrows=1, ncols=4, wspace=0)
ax = fig.add_subplot(gs[0, 1])
for mineral_name in mineral_names[:-1]:
ax.plot(test[mineral_name], test['depth'], linewidth=2, color='black')
colors = ["red", "green", "gray", "blue"]
previous_curve = 0
previous_name = ''
for mineral_name, color in zip(mineral_names, colors):
ax.fill_betweenx(test['depth'], previous_curve, test[mineral_name], color=color, alpha=0.4,
label=f'{previous_name} - {mineral_name}')
previous_curve = test[mineral_name]
previous_name = mineral_name
ax.margins(x=0, y=0) # no white space in plot
ax.invert_yaxis()
ax.legend()
plt.show()
Related
Why doesn't zorder work in this case? I've tried using it but the text still ends up being covered by the bar plot towers.
import numpy as np
from matplotlib import pyplot as plt
Percentage_Differences_1 = np.array([ [7.94*(10**-10),7.94*(10**-9),7.94*(10**-8),7.94*(10**-7),7.94*(10**-6),7.94*(10**-5)],
[7.92*(10**-12),7.92*(10**-11),7.92*(10**-10),7.92*(10**-9),7.92*(10**-8),7.92*(10**-7)],
[7.72*(10**-14),7.72*(10**-13),7.72*(10**-12),7.72*(10**-11),7.72*(10**-10),7.72*(10**-9)],
[5.66*(10**-16),5.66*(10**-15),5.66*(10**-14),5.66*(10**-13),5.66*(10**-12),5.66*(10**-11)],
[1.49*(10**-17),1.49*(10**-16),1.49*(10**-15),1.49*(10**-14),1.49*(10**-13),1.49*(10**-12)],
[2.21*(10**-18),2.21*(10**-17),2.21*(10**-16),2.21*(10**-15),2.21*(10**-14),2.21*(10**-13)] ]) # Layer 1, 12
fig1 = plt.figure(dpi = 120, tight_layout = True)
fig1.set_size_inches(10, 7)
ax1 = fig1.add_subplot(111, projection='3d')
width = depth = 0.3
column_names = ['$10^{-6} m$','$10^{-5} m$','$10^{-4} m$','$10^{-3} m$','$10^{-2} m$','$10^{-1} m$']
row_names = ['$10^{-6} g$','$10^{-5} g$','$10^{-4} g$','$10^{-3} g$','$10^{-2} g$','$10^{-1} g$']
height_names = ['$10^{-2}$','$10^{-4}$','$10^{-6}$','$10^{-8}$','$10^{-10}$','$10^{-12}$','$10^{-14}$','$10^{-16}$','$10^{-18}$']
for x in range(0,6):
for y in range(0,6):
plot1 = ax1.bar3d(x, y, 0, width, depth, np.log10(Percentage_Differences_1[x][y]), color = "#0040bf", alpha=0.3, zorder = 1)
txt1 = ax1.text(x,y,1.15*np.log10(Percentage_Differences_1[x][y]),'{:.2e}'.format(Percentage_Differences_1[y][x]), verticalalignment='top', bbox=dict(facecolor='grey', alpha=0.5), zorder = 2)
ax1.view_init(-140, -30)
ax1.set_xticks(np.linspace(0, 6, num = 6))
ax1.set_yticks(np.linspace(0, 6, num = 6))
ax1.set_xticklabels(column_names)
ax1.set_yticklabels(row_names)
ax1.set_zticklabels(height_names)
ax1.set_xlabel("Mass", labelpad = 13, rotation = 45)
ax1.set_ylabel("Radius", labelpad = 10, rotation = 45)
ax1.set_zlabel("Deviation $\Delta$")
ax1.set_title("1st Initial Condition: $r(0)$ and $r'(0)$ of $\Theta(12) = 2.18 \\times 10^{7} m$", pad = 40)
plt.show()
I've tried using both set_zorder and zorder but the plot still ends up covering the majority of the text labels.
Change your zorder for a number larger than the number of bar objects, 100 for example:
I am trying to create a bar plot that looks like this:
x axis is the number of detectors hit in coincidence (i.e. multiplicity)
for each multiplicity i have several events. The y axis contains the average pulse height of each event.The colors should correspond to the number of hits which have the shown pulse heights and appeared in events with the respective multiplicity
I have a dictionary that has multiplicities as keys and arrays of the avarage pulse heights as values. :
averages = {2 : [...],
3 : [...],
4 : [...],
5 : [...],
6 : [...],}
for key in averages:
plt.bar(key,averages[key] ,width = 0.8)
i only know how to produce the simple version of a bar chart that looks like this:
can someone tell me how to make the bars "broken to show all pulse heights and add the color coding?
Not entirely clear but I think you want something like this
import seaborn as sns
from scipy import stats
import matplotlib as mpl
import matplotlib.pyplot as plt
# Create some fake data that looks roughly like what you have
tips = sns.load_dataset("tips")
weights = stats.gaussian_kde(tips["total_bill"])(tips["total_bill"])
tips = tips.sample(frac=50, weights=weights, replace=True)
days = []
segments = []
counts = []
for day, x in tips["total_bill"].groupby(tips["day"]):
days.append(day)
segments.append(np.sort(x.unique()))
counts.append(x.value_counts().sort_index())
# Map from counts to colors
norm = mpl.colors.Normalize(0, np.concatenate(counts).max())
colors = [mpl.cm.viridis(norm(c)) for c in counts]
f, ax = plt.subplots()
# Draw each horizontal line
events = ax.eventplot(segments, colors=colors, orientation="vertical", zorder=.5)
events[0].set_norm(norm)
f.colorbar(events[0])
# Add the mean/std for each x position
sns.pointplot(data=tips, x="day", y="total_bill", ci="sd", order=days, join=False, color=".1")
I took the question to need each horizontal line to represent each data value, but if you're satisfied with a histogram, this is two function calls in seaborn (>=0.11)
sns.histplot(
data=tips, x="day", y="total_bill",
discrete=(True, False), binwidth=(1, .5),
cmap="viridis", cbar=True, zorder=.5, alpha=.75,
)
sns.pointplot(
data=tips, x="day", y="total_bill",
ci="sd", order=days, join=False, color=".1",
)
Here is a solution which uses imshow to produce the columnwise "color histograms":
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
# Create dummy data
coincidences = [2, 3, 4, 5, 6]
n_list = [10000, 8000, 6000, 4000, 2000]
mu_list = np.array([200, 300, 400, 500, 600])
scale = 100
averages = {c: np.random.normal(loc=mu_list[i], scale=scale, size=n_list[i])
for i, c in enumerate(coincidences)}
# Calculate histogram for each column
bins = np.linspace(0, 1000, 1000)
hist_img = np.array([np.histogram(averages[c], bins=bins)[0]
for c in coincidences]).T
# Create Normalized colormap
# norm = mpl.colors.Normalize()
norm = mpl.colors.LogNorm(vmin=1, vmax=hist_img.max())
sm = mpl.cm.ScalarMappable(cmap='viridis', norm=norm)
# Use colormap for img_hist and make zeros transparent
hist_img2 = sm.to_rgba(hist_img, bytes=True)
hist_img2[hist_img == 0, 3] = 0
# Plot
fig, ax = plt.subplots()
cc = ax.imshow(hist_img2, aspect='auto', interpolation='none', origin='lower',
extent=[1.5, 6.5, 0, 1000])
plt.colorbar(sm)
mean = [np.mean(averages[c]) for c in coincidences]
std = [np.std(averages[c]) for c in coincidences]
ax.errorbar(coincidences, mean, yerr=std, ls='', c='k', capsize=3, label='std')
ax.plot(coincidences, mean, ls='', marker='o', c='b', label='mean')
ax.legend()
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.pyplot import figure
plt.style.use('ggplot')
overs = np.arange(1, 51)
india_score = np.random.randint(low = 1, high = 18, size = 50, dtype = 'int16')
plt.bar(overs, india_score, width = 0.80, align = 'center', color = 'orange', label = 'Runs per over')
plt.xlabel('Overs')
plt.ylabel('Score')
plt.title('India Inning')
plt.axis([1, 50, 0, 18])
plt.legend()
plt.grid(color='k', linestyle='-', linewidth=1)
fig = plt.gcf()
fig.set_size_inches(16, 9)
plt.show()
The output looks like this:
If you see the bar chart then runs scored in first over and runs scored in last over stick to the Y axis. How can I give some space between Y axis and my first and last vertical bars. I tried the margins function but that is not working
I searched for similar posts but I was unable to understand the solution as I am new to matplotlib. Any help will be greatly appreciated. Thanks.
Here is how you could do this:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.pyplot import figure
plt.style.use('ggplot')
overs = np.arange(1, 51)
india_score = np.random.randint(low = 1, high = 18, size = 50, dtype = 'int16')
plt.bar(overs, india_score, width = 0.80, align = 'center', color = 'orange', label = 'Runs per over')
plt.xlabel('Overs')
plt.ylabel('Score')
plt.title('India Inning')
plt.axis([1, 50, 0, 18])
plt.legend()
plt.grid(color='k', linestyle='-', linewidth=1)
fig = plt.gcf()
fig.set_size_inches(16, 9)
left, right = plt.xlim()
plt.xlim(left-1, right+1)
plt.show()
left, right = plt.xlim() gets the current limits of the x-axis and plt.xlim(left-1, right+1) sets the new limits by one step further outside relative to the old limits.
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 am trying to animate multiple patches as efficiently as possible when reading data from a list?
The code below displays an animation of the scatter plot but not the patches. Each point in scatter plot contains various sizes of circles. This example would require 6 different circles to be animated at 2 subjects each time point. But what if there were 20 subjects that each had 3 circles around them.
What is the most efficient way to animate all 60 circles for each frame?
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib as mpl
x_data = np.random.randint(80, size=(400, 4))
y_data = np.random.randint(80, size=(400, 4))
fig, ax = plt.subplots(figsize = (8,6))
ax.set_xlim(0,80)
ax.set_ylim(0,80)
scatter = ax.scatter(x_data[0], y_data[0], zorder = 5) #Scatter plot
Player_1 = x_data[0][0], y_data[0][0]
Player_2 = x_data[0][1], y_data[0][1]
Player_1_IR = mpl.patches.Circle(Player_1, radius = 2, color = 'black', lw = 1, alpha = 0.8, zorder = 4)
Player_1_MR = mpl.patches.Circle(Player_1, radius = 4, color = 'gray', lw = 1, alpha = 0.8, zorder = 3)
Player_1_OR = mpl.patches.Circle(Player_1, radius = 6, color = 'lightgrey', lw = 1, alpha = 0.8, zorder = 2)
Player_2_IR = mpl.patches.Circle(Player_2, radius = 2, color = 'black', lw = 1, alpha = 0.8, zorder = 4)
Player_2_MR = mpl.patches.Circle(Player_2, radius = 4, color = 'gray', lw = 1, alpha = 0.8, zorder = 3)
Player_2_OR = mpl.patches.Circle(Player_2, radius = 6, color = 'lightgrey', lw = 1, alpha = 0.8, zorder = 2)
ax.add_patch(Player_1_IR)
ax.add_patch(Player_1_MR)
ax.add_patch(Player_1_OR)
ax.add_patch(Player_2_IR)
ax.add_patch(Player_2_MR)
ax.add_patch(Player_2_OR)
def animate(i) :
scatter.set_offsets(np.c_[x_data[i,:], y_data[i,:]])
ani = animation.FuncAnimation(fig, animate, frames=len(x_data),
interval = 700, blit = False)
plt.show()
You can store all patches that you want to update in a list through which you then iterate through every iteration step. Note that the size of the Circle patches is in data units/coordinates while the scatter plot points are in points (one point = 1/72 inch), which means that the relative size between scatter points and circles depends on the figure size and axes limits and will change when you re-scale the figure.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib as mpl
x_data = np.random.randint(80, size=(400, 20))
y_data = np.random.randint(80, size=(400, 20))
fig, ax = plt.subplots(figsize = (8,6))
ax.set_xlim(0,80)
ax.set_ylim(0,80)
scatter = ax.scatter(x_data[0], y_data[0], zorder = 5) #Scatter plot
##creating list of patches
players = []
for n in range(10):
##as there are always 3 circles, append all three patches as a list at once
players.append([
mpl.patches.Circle((x_data[0,n],y_data[0,n]), radius = 2, color = 'black', lw = 1, alpha = 0.8, zorder = 4),
mpl.patches.Circle((x_data[0,n],y_data[0,n]), radius = 4, color = 'gray', lw = 1, alpha = 0.8, zorder = 3),
mpl.patches.Circle((x_data[0,n],y_data[0,n]), radius = 6, color = 'lightgrey', lw = 1, alpha = 0.8, zorder = 2)
])
##adding patches to axes
for player in players:
for circle in player:
ax.add_patch(circle)
def animate(i):
scatter.set_offsets(np.c_[x_data[i,:], y_data[i,:]])
##updating players:
for n,player in enumerate(players):
for circle in player:
circle.center = (x_data[i,n],y_data[i,n])
ani = animation.FuncAnimation(fig, animate, frames=len(x_data),
interval = 700, blit = False)
plt.show()
Old Answer (slightly different visual effect, but could be tuned to look the same):
If you really just want circles around your scatter points, you can actually forget about the Circle patches and just overlay several scatter plots with different marker sizes.
In the example below I only mark part of the scatter points with circles by slicing the array of random numbers. Also remember that in scatter plots the marker size is given as points square, so if you want to increase the circle radius from, say, 5 to 6, the given marker size should change from 25 to 36.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib as mpl
x_data = np.random.randint(80, size=(400, 20))
y_data = np.random.randint(80, size=(400, 20))
fig, ax = plt.subplots(figsize = (8,6))
ax.set_xlim(0,80)
ax.set_ylim(0,80)
scatter = ax.scatter(x_data[0], y_data[0], zorder = 5) #Scatter plot
scatter_IR = ax.scatter(
x_data[0,:10], y_data[0,:10], zorder = 4,
facecolor='black', edgecolor = 'black',
alpha = 0.8, s = 100
)
scatter_MR = ax.scatter(
x_data[0,:10], y_data[0,:10], zorder = 3,
facecolor='grey', edgecolor = 'grey',
alpha = 0.8, s = 225
)
scatter_OR = ax.scatter(
x_data[0,:10], y_data[0,:10], zorder = 2,
facecolor='lightgrey', edgecolor = 'lightgrey',
alpha = 0.8, s = 400
)
def animate(i) :
scatter.set_offsets(np.c_[x_data[i,:], y_data[i,:]])
scatter_IR.set_offsets(np.c_[x_data[i,:10], y_data[i,:10]])
scatter_MR.set_offsets(np.c_[x_data[i,:10], y_data[i,:10]])
scatter_OR.set_offsets(np.c_[x_data[i,:10], y_data[i,:10]])
ani = animation.FuncAnimation(fig, animate, frames=len(x_data),
interval = 700, blit = False)
plt.show()