How to plot two y-axes in Excel 2003 with Python - python

I'm trying to plot two data series with different y-axes in the same plot in Excel 2003 using Python and win32com.client. I started with VBA to try to get the code I needed. Here's what it looks like so far:
chart = xlApp.Charts.Add()
# This part successfully creates the first series I want
series = chart.SeriesCollection(1)
series.XValues = xlSheet.Range("L13:L200")
series.Values = xlSheet.Range("M13:M200")
# This is what I added to try to plot the second series
series.AxisGroup = xlPrimary
series2 = chart.SeriesCollection(2)
series2.XValues = xlSheet.Range("L13:L200")
series2.Values = xlSheet.Range("N13:N200")
series2.AxisGroup = xlSecondary
# The rest is for formatting it the way I want, but it doesn't work now that I'm
# to plot the second series. (It stops working when I add the last five lines of code).
chart.Legend.Delete() # Delete legend; MUST BE DONE BEFORE CHART IS MOVED
series.Name = file
chart.Location(2, xlSheet.Name) # Copy chart to active worksheet
chart = xlSheet.Shapes(1)
chart.Top = 51
chart.Left = 240
chart.Width = 500
chart.Height = 350
This plots the first series, but as noted in the comments, no longer adds the title, moves the chart, deletes the legend or resizes the chart. It does nothing with the second series. It is also not generating an error.

Related

PPTX Python - How to fix ValueError: chart data contains no categories for a LineChart?

I'm trying to replace data in an existing line chart in Python PPTX. Here's the code I'm using:
for chart in charts:
chart_data = CategoryChartData()
chart_index = list(charts).index(chart)
scenario_no = chart_index + 1
sc_df = wrk_df[wrk_df['Scenario No'] == scenario_no]
for category in sc_df['categories'].tolist():
chart_data.add_category(category)
chart_data.add_series('Volume', sc_df['Series 1'].tolist())
chart_data.add_series('Value', sc_df['Series 2'].tolist())
chart.replace_data(chart_data)
Basically there are several charts on the slide, through which the code iterates and replaces the data. The charts themselve have a numeric x axis and two series.
When I run this code I get the following error:
ValueError: chart data contains no categories
I've already tried converting the new categories into string, however, it doesn't work with any data type.
I'm also able to print original category labels in the existing chart, which means it does have categories.
I can't think of what's going wrong here. Does anyone have any solution for this or at least any knowledge of why this is happenning?
It turned out that the data being passed as categories was empty

How can I join the points of a plot whose data contains gaps?

I'm trying to join the points of a plot with at least 70 subplots, since it is not a scatter (because I can't use it since they are not series), I've tried marker = 'o-', but doesn't work. The data is in the format %mm-%yy, there are at least 6 different months (as a date column), and not for every column (Fund names) there exist any data in an specific month, however I want to join all the points from the same column even if they skipped any date.
I'm trying this, however it only joins the data that corresponds to following months.
df.plot(subplots = True, figsize = (20,20), layout = (14,5),legend=False,marker='o')

Legend on pandas plot of time series shows only "None"

data is a pandas dataframe with a date-time-index on entries with multiple attributes. One of these attributes is called STATUS. I tried to create a plot of the number of entries per day, broken down by the STATUS attribute.
My first attempt using pandas.plot:
for status in data["STATUS"].unique():
entries = data[data["STATUS"] == status]
entries.groupby(pandas.TimeGrouper("D")).size().plot(figsize=(16,4), legend=True)
The result:
How should I modify the code above so that the legend shows which status the curve belongs to?
Also, feel free to suggest a different approach to realizing such a visualization (group time series by time interval, count entries, and break down by attributes of the entries).
I believe that with below change to your code you will get what you want:
fig, ax = plt.subplots()
for status in data["STATUS"].unique():
entries = data[data["STATUS"] == status]
dfPlot = pandas.DataFrame(entries.groupby(pandas.TimeGrouper("D")).size())
dfPlot.columns=[status]
dfPlot.plot(ax=ax, figsize=(16,4), legend=True)
What happened is that the output for size function gives you a Series type with no name in its column. So creating a Dataframe from the Series and changing the column name does the trick.

Appending data sets to an OpenPyxl Chart using a For-Loop

In Python, I have the ability to add series data to my chart object to plot as a line graph.
I'm using the following lines:
overall_stats_sheet2 = current_book.worksheets[0]
overall_chart_sheet = current_book.worksheets[1]
chart_object = charts.LineChart()
for x in top_down_reference_points[0]:
chart_object.append(charts.Series(charts.Reference(overall_stats_sheet, (x,1), (x, overall_stats_sheet2.get_highest_column()+1)), title = 'Erasure Decodes'))
chart_object.drawing.top = 0
chart_object.drawing.left = 400
chart_object.drawing.width = 650
chart_object.drawing.height = 400
overall_chart_sheet.add_chart(chart_object)
top_down_reference_points[0] contains all of the row numbers that erasure decode exists on. In the example picture, the numbers are row 19 and row 39.
My for loop code currently iterates through those and appends them to the graph, but it creates a new legend label and line for each erasure-decode set. I want to combine all that data from the sheet and graph one line associated with all the erasure decode data. Is this possible?
It's not entirely clear from your code which cells you want in your chart and how. It may be as simple as creating a single series that refers to multiple cells. At the moment you're creating multiple series which is why you're seeing multiple items in the legend.
BTW. I strongly recommend you start using the 2.3 beta of openpyxl which has much better chart support.

How to get multiple legends from multiple pandas plots

I've got two dataframes (both indexed on time), and I'd like plot columns from both dataframes together on the same plot, with legend as if there were two columns in the same dataframe.
If I turn on legend with one column, it works fine, but if I try to do both, the 2nd one overwrites the first one.
import pandas as pd
# Use ERDDAP's built-in relative time functionality to get last 48 hours:
start='now-7days'
stop='now'
# URL for wind data
url='http://www.neracoos.org/erddap/tabledap/E01_met_all.csv?\
station,time,air_temperature,barometric_pressure,wind_gust,wind_speed,\
wind_direction,visibility\
&time>=%s&time<=%s' % (start,stop)
# load CSV data into Pandas
df_met = pd.read_csv(url,index_col='time',parse_dates=True,skiprows=[1]) # skip the units row
# URL for wave data
url='http://www.neracoos.org/erddap/tabledap/E01_accelerometer_all.csv?\
station,time,mooring_site_desc,significant_wave_height,dominant_wave_period&\
time>=%s&time<=%s' % (start,stop)
# Load the CSV data into Pandas
df_wave = pd.read_csv(url,index_col='time',parse_dates=True,skiprows=[1]) # skip the units row
plotting one works fine:
df_met['wind_speed'].plot(figsize=(12,4),legend=True);
but if I try to plot both, the first legend disappears:
df_met['wind_speed'].plot(figsize=(12,4),legend=True)
df_wave['significant_wave_height'].plot(secondary_y=True,legend=True);
Okay, thanks to the comment by unutbu pointing me to essentially the same question (which I searched for but didn't find), I just need to modify my plot command to:
df_met['wind_speed'].plot(figsize=(12,4))
df_wave['significant_wave_height'].plot(secondary_y=True);
ax = gca();
lines = ax.left_ax.get_lines() + ax.right_ax.get_lines()
ax.legend(lines, [l.get_label() for l in lines])
and now I get this, which is what I was looking for:
Well. Almost. It would be nice to get the (right) and (left) on the legend to make it clear which scale was for which line. #unutbu to the rescue again:
df_met['wind_speed'].plot(figsize=(12,4))
df_wave['significant_wave_height'].plot(secondary_y=True);
ax = gca();
lines = ax.left_ax.get_lines() + ax.right_ax.get_lines()
ax.legend(lines, ['{} ({})'.format(l.get_label(), side) for l, side in zip(lines, ('left', 'right'))]);
produces:

Categories