0

I need to create a plot using matplotlib.pyplotthat shows distance between Earth and Mars over time. In addition to that some months e.g. March to August should be shown in a different color than the other months. Data is provided from an array containing the date, distance and also a flag indicating whether the date is in the March to August-span or not.

The array containing the whole data is called master_array. First column containing the date, second the distance; seventh the s/w-flag. ('s' for summer, 'w' for winter).

I tried to make use of the fact that pyplot.plot switches color for every single .plot command in a way that I first plot the winter months and in a second plot the summer months.

import numpy as np
from matplotlib import pyplot as plt

def md_plot2(dt64=np.array, md=np.array):
    """Erzeugt Plot der Marsdistanz (y-Achse) zur Zeit (x-Achse)."""
    plt.style.use('seaborn-whitegrid')

    y, m, d = dt64.astype(int) // np.c_[[10000, 100, 1]] % np.c_[[10000, 100, 100]]
    dt64 = y.astype('U4').astype('M8') + (m-1).astype('m8[M]') + (d-1).astype('m8[D]')

    wFilter = np.argwhere(master_array[:,6] == 0)
    sFilter = np.argwhere(master_array[:,6] == 1)

    plt.plot(dt64[wFilter], md[wFilter], label='Halbjahr der fallenden \nTemperaturen')
    plt.plot(dt64[sFilter], md[sFilter], label='Halbjahr der steigenden \nTemperaturen')

    plt.xlabel("Zeit in Jahren\n")
    plt.xticks(rotation = 45)
    plt.ylabel("Marsdistanz in AE\n(1 AE = 149.597.870,7 km)")
    plt.legend(loc='upper right', frameon=True)

plt.figure('global betrachtet...') # diesen Block ggf. auskommentieren
#plt.style.use('seaborn-whitegrid')
md_plot2(master_array[:,0], master_array[:,1]) # Graph

plt.show()
#plt.close()

Problem now is that between the last point of a summer period and first point of the following summer period the plot for summers shows a line where the other plot (for winters) shows the correct data of the winter period that lays between those two summers. The data is containing many data points what will lead to many segments of those two colors. How can I stop the plot to draw a line, when the next data point is more that one day in the future? Is there maybe another method of pyplot for this task?

As I wrote a lot of code in the script where this belongs without using pandas I would be very happy to find a solution to this problem not using pandas as I try to avoid it because I don't want to bloat my script when there is a way to get the task done by using the modules I am already using. I also read it would decrease the speed here.

zorrolo
  • 117
  • 9
  • 2
    Kudos for your philosophy on not using Pandas when you don't need it – after all, it probably wouldn't even help in this case! – AKX Apr 01 '19 at 10:22
  • You need to 'cut' your data into parts, e.g. plot each summer separately with the same colour and then plot each winter separately as well. This way you will skip the connecting lines. Another solution would be to set all winter values to `np.nan`, then draw the summer line for all summers, then do the reverse for the winters. – Thomas Kühn Apr 01 '19 at 10:27
  • 1
    @AKX Thanks! I'm adding this disclaimer now, because everyone during this project suggested to use pandas and now this is the last problem (hopefully) to solve and it works completly without any line of pandas ¯\\_(ツ)_/¯ – zorrolo Apr 01 '19 at 10:28
  • It looks like [this question](https://stackoverflow.com/questions/44642966/how-to-plot-multi-color-line-if-x-axis-is-date-time-index-of-pandas) would be what you're after. Of course it does use pandas, because that makes it a bit simpler. I do not entirely understand your custom datetime format used here, so if you need further help, maybe you want to explain what the input `dt64` is, and how that relates to dates. – ImportanceOfBeingErnest Apr 01 '19 at 12:56
  • @ImportanceOfBeingErnest The `master_array` provides dates in form of a String like `18930201` for the first of February in 1893. To display the date in the plots in a convenient way I need to provide the dates as datetime (or datetime64 which is the equivalent to store them as numpy array) to matplotlib. In the end `dt64`is an numpy array that contains aprox. 40k items like `numpy.datetime('1893-02-01')` – zorrolo Apr 01 '19 at 13:10
  • If `dt64` is of type `"datetime64[D]"`, you can directly apply the linked solution. maybe a note for the future: If you store dates in a string format like `"2018-04-01"` instead of `"20180401"`, numpy can parse it to datetime directly (`np.array(["1893-02-01", "2018-04-01"]).astype("datetime64[D]")`) – ImportanceOfBeingErnest Apr 01 '19 at 13:29
  • @ImportanceOfBeingErnest The data is not stored by me. it's provided in this format. Although the linked solution looks promising I don't see how to customize it to make it fit to my question. Could you please give me a more detailed answer? Second question is: is it also possible to get it working without using pandas? – zorrolo Apr 01 '19 at 16:52
  • Did you try anything? Like remove pandas from that example, and use your `dt64` array instead? If you can provide a runnable code with at least an attempt to solve this according to the example, I can help you modify it to your needs. – ImportanceOfBeingErnest Apr 01 '19 at 21:17
  • Of course I tried! But I failed all along. Never the less I will post my (not working) code here as soon as I have time, if that means I can get some help! – zorrolo Apr 02 '19 at 07:27
  • @ImportanceOfBeingErnest [here](https://pastebin.com/Tz4Aigss) is what I tried. Unfortunately I am not familiar with pandas at all as I tried to avoid it. So I don't understand some important commands and therefore don't know how to replace them with the working equivalent. Beside this at first I tried to make the code provided by you working with my data despite it uses pandas. But it only produces an empty plot. – zorrolo Apr 02 '19 at 07:46
  • 1
    I updated [the original question](https://stackoverflow.com/questions/44642966/how-to-plot-multi-color-line-if-x-axis-is-date-time-index-of-pandas)'s answer with a new piece of code that does not use pandas. – ImportanceOfBeingErnest Apr 02 '19 at 11:19
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/191092/discussion-between-zorrolo-and-importanceofbeingernest). – zorrolo Apr 02 '19 at 12:41

2 Answers2

1

The multicolored_line example looks like what you're going for.

Also see this article for more information about the colormap system in Matplotlib.

AKX
  • 152,115
  • 15
  • 115
  • 172
  • This looks more like a comment to me than an actual answer. Maybe this turns out to be a duplicate in the end? – Thomas Kühn Apr 01 '19 at 10:23
  • I know it's a link-only-ish answer, but I didn't feel it would be worth the while to copy in the examples and diagrams from the linked articles. – AKX Apr 01 '19 at 10:26
  • @AKX could you explain the following section of [multicolored_line](https://matplotlib.org/examples/pylab_examples/multicolored_line.html) for my case? ```points = np.array([x, y]).T.reshape(-1, 1, 2) segments = np.concatenate([points[:-1], points[1:]], axis=1) ``` I don't know how to customize these section for my code. – zorrolo Apr 01 '19 at 11:54
  • more specified: I don't know how to customize the line `segments = np.concatenate([points[:-1], points[1:]], axis=1)` in my case... – zorrolo Apr 01 '19 at 12:19
0

Here is a simple one, just "overwrite" part where you want another color:

import matplotlib.pyplot as plt
%matplotlib inline
x = list(range(10))
y = [ 2*i for i in x]
x_1 = x[4:7]
y_1 = y[4:7]
plt.plot(x,y)
plt.plot(x_1,y_1)
plt.show()
Christian Sloper
  • 7,440
  • 3
  • 15
  • 28
  • Nice idea but not handy if you have many segments. Moreover it won't cover the unwanted lines from the code in the question. – zorrolo Apr 01 '19 at 11:31