Multiple histograms with logarithmic x scale - python

This is a combination of this thread on multiple histograms, and this thread on a logarithmic scales.
I am trying to have two (or more) histograms in a plot with a logarithmic x-scale, using this code: (with some external lists)
import numpy
import matplotlib.pyplot as plt
plt.hist([capacity_list, capacity_list2], np.logspace(-1,4,11))
plt.gca().set_xscale("log")
plt.show()
It works in principle; my only problem is that the logarithmic scale also seems to affect the bin width of the histograms and so one if them always has shorter bins, which doesn't look nice:
Does anybody know how to fix that?

Related

How do I use matplotlib to create a bar chart of a very large dataset?

The data I am working with is an array 27,000 elements long which is a histogram of a few million data points but what I have is the histogram and I need to plot it in my program, preferably with vertical bars.
I've tried using the 'bar' function in matplotlib but this takes a minute or two to plot whereas using just regular plot (with just points on the chart) is almost immediate but obviously does not achieve the effect I want (i.e. bars). I'm not sure why the bar function is so much slower so I was wondering if there was a more effective way to plot a histogram with vertical bars using matplotlib?
I've looked at the hist function with matplotlib but it's purpose to my understanding is to take data, make a histogram, and then plot it but I already have a histogram so I don't believe it works for my case. I greatly appreciate any help!
Here's a reference to the hist function documentation, maybe I missed something.
https://matplotlib.org/3.2.0/api/_as_gen/matplotlib.pyplot.hist.html
Thanks in advance! Let me know if you would like an example of the code I am working with but it is just your most generic my_axes.plot(my_data) or my_axes.bar(my_data) so I'm not sure how helpful it would be.
I've taken a look at this as well now: https://gist.github.com/pierdom/d639a1d3b8934ee31db8b2ab9997ae92.
This also works but has the same time issue as using bar so I suppose this is just an issue with rendering a lot of vertical bars? (though I still wonder why rendering 27000 points happens so quickly)
Apparently, this is a known and discussed limitation of the bar graph as it is currently implemented. See this issue and this discussion. Though there are questions about it's usefulness, in my particular case I have a toolbar across the top that allows the user to zoom in and move around the data set (which is very practical method for my use case).
However, a great alternative does exist in the form of stairs. Simply use fill and you have an effective bar graph, that is much more performant.
import matplotlib.pyplot as plt
import random
bins = range(27001) # Note that bins needs to be one greater then heights
heights = [random.randint(0, i) for i in range(27000)]
ax = plt.gca()
ax.stairs(heights, bins, fill=True)
plt.show()
matplotlib's bar should be pretty fast to execute so I'm guessing you're passing all the data points to it (although you mention you have "histogram data", so if you can provide more details on the format, that'd help).
bar takes the x positions for the bars and the heights, so if you want the bar function to produce a histogram you need to bin and count.
This will produce something similar to matplotlib's hist:
import matplotlib.pyplot as plt
bins = [0, 1, 2, 3]
heights = [1, 2, 3, 4]
ax = plt.gca()
ax.bar(bins, heights, align='center', width=1)

python multiple stacked plots along y axis

I have a binned data of an x-axis n-length vector and 3 y-axis n-length vector for 3 different histograms on the same x-axis.
Now I want this kind of stacked bar plot or any thing similar as below.
The nearest I have found is Qtiplot (which is not python). It can generate exactly this kind of histogram plots. But it computes the histogram by itself and requires the actual data samples which are not present in my case (I only have the histogram itself).
Please note that I don't know python very well. So I don't have a clue from where I shall start, neither I am really in a mood to learn programming in python. I need this only to make a nice vector-graphics plot for my research thesis.
I have tagged python as I think python is the most obvious language. In case someone knows any better solution other than in python (but not Matlab, I cannot install that huge pile), I will thankfully add the proper tag.
Thanks in advance for any help.
use matplotlib package in python
import matplotlib.pyplot as plt
apple_weight=[3,3,3,10,10,1,1,1,4,4,4,4,7,7,7]
banana_weight=[3,3,3,10,10,1,1,1,4,4,4,4,7,7,7]
mango_weight=[3,3,3,10,10,1,1,1,4,4,4,4,7,7,7]
fig=plt.figure()
ax1=fig.add_subplot(311)
ax2=fig.add_subplot(312)
ax3=fig.add_subplot(313)
ax1.hist(apple_weight)
ax2.hist(banana_weight)
ax3.hist(mango_weight)
plt.show()
import matplotlib.pyplot as plt
apple_weight=[3,3,3,10,10,1,1,1,4,4,4,4,7,7,7]
banana_weight=[3,3,3,10,10,1,1,1,4,4,4,4,7,7,7]
mango_weight=[3,3,3,10,10,1,1,1,4,4,4,4,7,7,7]
fig=plt.figure()
ax1=fig.add_subplot(111)
ax2=ax1.twinx()
#only two y axes so the third list just add to either
ax1.hist(apple_weight)
ax2.hist(banana_weight)
ax1.hist(mango_weight)
plt.show()

Python Heatmaps (Basic and Complex)

What's the best way to do a heatmap in python (2.7)? I've found the heatmap.py module, and I was wondering if people have any advice on using it, or if there are other packages that do a good job.
I'm dealing with pretty basic data, like xy = np.random.rand(1000,2) superimposed on an image.
Although there's another thing I want to try, which is doing a heatmap that's scaled to a different heatmap. E.g., I have
attempts = np.random.rand(5000,2)
successes = np.random.rand(500,2)
And I want a heatmap of the successes relative to the density of the attempts. Is this possible?
Seaborn is a pretty widely-used library for making nice-looking plots, and has a heatmap function. Seaborn uses matplotlib under the hood.
import numpy as np
import seaborn as sns
xy = np.random.rand(1000,2)
sns.heatmap(xy, yticklabels=100)
Regarding your second question, I'm not sure what you mean. But my advice would be to create a numpy array or pandas dataframe of "successes [scaled] relative to the density of the attempts", however you mean that, and then pass that scaled array or dataframe to sns.heatmap
You can plot very complex heatmap using python package PyComplexHeatmap: https://github.com/DingWB/PyComplexHeatmap
https://github.com/DingWB/PyComplexHeatmap/blob/main/examples.ipynb
The most basic heatmap you can get is an image plot:
import matplotlib.pyplot as plt
import numpy as np
xy = np.random.rand(100,2)
plt.imshow(xy, aspect="auto")
plt.colorbar()
plt.show()
Note that using more points than you have pixels to show the heatmap might not make too much sense.
There are of course also different methods to draw a heatmaps and you may go through the matplotlib example gallery and see which plot appeals most to you.

seaborn plots the same size?

seaborn has a conveninent keyword named size=, that aims to make the plots a certain size. However, the plots significantly differ in size depending on the xy-ticks and the axis labels. What is the best way to generate plots with exactly the same dimensions regardless of ticks and axis labels?
Seaborn sizing options vary by the plot type, which can be a bit confusing, so this is a useful universal approach.
First run this: import matplotlib as plt
Then add the line plt.figure(figsize=(9, 9)) in the notebook cells for each of the plots. You can adjust the integer values as you see fit.

Python, matplotlib: how to set tick label values to their logarithmic values

I have some data that I plot on a semi-log plot (log-lin style, with a logarithmic scale on the y-axis). Is there a way to change the y-axis tick labels from their actual values to their logarithmic values?
As an example, consider the following code:
import matplotlib.pyplot as plt
import numpy as np
x=np.array([1,2,3,4,5])
def f(x):
return 10**(x-1)
plt.plot(x,f(x))
plt.yscale(u'log')
plt.show()
Which produces the following plot:
(Sorry it is kind of big, I do not know how to make it smaller, feel free to edit to help out with that).
In this plot the tick labels are shown as 10^0, 10^1, 10^2, etc.; however I would like them to display as their logarithmic values: 0, 1, 2, etc.
I realize I could go back and change plt.plot(x,f(x)) to plt.plot(x,np.log10(f(x))) and then make the y-axis linear again instead of logarithmic but I want to know if there is anyway matplotlib can just change the y-axis tick values themselves without me having to put np.log10() in all my plt.plot()'s. My reason for this is two-fold: I have many plt.plot() lines in my code and would rather not go back and have to change it for all of them, and then I wouldn't have logarithmically spaced minor ticks (although I'm sure there's some way to change that even with a linear axis).
EDIT: I am aware of this question which has some similarities to mine but is not the same. The person in that question wants to change the tick labels from scientific form to "normal" decimal form. I want to change my tick labels from scientific form to the logarithmic (base 10) value of the number. I am sure the answer will be similar to the one I linked but it is not obvious to me how to do it. In fact, I looked at that question before posting mine but still decided to post mine because I did not know how to apply it to my problem. Perhaps to experienced programmers it is obvious how to apply the methods of the question I linked to my situation but it isn't obvious to me so please step me through it.
If you could show me a code sample (by copying my code sample and putting in the necessary lines) how this works I would much appreciate it.
You can use a custom formatter, for example:
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
import numpy as np
import math
x=np.array([1,2,3,4,5])
def f(x):
return 10**(x-1)
plt.plot(x,f(x))
plt.yscale(u'log')
#SET CUSTORM TICK FORMATTING
plt.gca().yaxis.set_major_formatter(FuncFormatter(lambda x,y: '{}'.format(math.log(x, 10))))
plt.show()

Categories

Resources