I have three different data columns. The columns have been converted to simplify the question.
size = [0.25, 0.5, 1.0, 2.0, 0.25, 0.5, 1.0, 2.0, 0.25, 0.5, 1.0, 2.0]
time = [228.64, 28.8, 3.88, 0.47, 439.72,54.2, 6.65, 0.77, 808.67, 103.53, 12.3, 1.79]
error = [0.0, 0.53, 0.28, 2.03, 0.0, 0.09, 0.29, 2.22, 0.0, 0.04, 0.35, 0.11]
I am trying to plot them using a scatter plot. X-axis will contain the size and Y-axis will contain time and error.
import plotly.graph_objects as go
from plotly.subplots import make_subplots
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(
go.Scatter(x=size, y=time, name="Time", mode = "markers", marker_symbol=3, marker_size = 10, marker_color = "red"),
secondary_y=False)
fig.add_trace(
go.Scatter(x=size, y=error, mode = "markers",name="Error", marker_symbol=14,marker_size = 10, marker_color = "black")),
secondary_y=True)
fig.show()
I want to add trendlines:
exponential/logarithmic trendline for size vs time
linear trendline for size vs error
Is there a built-in function of doing that?
I am getting the following graph:
I think Plotly Express has built-in support for some trendlines:https://plotly.com/python/linear-fits/
But not 'plain' Plotly. But it is not difficult to add them by hand. See the few lines I added to calculate the fitted values
size = [0.25, 0.5, 1.0, 2.0, 0.25, 0.5, 1.0, 2.0, 0.25, 0.5, 1.0, 2.0]
time = [228.64, 28.8, 3.88, 0.47, 439.72,54.2, 6.65, 0.77, 808.67, 103.53, 12.3, 1.79]
error = [0.0, 0.53, 0.28, 2.03, 0.0, 0.09, 0.29, 2.22, 0.0, 0.04, 0.35, 0.11]
import numpy as np
from sklearn.linear_model import LinearRegression
err_size_regr = LinearRegression()
err_size_res = err_size_regr.fit(np.array(size).reshape(-1,1), np.array(error))
err_fit = err_size_regr.predict(np.array(size).reshape(-1,1))
time_size_regr = LinearRegression()
time_size_res = err_size_regr.fit(np.array(size).reshape(-1,1), np.log(np.array(time)))
time_fit = np.exp(time_size_res.predict(np.array(size).reshape(-1,1)))
import plotly.graph_objects as go
from plotly.subplots import make_subplots
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(
go.Scatter(x=size, y=time, name="Time", mode = "markers", marker_symbol=3, marker_color = "red"),
secondary_y=False)
fig.add_trace(
go.Scatter(x=size, y=time_fit, mode = "markers",name="Time fit", marker_symbol=3, marker_color = "blueviolet"),
secondary_y=False)
fig.add_trace(
go.Scatter(x=size, y=error, mode = "markers",name="Error", marker_symbol=14,marker_color = "green"),
secondary_y=True)
fig.add_trace(
go.Scatter(x=size, y=err_fit, mode = "lines",name="Error fit", marker_color = "lightgreen"),
secondary_y=True)
fig.show()
output (sorry I changed your colours to see the result better)
Related
This question already has answers here:
How to create a grouped bar plot
(4 answers)
Closed 7 months ago.
Here is how I bar-plot from a group:
import numpy as np
import matplotlib.pyplot as plt
metrics = ['accuracy', 'precision', 'recall','f1_score', 'roc_auc_score']
x_values = np.arange(len(metrics))
width = 0.15
RF = [0.62, 0.59, 0.62, 0.57, 0.78]
SMOTE = [0.63, 0.62, 0.63, 0.60, 0.79]
AdaBoost = [0.27, 0.42, 0.27, 0.28, 0.58]
SMOTEBoost = [0.54, 0.60, 0.54, 0.57, 0.68]
decoc = [0.63, 0.61, 0.63, 0.58, 0.69]
plt.bar(x_values-0.2, RF, width=width, label='RF')
plt.bar(x_values, SMOTE, width=width, label='SMOTE')
plt.bar(x_values+0.2, AdaBoost, width=width, label='AdaBoost')
plt.bar(x_values+0.4, SMOTEBoost, width=width, label='SMOTEBoost')
plt.bar(x_values+0.6, decoc, width=width, label='DECOC')
plt.xticks(x_values, metrics)
plt.legend(loc='best')
plt.ylim(0.0, 1.2)
plt.title('Performance Evaluation')
plt.xlabel('Performance Metrics')
plt.show()
Figure:
But I need a space between each group ('accuracy', 'precision', 'recall','f1_score', 'roc_auc_score') to make it better. As it is, groups are mixed with almost no space separating.
Any reason to do multiple bar plots instead of one and pass the hue variable?
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (16,8)
RF = [0.62, 0.59, 0.62, 0.57, 0.78]
SMOTE = [0.63, 0.62, 0.63, 0.60, 0.79]
AdaBoost = [0.27, 0.42, 0.27, 0.28, 0.58]
SMOTEBoost = [0.54, 0.60, 0.54, 0.57, 0.68]
decoc = [0.63, 0.61, 0.63, 0.58, 0.69]
metrics = ['accuracy', 'precision', 'recall','f1_score', 'roc_auc_score']
df = pd.DataFrame({"metrics":metrics,"RF":RF, "SMOTE":SMOTE,"AdaBoost":AdaBoost,"SMOTEBoost":SMOTEBoost,"decoc":decoc})
df = pd.melt(df, id_vars="metrics")
sns.barplot(data=df, x="metrics", y="value", hue="variable")
plt.legend(loc='best')
plt.ylim(0.0, 1.2)
plt.title('Performance Evaluation')
plt.xlabel('Performance Metrics')
plt.show()
Increase the spacing between the x-values:
x_values = np.arange(0, len(metrics)*2, 2)
I am new to matplotlib and I am asking for your help to solve my little problem. I am sharing the graph below, here are the questions:
1- I want x-axis and y-axis replace
2- And most important for me is that errorbars should be horizontal (in graph below these are vertical).
Some errorbars in the graph is overlapping and I tried to avoid this problem using transform command. As I said before if I can manage the replacement of X and Y axis I would be happy.
Below I am sharing the code I wrote:
import ax as ax
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.transforms import Affine2D
y_values = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
p1 = [1, 0.77, 0.67, 0.85, 0.78, 1.05, 0.63]
p2 = [3, 2, 1.5, 1.20, 1.10, 1.40, 1.10]
x_err = [0.1, 0.2, 0.4, 0.5, 0.3, 0.2, 0.3]
y_err = [0.6, 0.2, 0.4, 0.5, 0.3, 0.2, 0.3]
fig, ax = plt.subplots()
trans1 = Affine2D().translate(-0.1, 0.0) + ax.transData
trans2 = Affine2D().translate(+0.1, 0.0) + ax.transData
er1 = ax.errorbar(y_values, p1, x_err, marker="o", linestyle="none", transform=trans1)
er2 = ax.errorbar(y_values, p2, y_err, marker="o", linestyle="none", transform=trans2)
errorbar plot
I'm trying to create a scatter plot with x and y errors that have different marker and errorbar colors in four sections (e.g. red for x=0 to x=2, blue for x=2 to c=5, etc.). I have used a colormap with bounds for the markers, but I haven't been able to do something similar for the errorbars. I've tried to set the markers, errorbars, and caps as the same color in the scatter colormap using this answer to a similar question, but I wasn't able to get it to work for my code (comes up with an error about lengths of data not matching or unable to convert to tuple). I think I haven't been able to correctly modify it for the colormap I use for the markers, or this isn't the best way to go about getting the right result.
This is an example with some made up data:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
bounds = [0,1.5,3,4.5,5]
colors = ["r", "b", "g", "y"]
cmap = matplotlib.colors.ListedColormap(colors)
norm = matplotlib.colors.BoundaryNorm(bounds, len(colors))
x = np.array([0.0, 0.0, 1.0, 2.0, 2.0, 3.0, 4.0, 4.0, 5.0, 5.0])
y = np.array([0.0, 0.1, 0.8, 0.9, 0.7, 0.1, -0.8, -0.5, -1.0, -0.7])
x_err = np.array([0.05, 0.06, 0.04, 0.045, 0.04, 0.06, 0.05, 0.055, 0.02, 0.05])
y_err = np.array([0.04, 0.05, 0.03, 0.055, 0.145, 0.065, 0.045, 0.15, 0.015, 0.17])
plt.scatter(x, y, marker='D', c=x, cmap=cmap, norm=norm)
plt.errorbar(x, y, xerr=x_err, yerr=y_err, fmt='.', lw=2, capsize=3, alpha=0.7, zorder=0)
plt.show()
which gives
.
How can I get the errorbars to have the same colormap as the one used in the scatter plot?
This is certainly not the fastest method but it works: get the colors for each x-value using to_rgba and then plot the error bars pointwise (probably slow for large data arrays):
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
import matplotlib.cm
bounds = [0,1.5,3,4.5,5]
colors = ["r", "b", "g", "y"]
cmap = matplotlib.colors.ListedColormap(colors)
norm = matplotlib.colors.BoundaryNorm(bounds, len(colors))
x = np.array([0.0, 0.0, 1.0, 2.0, 2.0, 3.0, 4.0, 4.0, 5.0, 5.0])
y = np.array([0.0, 0.1, 0.8, 0.9, 0.7, 0.1, -0.8, -0.5, -1.0, -0.7])
x_err = np.array([0.05, 0.06, 0.04, 0.045, 0.04, 0.06, 0.05, 0.055, 0.02, 0.05])
y_err = np.array([0.04, 0.05, 0.03, 0.055, 0.145, 0.065, 0.045, 0.15, 0.015, 0.17])
plt.scatter(x, y, marker='D', c=x, cmap=cmap, norm=norm)
colors = matplotlib.cm.ScalarMappable(norm,cmap).to_rgba(x)
for i,_ in enumerate(x):
plt.errorbar(x[i], y[i], xerr=x_err[i], yerr=y_err[i], fmt='.', lw=2, capsize=3, alpha=0.7, zorder=0, ecolor=colors[i])
plt.show()
I am trying to put multiple matplotlib subplots into a big axis, where tick labels on the big axis correspond to some parameter values for which the data in each subplot has been obtained. Here's an example,
import matplotlib.pyplot as plt
data = {}
data[(10, 10)] = [0.45, 0.30, 0.25]
data[(10, 20)] = [0.2, 0.5, 0.3]
data[(20, 10)] = [0.1, 0.3, 0.6]
data[(20, 20)] = [0.6, 0.15, 0.25]
data[(30, 10)] = [0.4, 0.35, 0.25]
data[(30, 20)] = [0.5, 0.1, 0.4]
# x and y coordinates for the big plot
x_coords = list(set([k[0] for k in data.keys()]))
y_coords = list(set([k[1] for k in data.keys()]))
labels = ['Frogs', 'Hogs', 'Dogs']
explode = (0.05, 0.05, 0.05) #
colors = ['gold', 'beige', 'lightcoral']
fig, axes = plt.subplots(len(y_coords), len(x_coords))
for row_topToDown in range(len(y_coords)):
row = (len(y_coords)-1) - row_topToDown
for col in range(len(x_coords)):
axes[row][col].pie(data[(x_coords[col], y_coords[row_topToDown])], explode=explode, colors = colors, \
autopct=None, pctdistance = 1.4, \
shadow=True, startangle=90, radius=0.7, \
wedgeprops = {'linewidth':1, 'edgecolor':'Black'}
)
axes[row][col].axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle.
axes[row][col].set_title('(' + str(x_coords[col]) + ', ' + str(y_coords[row_topToDown]) + ')')
fig.tight_layout()
plt.show()
and here's how I'd like the output to look like:
I see two options:
A. use a single axes
You may plot all pie charts to the same axes. Use the center and radius argument to scale the pies in data coordinates. This could look as follows.
import matplotlib.pyplot as plt
data = {}
data[(10, 10)] = [0.45, 0.30, 0.25]
data[(10, 20)] = [0.2, 0.5, 0.3]
data[(20, 10)] = [0.1, 0.3, 0.6]
data[(20, 20)] = [0.6, 0.15, 0.25]
data[(30, 10)] = [0.4, 0.35, 0.25]
data[(30, 20)] = [0.5, 0.1, 0.4]
labels = ['Frogs', 'Hogs', 'Dogs']
explode = [.2]*3
colors = ['gold', 'beige', 'lightcoral']
radius = 4
margin = 2
fig, ax = plt.subplots()
for x,y in data.keys():
d = data[(x,y)]
ax.pie(d, explode=explode, colors = colors, center=(x,y),
shadow=True, startangle=90, radius=radius,
wedgeprops = {'linewidth':1, 'edgecolor':'Black'})
ax.annotate("({},{})".format(x,y), xy = (x, y+radius),
xytext = (0,5), textcoords="offset points", ha="center")
ax.set_frame_on(True)
xaxis = list(set([x for x,y in data.keys()]))
yaxis = list(set([y for x,y in data.keys()]))
ax.set(aspect="equal",
xlim=(min(xaxis)-radius-margin,max(xaxis)+radius+margin),
ylim=(min(yaxis)-radius-margin,max(yaxis)+radius+margin),
xticks=xaxis, yticks=yaxis)
fig.tight_layout()
plt.show()
B. use inset axes
You can put each pie in its own axes and position the axes in data coordinates. This is facilitated by using mpl_toolkits.axes_grid1.inset_locator.inset_axes. The main difference to the above is that you may use a non-equal aspect of the parent axes, and that it's not possible to use tight_layout.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
data = {}
data[(10, 10)] = [0.45, 0.30, 0.25]
data[(10, 20)] = [0.2, 0.5, 0.3]
data[(20, 10)] = [0.1, 0.3, 0.6]
data[(20, 20)] = [0.6, 0.15, 0.25]
data[(30, 10)] = [0.4, 0.35, 0.25]
data[(30, 20)] = [0.5, 0.1, 0.4]
labels = ['Frogs', 'Hogs', 'Dogs']
explode = [.05]*3
colors = ['gold', 'beige', 'lightcoral']
radius = 4
margin = 2
fig, axes = plt.subplots()
for x,y in data.keys():
d = data[(x,y)]
ax = inset_axes(axes, "100%", "100%",
bbox_to_anchor=(x-radius, y-radius, radius*2, radius*2),
bbox_transform=axes.transData, loc="center")
ax.pie(d, explode=explode, colors = colors,
shadow=True, startangle=90,
wedgeprops = {'linewidth':1, 'edgecolor':'Black'})
ax.set_title("({},{})".format(x,y))
xaxis = list(set([x for x,y in data.keys()]))
yaxis = list(set([y for x,y in data.keys()]))
axes.set(aspect="equal",
xlim=(min(xaxis)-radius-margin,max(xaxis)+radius+margin),
ylim=(min(yaxis)-radius-margin,max(yaxis)+radius+margin),
xticks=xaxis, yticks=yaxis)
plt.show()
For how to put a legend outside the plot, I would refer you to How to put the legend out of the plot. And for how to create a legend for a pie chart to How to add a legend to matplotlib pie chart?
Also Python - Legend overlaps with the pie chart may be of interest.
I am trying to create a third slider to control my plot.
fig, ax = plt.subplots()
plt.subplots_adjust(left=0.25, bottom=0.25)
l, = plt.plot(u,v, lw=1, color='red')
plt.axis([-20, 20, -20,20])
amp_slider_ax = fig.add_axes([0.25, 0.15, 0.65, 0.03], axisbg=axis_color)
samp = Slider(amp_slider_ax, 'Ey', 1, 10.0, valinit=a0)
freq_slider_ax = fig.add_axes([0.25, 0.1, 0.65, 0.03], axisbg=axis_color)
sfreq = Slider(freq_slider_ax, 'gamma (Ex/Ey)', 0.01, 1.3, valinit=f0)
#new slider
fbz_slider_ax = fig.add_axes([3, 7, 0.65, 0.03], axisbg=axis_color)
sbz = Slider(fbz_slider_ax, 'Bz', 0.01, 1.3, valinit=b0)
I don't see why my third slider is not being initialized. Can someone provide an example with 3 sliders, please. When I call the slider object, I do not get any errors either.
In the line fig.add_axes([3, 7, 0.65, 0.03]) you are adding an axes at coordinates (3,7). The point (3,7) does not lie inside the figure, as the figure goes from 0 to 1 in both directions.
The solution is of course to add the axes somewhere inside the figure.