How to combine these two graphs in one graph? - python

first graph
second graph
I tried this script :
X = np.arange( 0, 100)
Quantum_cost_np_q_time = result_df_Quantum_cost['Quantum Cost Execution Time (in s)'].to_numpy()
classical_cost_np_q_time = result_df_classical_cost['Classical Cost Execution Time (in s)'].to_numpy()
plt.plot(X, Quantum_cost_np_q_time, color = 'red', label = 'Quantum_cost_time' )
plt.plot(X, classical_cost_np_q_time, color = "green", label = 'classical_cost_time' )
plt.xlabel("index")
plt.ylabel("execution time")
plt.title("cost")
# Adding legend, which helps us recognize the curve according to it's color
plt.legend()
# To load the display window
plt.show()
I want one graph to compare the two graphs :)

Related

How to use legend only once in a subplot for a for loop?

I am using a for loop and trying to figure out how to use legend only once, either on top or below the subplots.
import matplotlib.pyplot as plt
import numpy as np
plot_loc = 1
total_t = 0.1
dt = [1e-4, 1e-3, 1.5e-3]
for n in dt:
#
#
#
t, y_explicit = explicit_euler(total_t, n)
t, y_implicit = implicit_euler(total_t, n)
y_analytical = analytical(total_t,n)
plt.subplot(3,1,plot_loc)
plt.plot(t, y_explicit, color = 'blue')
plt.plot(t, y_implicit, color = 'black')
plt.plot(t,y_analytical,linestyle='dashed',color = 'orange')
plt.legend(['Explicit','Implicit','Analytical'])
plot_loc+=1
plt.tight_layout(pad=1.0)
plt.show()
If you only want the legend on the last subplot, then just move plt.legend outside the loop.
In that case it plots it in the third subplot (please see the result below), which I don't want. I want it either in the first subplot, below the plots or in the title.
As Mikael suggested, you should first move the legend code line outside the for loop. Then, use bbox_to_anchor() to set the position of the legend.
As you are using plt.plot() to plot each subplot, once you have completed the loop, the plot referred to will be the last one. So, the coordinates will be with respect to the last subplot. I have used -0.25 to set the height so that the plot is below the last subplot. Do adjust this to make sure the legend comes you exactly where you want it.
Also, notice that you can use ncols=3 to show the legend in 3 columns so that the plot looks better. You can remove it if it doesnt suit your requirement. The updated code (with random data) and legend line is given below. Hope this is what you are looking for...
import matplotlib.pyplot as plt
import numpy as np
plot_loc = 1
total_t = 0.1
dt = [1e-4, 1e-3, 1.5e-3]
t=np.linspace(0,0.1,101)
for n in dt:
# t, y_explicit = explicit_euler(total_t, n)
# t, y_implicit = implicit_euler(total_t, n)
# y_analytical = analytical(total_t,n)
y_explicit = np.random.uniform(low=-0.001, high=0, size=(101,))
y_implicit = np.random.uniform(low=-0.001, high=0, size=(101,))
y_analytical = np.random.uniform(low=-0.001, high=0, size=(101,))
plt.subplot(3,1,plot_loc)
plt.plot(t, y_explicit, color = 'blue')
plt.plot(t, y_implicit, color = 'black')
plt.plot(t,y_analytical,linestyle='dashed',color = 'orange')
plot_loc+=1
plt.legend(['Explicit','Implicit','Analytical'], bbox_to_anchor=(0.85, -0.25), ncol=3)
plt.tight_layout(pad=1.0)
plt.show()
Plot

How do I discretize a continuous function avoiding noise generation (see picture)

I have a continuous input function which I would like to discretize into lets say 5-10 discrete bins between 1 and 0. Right now I am using np.digitize and rescale the output bins to 0-1. Now the problem is that sometime datasets (blue line) yield results like this:
I tried pushing up the number of discretization bins but I ended up keeping the same noise and getting just more increments. As an example where the algorithm worked with the same settings but another dataset:
this is the code I used there NumOfDisc = number of bins
intervals = np.linspace(0,1,NumOfDisc)
discretized_Array = np.digitize(Continuous_Array, intervals)
The red ilne in the graph is not important. The continuous blue line is the on I try to discretize and the green line is the discretized result.The Graphs are created with matplotlyib.pyplot using the following code:
def CheckPlots(discretized_Array, Continuous_Array, Temperature, time, PlotName)
logging.info("Plotting...")
#Setting Axis properties and titles
fig, ax = plt.subplots(1, 1)
ax.set_title(PlotName)
ax.set_ylabel('Temperature [°C]')
ax.set_ylim(40, 110)
ax.set_xlabel('Time [s]')
ax.grid(b=True, which="both")
ax2=ax.twinx()
ax2.set_ylabel('DC Power [%]')
ax2.set_ylim(-1.5,3.5)
#Plotting stuff
ax.plot(time, Temperature, label= "Input Temperature", color = '#c70e04')
ax2.plot(time, Continuous_Array, label= "Continuous Power", color = '#040ec7')
ax2.plot(time, discretized_Array, label= "Discrete Power", color = '#539600')
fig.legend(loc = "upper left", bbox_to_anchor=(0,1), bbox_transform=ax.transAxes)
logging.info("Done!")
logging.info("---")
return
Any Ideas what I could do to get sensible discretizations like in the second case?
The following solution gives the exact result you need.
Basically, the algorithm finds an ideal line, and attempts to replicate it as well as it can with less datapoints. It starts with 2 points at the edges (straight line), then adds one in the center, then checks which side has the greatest error, and adds a point in the center of that, and so on, until it reaches the desired bin count. Simple :)
import warnings
warnings.simplefilter('ignore', np.RankWarning)
def line_error(x0, y0, x1, y1, ideal_line, integral_points=100):
"""Assume a straight line between (x0,y0)->(x1,p1). Then sample the perfect line multiple times and compute the distance."""
straight_line = np.poly1d(np.polyfit([x0, x1], [y0, y1], 1))
xs = np.linspace(x0, x1, num=integral_points)
ys = straight_line(xs)
perfect_ys = ideal_line(xs)
err = np.abs(ys - perfect_ys).sum() / integral_points * (x1 - x0) # Remove (x1 - x0) to only look at avg errors
return err
def discretize_bisect(xs, ys, bin_count):
"""Returns xs and ys of discrete points"""
# For a large number of datapoints, without loss of generality you can treat xs and ys as bin edges
# If it gives bad results, you can edges in many ways, e.g. with np.polyline or np.histogram_bin_edges
ideal_line = np.poly1d(np.polyfit(xs, ys, 50))
new_xs = [xs[0], xs[-1]]
new_ys = [ys[0], ys[-1]]
while len(new_xs) < bin_count:
errors = []
for i in range(len(new_xs)-1):
err = line_error(new_xs[i], new_ys[i], new_xs[i+1], new_ys[i+1], ideal_line)
errors.append(err)
max_segment_id = np.argmax(errors)
new_x = (new_xs[max_segment_id] + new_xs[max_segment_id+1]) / 2
new_y = ideal_line(new_x)
new_xs.insert(max_segment_id+1, new_x)
new_ys.insert(max_segment_id+1, new_y)
return new_xs, new_ys
BIN_COUNT = 25
new_xs, new_ys = discretize_bisect(xs, ys, BIN_COUNT)
plot_graph(xs, ys, new_xs, new_ys, f"Discretized and Continuous comparison, N(cont) = {N_MOCK}, N(disc) = {BIN_COUNT}")
print("Bin count:", len(new_xs))
Moreover, here's my simplified plotting function I tested with.
def plot_graph(cont_time, cont_array, disc_time, disc_array, plot_name):
"""A simplified version of the provided plotting function"""
# Setting Axis properties and titles
fig, ax = plt.subplots(figsize=(20, 4))
ax.set_title(plot_name)
ax.set_xlabel('Time [s]')
ax.set_ylabel('DC Power [%]')
# Plotting stuff
ax.plot(cont_time, cont_array, label="Continuous Power", color='#0000ff')
ax.plot(disc_time, disc_array, label="Discrete Power", color='#00ff00')
fig.legend(loc="upper left", bbox_to_anchor=(0,1), bbox_transform=ax.transAxes)
Lastly, here's the Google Colab
If what I described in the comments is the problem, there are a few options to deal with this:
Do nothing: Depending on the reason you're discretizing, you might want the discrete values to reflect the continuous values accurately
Change the bins: you could shift the bins or change the number of bins, such that relatively 'flat' parts of the blue line stay within one bin, thus giving a flat green line in these parts as well, which would be visually more pleasing like in your second plot.

How to plot two case1.hdf5 and case2.hdf5 files in matplotlib. Seeking help to correct the script

I have below script which only plots case1.hdf5 file.
I want to plot another case2.hdf5 file in same script such that I
get two overlapping plots.
Additionally, I want to use
Times New Roman fonts for labels and titles.
Insert Legends for both the plots.
Multiply Y-axis data with some constant number.
This script gives bottom three lines in a same colour but I want all
three in different solid colours for case1.hdf5 and with same
colour and dashed for another case2.hdf5 file.
My script is here
import h5py
import matplotlib.pyplot as plt
import warnings
import matplotlib
warnings.filterwarnings("ignore") # Ignore all warnings
ticklabels=[r'$\Gamma$','F','Q','Z',r'$\Gamma$']
params = {
'mathtext.default': 'regular',
'axes.linewidth': 1.2,
'axes.edgecolor': 'Black',
}
plt.rcParams.update(params)
fig, ax = plt.subplots()
f = h5py.File('band.hdf5', 'r')
#print ('datasets are:')
print(list(f.keys()))
dist=f[u'distance']
freq=f[u'frequency']
kpt=f[u'path']
# Iterate over each segment
for i in range(len(dist)):
# Iteraton over each band
for nbnd in range(len(freq[i][0])):
x=[]
y=[]
for j in range(len(dist[i])):
x.append(dist[i][j])
y.append(freq[i][j][nbnd])
# First 3 bands are red
if (nbnd<3):
color='red'
else:
color='black'
ax.plot(x, y, c=color, lw=2.0, alpha=0.8)
# Labels and axis limit and ticks
ax.set_ylabel(r'Frequency (THz)', fontsize=12)
ax.set_xlabel(r'Wave Vector (q)', fontsize=12)
ax.set_xlim([dist[0][0],dist[len(dist)-1][-1]])
xticks=[dist[i][0] for i in range(len(dist))]
xticks.append(dist[len(dist)-1][-1])
ax.set_xticks(xticks)
ax.set_xticklabels(ticklabels)
# Plot grid
ax.grid(which='major', axis='x', c='green', lw=2.5, linestyle='--', alpha=0.8)
# Save to pdf
plt.savefig('plots.pdf', bbox_inches='tight')
You see, there is
First 3 bands are red
if (nbnd<3):
color='red'
and instead of red I want all of these three in solid different colours and for case2.hdf5 in dashed lines with same colours.
1. Colours
It sounds like in the first instance you want to map different colours to the first there bands of your data.
One way you might do this is to setup a colourmap and then apply it to those first three bands. Here I have just picked the default matplotlib colormap, but there are loads to choose from, so if the default doesn't work for you I would suggest checking out the post about choosing a colormap. In most use cases you should try to stick to a perceptually constant map.
2. Legend
This should just be a matter of calling ax.legend(). Although be wary when setting the position of the legend to be outside the bounds of the plot as you need to do some extra finicking when saving to pdf, as detailed here..
However you first need to add some labels to your plot, which in your case you would do inside your ax.plot() calls. I'm not sure what you are plotting, so can't tell you what labels would be sensible, but you may want something like: ax.plot(... label=f'band {nbnd}' if nbnd < 4 else None).
Notice the inline if. You are likely going to have a whole bunch of black bands that you don't want to label individually, so you likely want to only label the first and let the rest have label = None which means no bloated legend.
3. Scale Y
If you change the way you iterate through your data you should be able to capture the h5 dataset as something that behaves much like a numpy array. What I mean by that is you really only need two loops to index the data you want. freq[i, :, nbnd] should be a 1-d array that you want to set to y. You can multiply that 1-d array by some scale value
4.
import h5py
import matplotlib.pyplot as plt
import warnings
import matplotlib
warnings.filterwarnings("ignore") # Ignore all warnings
cmap = matplotlib.cm.get_cmap('jet', 4)
ticklabels=['A','B','C','D','E']
params = {
'mathtext.default': 'regular',
'axes.linewidth': 1.2,
'axes.edgecolor': 'Black',
'font.family' : 'serif'
}
#get the viridis cmap with a resolution of 3
#apply a scale to the y axis. I'm just picking an arbritrary number here
scale = 10
offset = 0 #set this to a non-zero value if you want to have your lines offset in a waterfall style effect
plt.rcParams.update(params)
fig, ax = plt.subplots()
f = h5py.File('band.hdf5', 'r')
#print ('datasets are:')
print(list(f.keys()))
dist=f[u'distance']
freq=f[u'frequency']
kpt=f[u'path']
lbl = {0:'AB', 1:'BC', 2:'CD', 3:'fourth'}
for i, section in enumerate(dist):
for nbnd, _ in enumerate(freq[i][0]):
x = section # to_list() you may need to convert sample to list.
y = (freq[i, :, nbnd] + offset*nbnd) * scale
if (nbnd<3):
color=f'C{nbnd}'
else:
color='black'
ax.plot(x, y, c=color, lw=2.0, alpha=0.8, label = lbl[nbnd] if nbnd < 3 and i == 0 else None)
ax.legend()
# Labels and axis limit and ticks
ax.set_ylabel(r'Frequency (THz)', fontsize=12)
ax.set_xlabel(r'Wave Vector (q)', fontsize=12)
ax.set_xlim([dist[0][0],dist[len(dist)-1][-1]])
xticks=[dist[i][0] for i in range(len(dist))]
xticks.append(dist[len(dist)-1][-1])
ax.set_xticks(xticks)
ax.set_xticklabels(ticklabels)
# Plot grid
ax.grid(which='major', axis='x', c='green', lw=2.5, linestyle='--', alpha=0.8)
# Save to pdf
plt.savefig('plots.pdf', bbox_inches='tight')
This script gives me the following image with the data you supplied

MatPlotLib how to make plots zoom in and out

I'm new to Python and data visualization and here is the question: I have a plot built with points and lables on them, but since the range between points in general is TOO high but within a groop is too low a have a severe ovellapping =( (can be see on an image). Can anyone suggest either a nice python visualisation lib for such cases or maybe a solution how I can zoom in / out to show those groups closer ? Thanks P.S. labels of axis were messed up I know.
this is how I visualize my plot:
# here we concatinate set of arrays using numpy to display they in the graph
allAvg = np.concatenate((df['Avg']), axis=None)
allYears = np.concatenate((df['Year']), axis=None)
allStocs = np.concatenate((df['Stock']), axis=None)
minValueAvg = min(allAvg)
maxValueAvg = max(allAvg)
start = time.time()
print("Time taken to build plot")
for ind, type in enumerate(df['Stock']):
start = time.time()
print("Time taken to go through one Stock and put it on a plot")
for i, z in enumerate(df['Avg'][ind]):
x = allAvg[i]
y = allYears[i]
plt.scatter(x, y, alpha=0.5, marker='D', color='green')
plt.text(x + 0.1, y + 0.1, type, fontsize=4)
end = time.time()
print(end - start)
plt.xlabel('Year')
plt.ylabel('Average Adjustment Close Price')
plt.title('Stock market graph')
plt.legend()
# show plot right away
plt.show()

Increase visibility of large scatter plot

I am plotting a dotplot( here is a brief explanation of what it is)https://en.wikipedia.org/wiki/Dot_plot_(bioinformatics) of a large amount of data( the largest one being 66x80,000x80,000!!).
The current method I'm using is to plot a matplotlib scatter plot with the x,y coordinates of the dots.
the problem is I can not set the interpolation value of the plot, and the output is not a vector graph. This makes the graph very hard to see when zoomed out.
here is the code:
v_x = np.random.randint(0, 80000, 300000)
v_y = v_x # the x, y cordinate of the dots.
f,axes = plt.subplots(11,11,figsize = (20,20))
for row in range(11):
for col in range(11):
axes[row,col].set_yticklabels([])
axes[row,col].set_xticklabels([])
if row > col:
axes[row,col].axis('off')
else:
axes[row,col].set_xlim(0,len(v_x))
axes[row,col].set_ylim(0,len(v_y))
axes[row,col].scatter(v_x,v_y, c = '#000000', s=(72./300)**2*20, marker = 's', edgecolor= '', rasterized = True)
f.savefig('{}'.format('test.pdf'), facecolor='w', bbox_inches='tight', dpi = 300)
If I don't do the rasteration, the pdf file contains too many dots and cannot be opened, if I do rasteration, the plot is hard to see when zoomed out.
I wonder if there is any way that I can solve this problem.

Categories

Resources