So I'm trying to expand on this code, which is the only code I could find to display Markov Chains as a diagram of nodes and arrows. Specifically, I needed it to work for more than 4 states and I have been editing it to suit my needs. Since right now I want to use it for n=7 where any two states have a transition probability, it can get very messy with all the arrows, which is why I wanted to use the parameter alpha in the matplotlib.patches.FancyArrow() function.
However, I have tested it and while I get an error if I give it a value outside of the interval [0,1], any value in that interval seems to do nothing, whether it's 0.001 or 0.999. The documentation isn't great, it includes alpha as a possible kwarg but the description just says "unknown". In the "Arrow Guide" there is no mention of this parameter at all. So does anyone know how I can make my arrows more transparent?
Here is a code example where you can change alpha and see no change:
import matplotlib.patches as mpatches
from matplotlib.collections import PatchCollection
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(20,20))
plt.xlim(-10,10)
plt.ylim(-10,10)
coords = [(5,7),(3,-6),(0,5),(-2,-4)]
for (x,y) in coords:
arrow = mpatches.FancyArrow(0,0,x,y,
width = .2,
head_width = 1,
length_includes_head = True,
alpha = 0.1)
p = PatchCollection(
[arrow],
edgecolor = '#a3a3a3',
facecolor = '#a3a3a3'
)
ax.add_collection(p)
plt.axis("off")
plt.show()
Ok I just realized my mistake (well sort of, I don't really understand the mechanics of why this works). I have to pass the alpha keyword in the PatchCollection() function. Then it works. Thank you to myself for figuring this out lol
Related
I saw that matplotlib's pyplot.scatter() has an 'alpha' parameter that can be used to set the transparency of points. The pyplot.pie() doesn't have a similar parameter however. How can I set the transparency of certain wedges?
I found the answer while writing up this question and figured I'd post the solution for anyone who wants to know.
To set a wedge to be transparent:
import matplotlib.pyplot as plt
x = [1,2,3,0.4,5]
alpha = 0.5
which_wedge = 4
n = plt.pie(x)
n[0][which_wedge].set_alpha(alpha)
If you want to only display a single wedge, use a loop:
for i in range(len(n[0])):
n[0][i].set_alpha(0.0)
n[0][which_wedge].set_alpha(1.0)
Hope this helps someone! It can probably be used for pyplot.bar() too to hide certain bars.
alpha can be passed to plt.pie directly using the wedgeprop arg (credit #Seth):
import matplotlib.pyplot as plt
plt.pie(x, wedgeprops={"alpha": 0.5})
I have a function that produces triangles and quadrilaterals (called 'trisq') in red or green, resp. My goal is to make an arrangement of these shapes on the same plot by running a loop over my drawing function.
I can draw multiple shapes and call plt.show() on it which works fine but after that I won't be able to add more shapes as it gives me a blank output.
I think my issue is that I don't know how to control subplot command. Please see my inline comment in the code for how it goes wrong. What would be the cleanest way to do this? Thanks!
(Btw, this is my first time posting here. I think my question is basic but I hope that at least I've posed it in a clear way).
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
fig, ax = plt.subplots()
def trisq(points):
inf = 20
plt.xlim(-inf, inf)
plt.ylim(-inf, inf)
plt.gca().set_aspect('equal', adjustable='box')
ver = np.array(points)
polygon = Polygon(ver, True)
patches = []
patches.append(polygon)
if len(points) == 3:
color = 'red'
elif len(points) == 4:
color = 'green'
p = PatchCollection(patches, color = color,cmap=matplotlib.cm.jet, alpha=0.4)
ax.add_collection(p)
trisq([(4,18),(6,16),(5,-1),(-5,9)]
trisq([(4,-8),(1,7),(15,9)])
# this works as expected
plt.show()
trisq([(4,8),(12,3),(0,0),(1,9)])
# but this one returns a blank plot
plt.show()
Update:
My concrete question is: how do I show a graph, then add more elements to it and show it again in the above context and possibly repeat inside a loop? Apparently, plt.show() can only be called once and not in an ongoing manner.
Plt.show() shows the active figures. After your first call to plt.show() there is no active figure any more.
Unfortunately the question is not clear about what the actual goal is.
You may call plt.show only once at the end. You may also create a new figure in between.
Make sure to add the collection inside the trisq function.
I'm trying to add a color bar in a graph, but I don't understand how it works. The problem is that I make my own colorcode by:
x = np.arange(11)
ys = [i+x+(i*x)**2 for i in range(11)]
colors = cm.rainbow(np.linspace(0, 1, len(ys)))
and colors[i] will give me a new color. Then I use (homemade) functions to select the relevant data and plot them accordingly. This would look something like this:
function(x,y,concentration,temperature,1,37,colors[0])
function(x,y,concentration,temperature,2,37,colors[1])
# etc
Now I want to add the colors in a color bar, with labels I can change. How do I do this?
I have seen several examples where you plot all the data as one array, with automated color bars, but here I plot the data one by one (by using functions to select the relevant data).
EDIT:
function(x,y,concentration,temperature,1,37,colors[0]) looks like this (simplified):
def function(x,y,c,T,condition1,condition2,colors):
import matplotlib.pyplot as plt
i=0
for element in c:
if element == condition1:
if T[i]==condition2:
plt.plot(x,y,color=colors,linewidth=2)
i=i+1
return
Drawing a colorbar aside a line plot
Please map my solution (I used simply 11 sines of different amplitudes) to your problem (as I told you, it is difficult to understand from what you wrote in your Q).
import matplotlib
import numpy as np
from matplotlib import pyplot as plt
# an array of parameters, each of our curves depend on a specific
# value of parameters
parameters = np.linspace(0,10,11)
# norm is a class which, when called, can normalize data into the
# [0.0, 1.0] interval.
norm = matplotlib.colors.Normalize(
vmin=np.min(parameters),
vmax=np.max(parameters))
# choose a colormap
c_m = matplotlib.cm.cool
# create a ScalarMappable and initialize a data structure
s_m = matplotlib.cm.ScalarMappable(cmap=c_m, norm=norm)
s_m.set_array([])
# plotting 11 sines of varying amplitudes, the colors are chosen
# calling the ScalarMappable that was initialised with c_m and norm
x = np.linspace(0,np.pi,31)
for parameter in parameters:
plt.plot(x,
parameter*np.sin(x),
color=s_m.to_rgba(parameter))
# having plotted the 11 curves we plot the colorbar, using again our
# ScalarMappable
plt.colorbar(s_m)
# That's all, folks
plt.show()
Example
Acknowledgements
A similar problem, about a scatter plot
Update — April 14, 2021
With recent versions of Matplotlib, the statement s_m.set_array([]) is not required any more. On the other hand, it does no harm.
When plotting, in place of color=s_m.to_rgba(parameter) one may want to use the (slightly) more obvious color=c_m(norm(parameter)).
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
Default matplotlib graphs look really unattractive and even unprofessional. I tried out couple of packages include seaborn as well as prettyplotlib but both of these just barely improves the styles.
So far I've gotten to following using seaborn package:
Below is the appearance I'm looking for which is far cry from above:
Notice the following niceness in the 2nd example:
Area under the graph is filled with much more eye pleasing color.
The graph line is thinker and nicely stands out.
Axis lines are thinker and again nicely stands out.
Area under the curve is transparent.
X-Axis tick marks are more denser.
My questions are: Do you recognize above as some kind of popular theme or style that I can quickly use in matplotlib? Or if I can use from some package? Failing that, is there anyway to set this style as my global preference? Failing that, is it even possible to do this in matlibplot?
Thanks!
This is really a matter of taste, and also a matter of target audience. matplotlib tries to produce clear illustrations for scientific purposes. This is - necessarily - a compromise, and the illustrations are not something you would print in a magazine or show in an advertisement.
There are some good news and some bad news about matplotlib in this sense.
Bad news:
There is no single magical command or package which would create beautiful plots with matplotlib.
Good news:
There are simple ways to change the default settings, see: http://matplotlib.org/users/customizing.html
The object model enables the user to change almost everything and introduce complex new features.
The source code is available, and even it can be changed quite easily by the user.
In my opinion the most difficult thing is to decide what you want. Then doing what you want is easier, even though there is a steepish learning curve in the beginning.
Just as an example:
import numpy as np
import matplotlib.pyplot as plt
# create some fictive access data by hour
xdata = np.arange(25)
ydata = np.random.randint(10, 20, 25)
ydata[24] = ydata[0]
# let us make a simple graph
fig = plt.figure(figsize=[7,5])
ax = plt.subplot(111)
l = ax.fill_between(xdata, ydata)
# set the basic properties
ax.set_xlabel('Time of posting (US EST)')
ax.set_ylabel('Percentage of Frontpaged Submissions')
ax.set_title('Likelihood of Reaching the Frontpage')
# set the limits
ax.set_xlim(0, 24)
ax.set_ylim(6, 24)
# set the grid on
ax.grid('on')
(Just a comment: The X-axis limits in the original image do not take the cyclicity of the data into account.)
This will give us something like this:
It is easy to understand that we need to do a lot of changes in order to be able to show this to a less-engineering-minded audience. At least:
make the fill transparent and less offensive in colour
make the line thicker
change the line colour
add more ticks to the X axis
change the fonts of the titles
# change the fill into a blueish color with opacity .3
l.set_facecolors([[.5,.5,.8,.3]])
# change the edge color (bluish and transparentish) and thickness
l.set_edgecolors([[0, 0, .5, .3]])
l.set_linewidths([3])
# add more ticks
ax.set_xticks(np.arange(25))
# remove tick marks
ax.xaxis.set_tick_params(size=0)
ax.yaxis.set_tick_params(size=0)
# change the color of the top and right spines to opaque gray
ax.spines['right'].set_color((.8,.8,.8))
ax.spines['top'].set_color((.8,.8,.8))
# tweak the axis labels
xlab = ax.xaxis.get_label()
ylab = ax.yaxis.get_label()
xlab.set_style('italic')
xlab.set_size(10)
ylab.set_style('italic')
ylab.set_size(10)
# tweak the title
ttl = ax.title
ttl.set_weight('bold')
Now we have:
This is not exactly as in the question, but everything can be tuned towards that direction. Many of the things set here can be set as defaults for matplotlib. Maybe this gives an idea of how to change things in the plots.
To get closer to the style you prefer, you could use the whitegrid style in seaborn. As the other answers have noted, you control the transparency of the fill with the alpha parameter to fill_between.
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
sns.set_style("whitegrid")
blue, = sns.color_palette("muted", 1)
x = np.arange(23)
y = np.random.randint(8, 20, 23)
fig, ax = plt.subplots()
ax.plot(x, y, color=blue, lw=3)
ax.fill_between(x, 0, y, alpha=.3)
ax.set(xlim=(0, len(x) - 1), ylim=(0, None), xticks=x)
More information on seaborn styles can be found in the docs.
matplotlib is almost infinitely flexible so you can do almost anything with it and if it doesn't exist you can write it yourself! Obviously the defaults are bland, this is because everyone has there own idea of what is "nice" so it is pointless to impose a predefined style.
Here is a really simple example that addresses 4 of your points.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
x = np.linspace(-10, 10, 1000)
y = 1+np.sinc(x)
ax = plt.subplot(111)
ax.plot(x, y, lw=2)
ax.fill_between(x, 0, y, alpha=0.2)
ax.grid()
majorLocator = MultipleLocator(1)
ax.xaxis.set_major_locator(majorLocator)
plt.show()
If your want to set defaults so all your plots look the same then you should generate a custom matplotlibrc file or use style. A useful guide is here. To view a list of all the available options just call print plt.rcParams from an interactive terminal.
Some of the other features such as filling will need to be done on a per plot basis. You can standardise this across your work by creating a function which adds the fill between given some input such as the axis instance and data.
You can customize plots style as follow:
import numpy as np
import matplotlib.pyplot as plt
plt.use_style('ggplot') # customize your plots style
x = np.linspace(0,2*np.pi,100)
y = np.sin(x)
plt.fill_between(x,y)
plt.show()
I am working on using Matplotlib to produce plots of implicit equations (eg. y^x=x^y). With many thanks to the help I have already received I have got quite far with it. I have used a contour line to produce the plot. My remaining problem is with formatting the contour line eg width, color and especially zorder, where the contour appears behind my gridlines. These work fine when plotting a standard function of course.
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
import numpy as np
fig = plt.figure(1)
ax = fig.add_subplot(111)
# set up axis
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
# setup x and y ranges and precision
x = np.arange(-0.5,5.5,0.01)
y = np.arange(-0.5,5.5,0.01)
# draw a curve
line, = ax.plot(x, x**2,zorder=100,linewidth=3,color='red')
# draw a contour
X,Y=np.meshgrid(x,y)
F=X**Y
G=Y**X
ax.contour(X,Y,(F-G),[0],zorder=100,linewidth=3,color='green')
#set bounds
ax.set_xbound(-1,7)
ax.set_ybound(-1,7)
#add gridlines
ax.xaxis.set_minor_locator(MultipleLocator(0.2))
ax.yaxis.set_minor_locator(MultipleLocator(0.2))
ax.xaxis.grid(True,'minor',linestyle='-',color='0.8')
ax.yaxis.grid(True,'minor',linestyle='-',color='0.8')
plt.show()
This is rather hackish but...
Apparently in the current release Matplotlib does not support zorder on contours. This support, however, was recently added to the trunk.
So, the right way to do this is either to wait for the 1.0 release or just go ahead and re-install from trunk.
Now, here's the hackish part. I did a quick test and if I changed line 618 in
python/site-packages/matplotlib/contour.py
to add a zorder into the collections.LineCollection call, it fixes your specific problem.
col = collections.LineCollection(nlist,
linewidths = width,
linestyle = lstyle,
alpha=self.alpha,zorder=100)
Not the right way to do things, but might just work in a pinch.
Also off-topic, if you accept some responses to your previous questions, you probably get quicker help around here. People love those rep points :)