I am trying to plot column data vs the row label of a data frame. When I do so, the plot looks good but the the Y axis starts to look illegible as the number of rows is increased. What I don't get it why does the automatic spacing for the X axis work fine but not the same for the Y axis.
x1 = M.iloc[:,1]
plt.plot(x1,x)
Where the variable "x" represents Column 0 values of dataframe "M" below
The "M" dataframe:
0.0 0.5 1.0
0 300 300.000000 1550
1.00e-01 s 300 300.769527 1550
2.00e-01 s 300 301.538106 1550
3.00e-01 s 300 302.305739 1550
.
.
.
2.80e+00 s 300 321.192396 1550
2.90e+00 s 300 321.935830 1550
Edit
So it seems it's the formatting of the first column being in scientific notation that is messing things up, still not sure why however
x = [0]
i=1
while i < 30:
q = i*0.1
xx = str('{:.2e}'.format(q)) + ' s'
x.append(xx)
i = i + 1
M = pd.DataFrame(index=x, columns=3)
So in the code above, it is the line xx = str('{:.2e}'.format(q)) + ' s' that is making the Y-labels go crazy. I unfortunately can't take it out as I need them to be in scientific notation.
You can try tick-spacing if okay to eliminate few tick labels. Other options are to increase you plot size or decrase font size for y labels.
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
x1 = M.iloc[:,1]
tick_spacing = 2 # or whatever label gap you want to use.
fig, ax = plt.subplots(1,1)
apx.plot(x1,x)
ax.yaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))
plt.show()
Related
How can i use my while loop conditions to loop through axis of subplots. I am very new to python. I have written a code where i plot the data based on some conditions in a while loop. The code works fine for plotting individual plots but when i have to plot all in one plot like subplots, i don't know how can i index that every time one round of plotting is finished the axis index should change and the next plotting is done on different index. As in the image it can be seen, the first row is plotted and rest everything is plotted all over again as the loop has no condition to go for axis indexing. How can i achieve is that every time the value of i,j.l,m in the code is incremented, the plots should move to next row in subplot figure.[]
import matplotlib.pyplot as plt
import xarray as xr
file="/home/arjun2516/hlrn/JOBS/cy_topo_ref4hr2/OUTPUT/cy_topo_ref4hr2_av_3d.002.nc"
Data=xr.open_dataset(file)
l=150
m=300
i = 75
j = 175
while i and j < 700 and l and m < 800 :
fig,axs = plt.subplots(ncols=3, nrows=3,figsize=(20,20))
Data.zusi[i:j,75:175].plot.contourf(ax=axs[0,0])
print(i,j)
# plt.show()
Data.zusi[l:m,250:400].plot.contourf(ax=axs[0,1])
# plt.show()
Data.zusi[l:m,450:600].plot.contourf(ax=axs[0,2])
# plt.show()
i += 200
j += 200
l += 200
m += 200
print(i,j)
print('ok')
I tried to introduce a for loop inside the while loop but it was also producing same results.
There is several problems in your code:
You are creating a new figure object (containing the grid of subplots) in every loop iteration, so the plots from different iterations will end up in different figures. Move the plt.subplots command before the loop.
In order to plot onto the axis of a different row in each loop iteration, you need an axis index that starts at zero (that is, indexing the first row) and is incremented in each iteration.
With these changes, your code becomes:
l=150
m=300
i = 75
j = 175
fig,axs = plt.subplots(ncols=3, nrows=3,figsize=(20,20))
ax_idx = 0
while i and j < 700 and l and m < 800 :
# Select axis based on the axis index
Data.zusi[i:j,75:175].plot.contourf(ax=axs[ax_idx,0])
print(i,j)
# plt.show()
Data.zusi[l:m,250:400].plot.contourf(ax=axs[ax_idx,1])
# plt.show()
Data.zusi[l:m,450:600].plot.contourf(ax=axs[ax_idx,2])
# plt.show()
i += 200
j += 200
l += 200
m += 200
# Increase the axis index
ax_idx += 1
print(i,j)
Note that you could also simplify your code by using a for loop. I would also highly recommend using xarray's capabilities for label-based indexing, in this case isel. It makes the code a little bit more verbose, but much more understandable.
n_rows = 3
fig,axs = plt.subplots(ncols=3, nrows=n_rows, figsize=(20,20))
ax_idx = 0
for ax_idx in range(n_rows):
# Compute the index values
l = 150 + ax_idx * 200
m = 300 + ax_idx * 200
i = 75 + ax_idx * 200
j = 175 + ax_idx * 200
# Index array based on named dimensions and plot it
Data.zusi.isel(x=slice(i, j), y=slice(75, 175)).plot.contourf(ax=axs[ax_idx, 0])
Data.zusi.isel(x=slice(l, m), y=slice(250, 400)).plot.contourf(ax=axs[ax_idx, 1])
Data.zusi.isel(x=slice(l, m), y=slice(450, 600)).plot.contourf(ax=axs[ax_idx, 2])
print(i,j)
I would be so thankful if someone would be able to help me with this. I am creating a graph in matplotib however I would to love to split up the 14 lines created from the while loop into the x and y values of P, so instead of plt.plot(t,P) it would be plt.plot(t,((P[1])[0]))) and
plt.plot(t,((P[1])[1]))). I would love if someone could help me very quick, it should be easy but i am just getting errors with the arrays
`
#Altering Alpha in Tumor Cells vs PACCs
#What is alpha? α = Rate of conversion of cancer cells to PACCs
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from google.colab import files
value = -6
counter = -1
array = []
pac = []
while value <= 0:
def modelP(x,t):
P, C = x
λc = 0.0601
K = 2000
α = 1 * (10**value)
ν = 1 * (10**-6)
λp = 0.1
γ = 2
#returning odes
dPdt = ((λp))*P*(1-(C+(γ*P))/K)+ (α*C)
dCdt = ((λc)*C)*(1-(C+(γ*P))/K)-(α*C) + (ν***P)
return dPdt, dCdt
#initial
C0= 256
P0 = 0
Pinit = [P0,C0]
#time points
t = np.linspace(0,730)
#solve odes
P = odeint(modelP,Pinit,t)
plt.plot(t,P)
value += 1
#plot results
plt.xlabel('Time [days]')
plt.ylabel('Number of PACCs')
plt.show()
`
You can use subplots() to create two subplots and then plot the individual line into the plot you need. To do this, firstly add the subplots at the start (before the while loop) by adding this line...
fig, ax = plt.subplots(2,1) ## Plot will 2 rows, 1 column... change if required
Then... within the while loop, replace the plotting line...
plt.plot(t,P)
with (do take care of the space so that the lines are within while loop)
if value < -3: ## I am using value = -3 as the point of split, change as needed
ax[0].plot(t,P)#, ax=ax[0]) ## Add to first plot
else:
ax[1].plot(t,P)#,ax=ax[1]) ## Add to second plot
This will give a plot like this.
I tried to follow the Altair example of "Text over a Heatmap" but came across some problems.
My dataset consists of two indexes (N, Z) and a value column color.
I would like to set the origin at the bottom-left side.
How to display the heatmap with text in a script?
Is it possible to put labels (N, Z) in each pixel?
Below attached the part of the code.
def chart_altair(self):
import altair as alt
data = self.df.dropna().reset_index(name='color')
# Configure common options
base = alt.Chart(data).encode(
alt.X('N:O'),
alt.Y('Z:O'),
)
# Configure heatmap
heatmap = base.mark_rect().encode(
color=alt.Color(
'color:Q',
scale=alt.Scale(scheme='viridis'),
legend=alt.Legend()
)
)
text = base.mark_text(baseline='middle').encode(
text='color:Q'
)
I pasted below a few rows of my dataset which consists of two indexses Z, N, and a value column color (represents actually a atomic mass table). The "heatmap" should be similar to the chart of nuclei, with the neutron number increase to the right x-axis, and the proton number increases upwards in the y-axis. However, the proton number increases in the opposite direction (in the negative y-axis).
Z N color
0 1 8.07
1 0 7.29
1 1 13.14
1 2 14.95
2 1 14.93
1 3 24.62
2 2 2.42
3 3 14.09
4 2 18.38
2 5 26.07
3 4 14.91
4 3 15.77
5 2 27.68
Here is an example where I concatenate the two labels using transform_calculate. You could also do this by creating the label column in pandas instead.
import altair as alt
import numpy as np
import pandas as pd
# Compute x^2 + y^2 across a 2D grid
x, y = np.meshgrid(range(-5, 5), range(-5, 5))
z = x ** 2 + y ** 2
# Convert this grid to columnar data expected by Altair
source = pd.DataFrame({'x': x.ravel(),
'y': y.ravel(),
'z': z.ravel()})
heatmap = alt.Chart(source).mark_rect().encode(
x='x:O',
y='y:O',
color='z:Q'
)
heatmap + heatmap.mark_text().transform_calculate(label = '"" + datum.x + datum.y').encode(
text='label:N',
color=alt.value('black'))
I have a Dataframe =
from collections import OrderedDict
dico = OrderedDict({"Cisco" :54496.923851069776,
"Citrix" :75164.2973859488,
"Datacore/veritas/docker/quest" :7138.499540816414,
"Dell / EMC" : 34836.42983441935,
"HPE": 40265.33070005489,
"IBM Hard Ware / IBM services" : 220724.89293359307,
"Microsoft cloud" : 3159.7624999999994,
"Netapp":48898.21721115539,
"Nutanix / Lenovo DCG":38761.815197677075,
"Oracle/Microfocus":100877.21884162886,
"Other brands":13825.151033348895,
"VM Ware":21267.66907692287,
"Veeam / Redhat":5006.715599405339})
That I can plot :
df = pd.DataFrame(list(dico.values()))
df.index = dico.keys()
ax = df.sort(0).plot.barh()
but I want to format the xtick labels :
ax = df.sort_values(0).plot.barh()
new_labels = [str(pow(10,i-1))+"€" if i>0 else str(i) for i, tick_label in enumerate(ax.get_xticklabels())]
print(new_labels)
ax.set_xticklabels(new_labels)
Giving :
['0', '1€', '10€', '100€', '1000€', '10000€']
[]2
Why don't I get 20 000 in the list of the new labels ?
Why the 10 000 it self is not displayed ?
You don't get 20000 because you are creating powers of 10 as pow(10,i-1). It is mathematically not possibly from this equation. Moreover, 10000 is not displayed because you just use ax.set_xticklabels to reset the labels of the already existing xticks. Since you have only 5 major ticks in your first plot, you only create 5 labels as 0, 1, 10, 100, 1000 as per your definition.
To get what you want, just replace the last three lines of your code (after plotting) by:
locs = ax.get_xticks()
labels = [ '{}{}'.format(int(i), '\u20ac') for i in locs]
ax.set_xticklabels(labels)
Output
How can I create a mesh with refinement, lets say x and y go from 0 to 1 and between 0.4 and 0.6 in both directions I want the points to be closer.
I have been reading about numpy.logspace, but it doesnt allow much freedom.
Any ideas?
There isn't one specific command with this functionality, but you can build arrays up with numpy.concatenate this way:
import numpy
start = 0
end = 1
bigstep = 0.1
refinedstart = 0.4
refinedend = 0.6
smallstep = 0.01
x = numpy.concatenate([numpy.arange(start, refinedstart, bigstep),
numpy.arange(refinedstart, refinedend, smallstep),
numpy.arange(refinedend, end, bigstep)])
It depends on how you want to "squash" the middle values. But say you want to do it quadratically, using an 11-by-11 grid spanning from -10 to 10 on each axis:
a = np.linspace(-np.sqrt(10), np.sqrt(10), 11)
b = np.sign(a)*a**2
x, y = np.meshgrid(b, b)
To see what this grid looks like:
import matplotlib.pyplot as plt
plt.plot(x.flatten(), y.flatten(), '*')
plt.show()