Python OpenPyxl Remove a Scatter Chart gridlines? - python-3.x

Python3 and OpenPyxl version 2.3.2
How do you remove a Scatter Chart Gridlines?
from openpyxl.chart.axis import ChartLines
SCchart = ScatterChart()
SCchart.title = "Scatter Chart"
SCchart.style = 13
SCchart.x_axis.majorGridlines = False
gives me the error:
TypeError: expected class 'openpyxl.chart.axis.ChartLines'
And this:
SCchart.x_axis.ChartLines.majorUnit = False
gives the error: AttributeError: 'NumericAxis' object has no attribute 'ChartLines'
I'd like to remove all the chart gridlines.

I have not been able to do this with Openpyxl 2.51, even using some tricks like setting the gridlines to the background color of white (hex 'FFFFFF'). I can get close to accessing the line parameter with openpyxl, but can't quite get it to work. I am including my efforts here, hoping some one else will pick up the ball.
The python gist:
from openpyxl.chart.shapes import GraphicalProperties
# turn majorGridlines off using shapes.GraphicalProperties
sgp = GraphicalProperties(solidFill='FFFFFF') # White
chart.y_axis.majorGridlines.spPr = sgp
This is the XML that openpyxl writes:
<valAx>
<axId val="2" />
<scaling>
<orientation val="minMax" />
<min val="0" />
</scaling>
<axPos val="l" />
<majorGridlines>
<spPr>
<a:solidFill>
<a:srgbClr val="FFFFFF" />
</a:solidFill>
<a:ln>
<a:prstDash val="solid" />
</a:ln>
</spPr>
</majorGridlines>
When I open the spreadsheet that openpyxl just wrote with Excel 2010, the major gridlines are still there with a dark grey color. I click on them and set their color to white and save the file with a new filename. This is how excel writes the new xml code:
<c:valAx>
<c:axId val="83446016"/>
<c:scaling>
<c:orientation val="minMax"/>
<c:min val="0"/>
</c:scaling>
<c:delete val="0"/>
<c:axPos val="r"/>
<c:majorGridlines>
<c:spPr>
<a:ln>
<a:solidFill>
<a:schemeClr val="bg1"/>
</a:solidFill>
<a:prstDash val="solid"/>
</a:ln>
</c:spPr>
</c:majorGridlines>
So logically, you might think that this python would work (spoiler, not for me!):
chart.y_axis.majorGridlines.spPr.ln = sgp
The proper method (the one used by Microsoft) is to set the gridlines to NoFill. Turning off gridlines in excel, saving the file and looking at the chart.xml file yields this:
<c:valAx>
<c:axId val="83031552"/>
<c:scaling>
<c:orientation val="minMax"/>
<c:min val="0"/>
</c:scaling>
<c:delete val="0"/>
<c:axPos val="r"/>
<c:majorGridlines>
<c:spPr>
<a:ln>
<a:noFill/>
<a:prstDash val="solid"/>
</a:ln>
</c:spPr>
</c:majorGridlines>
The python would be something like:
sgp = GraphicalProperties(noFill=True) # bonks, tried None also not effective
chart.y_axis.majorGridlines.spPr.ln = sgp
or maybe
chart.y_axis.majorGridlines.spPr.ln.noFill = True
which also bonks because there is no ln or line in this openpyxl path.

I just found an actual answer that works! You dont need to import ChartLines. The trick was I needed to include another class to get the line thing to work like this:
from openpyxl.drawing.line import LineProperties
# turn majorGridlines off using shapes.GraphicalProperties and drawing.LineProperties
sgp = GraphicalProperties(ln=LineProperties(noFill=True))
chart.x_axis.majorGridlines.spPr = sgp
Try it out!

Not sure if the earlier answers ended this thread, but based on those recommendations and a few tweaks I was able to enable/disable grid Lines for a Line Chart, add data labels.
The following code was used:
from openpyxl.chart.shapes import GraphicalProperties
from openpyxl.drawing.line import LineProperties
from openpyxl.chart.axis import ChartLines
from openpyxl.chart.label import DataLabelList
c1.y_axis.majorGridlines.spPr = GraphicalProperties(noFill = 'True')
c1.y_axis.majorGridlines.spPr.ln = LineProperties(solidFill = '000000')
c1.x_axis.majorGridlines = ChartLines()
c1.x_axis.majorGridlines.spPr = GraphicalProperties(noFill = 'True')
c1.x_axis.majorGridlines.spPr.ln = LineProperties(solidFill = '000000')
c1.dLbls = DataLabelList()
c1.dLbls.showVal = 1
Basically, certain parameters 1st need a class instance to be assigned to them in order to change subsequent sub-parameters.
For ex. When you try to set a value to spPr, the error thrown back will specify the class it expected, which you can then import and assign it's instance to the variable, if I may call it that. Beyond that, the xml can greatly help you figure which variables need to be changed. Hope this helps..

I successfully removed the gridlines from my chart by setting majorGridlines to None.
I included the following two lines in my script.
c1.x_axis.majorGridlines = None
c1.y_axis.majorGridlines = None
In my case, c1 is the instance of openpyxl.chart.LineChart().
I came up with this solution after noticing that majorGridlines accepts None as a value. I noticed this while reading the class definition for _BaseAxis which can be found here:
https://openpyxl.readthedocs.io/en/latest/_modules/openpyxl/chart/axis.html
Below is a full example program. Note: file paths are for windows so you may have to tweak these if you want to run the script on your machine.
# Generate Plots With No Grid Lines
import openpyxl as xl
import numpy as np
from pathlib import Path
# Create Sheet 1 Data
years = np.arange(2000,2023,1)
x1 = np.linspace(0,20,years.size)
x2 = np.linspace(10,2,years.size)
# Create Sheet 2 Data
x3 = np.linspace(10,100,years.size)
x4 = np.linspace(120,50,years.size)
# Open Workbook and Write Sheet 1
wb = xl.Workbook()
sheet = wb[wb.sheetnames[0]]
sheet_one_title = 'Data One'
sheet.title = sheet_one_title
sheet.append(['Year','X1','X2'])
for i in range(0,years.size):
sheet.append([years[i],x1[i],x2[i]])
# Create Sheet 2 and Switch to It
sheet_two_title = "Data Two"
wb.create_sheet(title=sheet_two_title)
sheet = wb[sheet_two_title]
# Write To Sheet 2
sheet.append(['Year','X3','X4'])
for i in range(0,years.size):
sheet.append([years[i],x3[i],x4[i]])
# Now Add The Charts
# Starting With Sheet Two (i.e. "Data Two")
c2 = xl.chart.LineChart()
data = xl.chart.Reference(sheet, min_col=2, min_row=1, max_col=3, max_row=years.size+1)
c2.add_data(data, titles_from_data=True)
dates = xl.chart.Reference(sheet, min_col=1, min_row=2, max_row=years.size+1)
c2.set_categories(dates)
# REMOVE THE GRIDLINES
c2.x_axis.majorGridlines = None
c2.y_axis.majorGridlines = None
# Add Chart to Sheet
sheet.add_chart(c2, 'D5')
# Swtich Back To Sheet 1 (i.e. "Data One")
sheet = wb[sheet_one_title]
# Create Chart
c1 = xl.chart.LineChart()
data = xl.chart.Reference(sheet, min_col=2, min_row=1, max_col=3, max_row=years.size+1)
c1.add_data(data, titles_from_data=True)
dates = xl.chart.Reference(sheet, min_col=1, min_row=2, max_row=years.size+1)
c1.set_categories(dates)
# REMOVE THE GRIDLINES ONCE MORE
c1.x_axis.majorGridlines = None
c1.y_axis.majorGridlines = None
# Add Chart to Sheet
sheet.add_chart(c1, 'D5')
# Get Route to Desktop
desktop = str(Path.home()) + "\Desktop"
# Create Path by Appending File Name
save_path = desktop + "\\PlotExample.xlsx"
# Save Workbook
wb.save(save_path)
print("Workbook Saved To:" + save_path)
p.s. this is my first ever stack overflow answer :)

Related

is there any way to switch ImageJ macro code to python3 code?

I'm making an app in python3 and I want to use some function in imagej. I used macro recorder to switch to python code but it got really messy, now I don't know how to do next. Can someone help me, please.
Here is the marco recorder code and my marco code
imp = IJ.openImage("D:/data/data_classify/data_train/1/9700TEST.6.tiff40737183_2.jpg");
//IJ.setTool("line");
//IJ.setTool("polyline");
xpoints = [177,155,114,101,100,159,179];
ypoints = [82,94,109,121,133,163,173];
imp.setRoi(new PolygonRoi(xpoints,ypoints,Roi.POLYLINE));
IJ.run(imp, "Straighten...", "title=9700TEST.6.tiff40737183_2-1.jpg line=30");
my python3 code
mport imagej
from scyjava import jimport
ij = imagej.init('2.5.0', mode='interactive')
print(ij.getVersion())
imp = ij.IJ.openImage("D:/data/data_classify/data_train/1/9700TEST.6.tiff40737183_2.jpg")
xpoints = [177,155,114,101,100,159,179]
xpoints_int = ij.py.to_java(xpoints)
ypoints = [82,94,109,121,133,163,173]
ypoints_int = ij.py.to_java(xpoints)
straightener = jimport('ij.plugin.Straightener')
polyRoi = jimport('ij.gui.PolygonRoi')
and I don't know how to do next...
After a few days, I finally found the answer. It is important to understand the parameters of the function to write, I have referenced in:
https://pyimagej.readthedocs.io/en/latest/
https://imagej.nih.gov/ij/developer/api/ij/module-summary.html
in my example the next thing i need is polygonroi from the given coordinates. I found the required coefficients of PolygonRoi in the above website and determined to take as parameters PolygonRoi​(int[] xPoints, int[] yPoints, int nPoints, int type)
Next, I found a way to convert my list of coordinates to an int[] which was shown in the pyimagej tutorial.
In the type section, I can find it by trying print(int(roi.PolygonRoi)) and the result is 6, you can also find the reason in the website above in the Roi section
The rest, the last thing you need to do is put that PolygonRoi into the Straightener function with the line value you want
Here is my code for using macro Imagej in Python3
import imagej
from scyjava import jimport
from jpype import JArray, JInt
ij = imagej.init('2.5.0', mode='interactive')
print(ij.getVersion())
imp = ij.IJ.openImage("D:/AI lab/joint_detection/data/1/9700TEST.6.tiff133328134_1.jpg")
xpoints = [124,126,131,137,131,128,121,114]
xpoints_int = JArray(JInt)(xpoints)
ypoints = [44,63,105,128,148,172,194,206]
ypoints_int = JArray(JInt)(ypoints)
straightener = jimport('ij.plugin.Straightener')
polyRoi = jimport('ij.gui.PolygonRoi')
roi = jimport('ij.gui.Roi')
new_polyRoi = polyRoi(xpoints_int,ypoints_int,len(xpoints), int(roi.POLYLINE))
imp.setRoi(new_polyRoi)
straightened_img = ij.IJ.run(imp, "Straighten...", "title=9700TEST.6.tiff40737183_2-1.jpg line=30")
ij.IJ.saveAs(straightened_img, 'Jpeg', './test.jpg')

How to fix unidentified character problem while passing data from TKinter to Photoshop via Python script?

I made a GUI Application which looks like this:
The ones marked red are Tkinter Text widgets and the ones marked yellow are Tkinter Entry widgets
After taking user input, the data is to be added to a PSD file and then rendered as an image. But Lets say, after taking the following data as input:
It renders the following Photoshop file:
How do I fix this issue that it does not recognize "\n" properly and hence the rendered document is rendered useless.
Here is the code which deals with converting of the accepted user data into strings and then adding it to Photoshop template and then rendering it:
def DataAdder2CSV():
global edate, eSNO, eage, egender, ename, ePID, econtact, ecomp, eallergy, ehistory, eR
e=edate.get()
a=eSNO.get()
d=eage.get()
f=egender.get()
b=ename.get()
c=ePID.get()
g=econtact.get()
h=ecomp.get(1.0,END)
i=eallergy.get(1.0,END)
j=ehistory.get(1.0,END)
k=eR.get(1.0,END)
data=[a,b,c,d,e,f,g,h,i,j,k]
file=open("Patient_Data.csv","a", newline="")
writer=csv.writer(file, delimiter=",")
writer.writerow(data)
file.close()
messagebox.showinfo("Prescription Generator", "Data has been saved to the database successfully!")
import win32com.client, os
objShell = win32com.client.Dispatch("WScript.Shell")
UserDocs = objShell.SpecialFolders("MyDocuments")
from tkinter import filedialog
ExpDir=filedialog.askdirectory(initialdir=UserDocs, title="Choose Destination Folder")
psApp = win32com.client.Dispatch("Photoshop.Application")
psApp.Open("D:\Coding\Python Scripts\Dr Nikhil Prescription App\Prescription Generator\Presc_Template.psd")
doc = psApp.Application.ActiveDocument
lf1 = doc.ArtLayers["name"]
tol1 = lf1.TextItem
tol1.contents = b
lf2 = doc.ArtLayers["age"]
tol2 = lf2.TextItem
tol2.contents = d
lf3 = doc.ArtLayers["gender"]
tol3 = lf3.TextItem
tol3.contents = f
lf4 = doc.ArtLayers["pid"]
tol4 = lf4.TextItem
tol4.contents = c
lf4 = doc.ArtLayers["date"]
tol4 = lf4.TextItem
tol4.contents = e
lf5 = doc.ArtLayers["contact"]
tol5 = lf5.TextItem
tol5.contents = g
lf6 = doc.ArtLayers["complaint"]
tol6 = lf6.TextItem
varH=" "+h.rstrip("\n")
tol6.contents =varH
lf7 = doc.ArtLayers["allergy"]
tol7 = lf7.TextItem
tol7.contents = i.rstrip("\n")
lf8 = doc.ArtLayers["history"]
tol8 = lf8.TextItem
varJ=" "+j.rstrip("\n")
tol8.contents =varJ
lf9 = doc.ArtLayers["R"]
tol9 = lf9.TextItem
tol9.contents = k.rstrip("\n")
options = win32com.client.Dispatch('Photoshop.ExportOptionsSaveForWeb')
options.Format = 13
options.PNG8 = False
pngfile =ExpDir+f"/{c}-{b}_({e}).png"
doc.Export(ExportIn=pngfile, ExportAs=2, Options=options)
messagebox.showinfo("Prescription Generator", "Prescription has been saved in the desired location successfully!")
There are 3 ways of expressing new line characters:
MacOS uses \r
Linux uses \n
Windows uses \r\n
Python and tkinter use \n but it looks like psApp.Application uses \r instead. That is why the document isn't rendered properly. For more info read the answers to this question.

Macro ignores parameter change

Given a FreeCAD model that consists of
Spreadsheet "parameters" with a cell aliased as "radius" and value 50
Icosahedron (from the Pyramids-and-Polyhedrons macro) with Radius=parameters.radius
some facebinders which are unimportant for the purpose of this question,
the python script below opens this model, changes the radius cell in the Spreadsheet to 15, call recompute() on the spreadsheet, invokes touch() on the icosahedron, calls recompute() on the document, and finally tessellates the icosahedron. The z coordinate of the vertex at index 11 in the tessellated mesh happens to be equal to the icosahedron's radius. I was expecting it to change to 15, according to the parameter change. But it remains at its original value 50. What am I doing wrong?
To my understanding the macro's execute method should get invoked during the recomputation of the document.
When I trace Document.recompute() with pudb, I only see it executing Facebinder.execute() but not Icosahedron.execute(). The path it takes from Document.recompute() to Facebinder.execute() method is not visible in pudb; it immediately stops in Facebinder.execute().
FREECADPATH = '/usr/local/lib' # path to your FreeCAD.so or FreeCAD.dll POLYHEDRONS_PATH = '/home/user/.FreeCAD/Mod/Pyramids-and-Polyhedrons'
import sys
sys.path.append(FREECADPATH)
sys.path.append(POLYHEDRONS_PATH)
import FreeCAD
filename = 'icosahedron.FCStd'
newRadius = 15
doc = FreeCAD.open(filename)
sheet = doc.Spreadsheet
sheet.set('radius', str(newRadius))
sheet.recompute()
print('radius = ' + str(sheet.get('radius')))
icosahedron = doc.getObjectsByLabel('Icosahedron')[0]
print('icosahedron.Radius = '+str(icosahedron.Radius))
icosahedron.touch()
doc.recompute()
print('icosahedron.Radius = '+str(icosahedron.Radius))
(vertices, faces) = icosahedron.Shape.tessellate(1)
z11 = vertices[11][2]
print('z11 = ' + str(z11))
FreeCAD.closeDocument(doc.Name)
I figured it out. The reason was Pyramids-and-Polyhedrons not being imported after all.
The first problem was that Pyramids-and-Polyhedrons imports FreeCADGui (in order to install its workbench), which depends on certain native libs that need to be added to LD_LIBRARY_PATH before running the script:
export LD_LIBRARY_PATH=$(echo $(find /usr/local/lib/python3.7/site-packages -maxdepth 2 -mindepth 2 -type f -name *.so* | sed -r 's|/[^/]+$||' | sort -u) | sed -E 's/ /:/g')
Now FreeCADGui could be imported, but it was lacking the required addCommand method that Pyramids-and-Polyhedrons invokes. I found out that FreeCADGui will only be fully initialized after FreeCADGui.showMainWindow() has been called. This requires a display, however, and I want to run the script as part of a headless toolchain in a Docker container. Therefore I added Xvfb to the image. I'm launching it in the background before running the updated script with DISPLAY pointing to Xvfb:
FREECADPATH = '/usr/local/lib' # path to your FreeCAD.so or FreeCAD.dll file
POLYHEDRONS_PATH = '/home/user/.FreeCAD/Mod/Pyramids-and-Polyhedrons'
import sys
sys.path.append(FREECADPATH)
sys.path.append(POLYHEDRONS_PATH)
import FreeCAD
import FreeCADGui
FreeCADGui.showMainWindow()
import polyhedrons
filename = 'icosahedron.FCStd'
newRadius = 15
doc = FreeCAD.open(filename)
sheet = doc.Spreadsheet
sheet.set('radius', str(newRadius))
sheet.recompute()
print('radius = ' + str(sheet.get('radius')))
icosahedron = doc.getObjectsByLabel('Icosahedron')[0]
print('icosahedron.Radius = '+str(icosahedron.Radius))
breakpoint()
icosahedron.touch()
doc.recompute()
print('icosahedron.Radius = '+str(icosahedron.Radius))
(vertices, faces) = icosahedron.Shape.tessellate(1)
z11 = vertices[11][2]
print('z11 = ' + str(z11))
FreeCAD.closeDocument(doc.Name)
Now the output is
...
z11 = 15.0
as expected.

slider.value values not getting updated using ColumnDataSource(Dataframe).data

I have been working on COVID19 analysis for a dashboard and am using a JSON data source. I have converted the json to dataframe. I am working on plotting bar chart for "Days to reach deaths" over a "States" x-axis (categorical values). I am trying to use a function to update the slider.value. Upon running the bokeh serve with --log-level=DEBUG, I am getting a following error:
Can someone provide me with any direction or help with what might be causing the issue as I am new to Python and any help is appreciated? Or if there's any other alternative.
Please find the code below:
cases_summary = requests.get('https://api.rootnet.in/covid19-in/stats/history')
json_data = cases_summary.json()
#Data Cleaning
cases_summary=pd.json_normalize(json_data['data'], record_path='regional', meta='day')
cases_summary['loc']=np.where(cases_summary['loc']=='Nagaland#', 'Nagaland', cases_summary['loc'])
cases_summary['loc']=np.where(cases_summary['loc']=='Madhya Pradesh#', 'Madhya Pradesh', cases_summary['loc'])
cases_summary['loc']=np.where(cases_summary['loc']=='Jharkhand#', 'Jharkhand', cases_summary['loc'])
#Calculate cumulative days since 1st case for each state
cases_summary['day_count']=(cases_summary['day'].groupby(cases_summary['loc']).cumcount())+1
#Initial plot for default slider value=35
days_reach_death_count=cases_summary.loc[(cases_summary['deaths']>=35)].groupby(cases_summary['loc']).head(1).reset_index()
slider = Slider(start=10, end=max(cases_summary['deaths']), value=35, step=10, title="Total Deaths")
source = ColumnDataSource(data=dict(days_reach_death_count[['loc','day_count', 'deaths']]))
q = figure(x_range=days_reach_death_count['loc'], plot_width=1200, plot_height=600, sizing_mode="scale_both")
q.title.align = 'center'
q.title.text_font_size = '17px'
q.xaxis.axis_label = 'State'
q.yaxis.axis_label = 'Days since 1st Case'
q.xaxis.major_label_orientation = math.pi/2
q.vbar('loc', top='day_count', width=0.9, source=source)
deaths = slider.value
q.title.text = 'Days to reach %d Deaths' % deaths
hover = HoverTool(line_policy='next')
hover.tooltips = [('State', '#loc'),
('Days since 1st Case', '#day_count'), # #$name gives the value corresponding to the legend
('Deaths', '#deaths')
]
q.add_tools(hover)
def update(attr, old, new):
days_death_count = cases_summary.loc[(cases_summary['deaths'] >= slider.value)].groupby(cases_summary['loc']).head(1).reindex()
source.data = [ColumnDataSource().from_df(days_death_count)]
slider.on_change('value', update)
layout = row(q, slider)
tab = Panel(child=layout, title="New Confirmed Cases since Day 1")
tabs= Tabs(tabs=[tab])
curdoc().add_root(tabs)
Your code has 2 issues
(critical) source.data must be a dictionary, but you're assigning it an array
(minor) from_df is a class method, you don't have to construct an object of it
Try using source.data = ColumnDataSource.from_df(days_death_count) instead.

Making a copy of a object pandas column as a category type giving warning

I'm making a copy of a pandas object column into a separate ordered column but I'm getting a warning and haven't figured out for the life of me how to do it the correct way.
I can't post the entire data frame up but here is the syntax I'm using:
marriage_cat_type = CategoricalDtype(categories= ['M_22', 'M_23', 'M_24', 'M_25', 'M_26', 'M_27', 'M_28', 'M_29', 'M_30'
, 'M_31', 'M_32', 'M_33', 'M_34', 'M_35', 'M_36', 'M_37', 'M_38', 'M_39'
, 'M_40', 'M_41', 'M_42', 'M_43', 'M_44', 'M_45', 'M_46', 'M_47', 'M_48'
, 'M_49', 'M_50', 'M_51', 'M_52', 'M_53', 'M_54', 'M_55', 'M_56', 'M_57'
, 'M_58', 'M_59', 'M_60', 'M_61', 'M_62', 'M_63', 'M_64', 'M_65', 'M_66'
, 'M_67', 'M_68', 'M_69', 'M_70', 'M_71', 'M_72', 'M_73', 'M_74', 'M_75'
, 'M_76', 'M_77', 'M_78', 'M_79', 'M_80', 'M_81', 'M_82', 'M_999', 'S_18'
, 'S_19', 'S_20', 'S_21', 'S_22', 'S_23', 'S_24', 'S_25', 'S_26', 'S_27'
, 'S_28', 'S_29', 'S_30', 'S_31', 'S_32', 'S_33', 'S_34', 'S_35', 'S_36'
, 'S_37', 'S_38', 'S_39', 'S_40', 'S_41', 'S_42', 'S_43', 'S_44', 'S_45'
, 'S_46', 'S_47', 'S_48', 'S_49', 'S_50', 'S_51', 'S_52', 'S_53', 'S_54'
, 'S_55', 'S_56', 'S_57', 'S_58', 'S_59', 'S_60', 'S_61', 'S_62', 'S_63'
, 'S_64', 'S_65', 'S_66', 'S_67', 'S_68', 'S_69', 'S_70', 'S_71', 'S_72'
, 'S_73', 'S_74', 'S_75', 'S_77', 'S_79', 'S_999'], ordered = True)
coll_train['marriage_statusXage_codes'] = coll_train['marital_statusXage2'].astype(marriage_cat_type)
I'm getting this warning.
C:\ProgramData\Anaconda3\lib\site-packages\ipykernel_launcher.py:2:
SettingWithCopyWarning: A value is trying to be set on a copy of a
slice from a DataFrame. Try using .loc[row_indexer,col_indexer] =
value instead
See the caveats in the documentation:
http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
And I've tried this resulting in failure:
coll_train['marriage_statusXage_codes'] = coll_train.loc[:,
'marital_statusXage2'].astype(marriage_cat_type)
Can anyone point me in the right direction?
This is a chained assignment issue. That may be manipulated by pd.set_option('chained_assignment',None|'warn'|'raise').
The warnings are turned on, and Pandas does not like coll_train.
There are a couple options: Make sure coll_train is the source dataframe you intend to modify (which you are doing by placing a new column named marriage_statusXage_codes in it). If it is, and Pandas is wrong, set pd.set_option('chained_assignment',None). Can Pandas be wrong about that? I don't know.
Here is an illustration of setting a value on a slice.
import pandas as pd
from pandas.compat import StringIO
print(pd.__version__)
csvdata = StringIO("""date,LASTA,LASTB,LASTC
1999-03-15,2.5597,8.20145,16.900
1999-03-31,2.7724,7.73057,16.955
1999-04-01,2.8321,7.63714,17.500
1999-04-06,2.8537,7.63703,17.750""")
df = pd.read_csv(csvdata, sep=",", index_col="date", parse_dates=True, infer_datetime_format=True)
pd.set_option('chained_assignment','warn')
a_slice = df['1999-03-31':'1999-04-01']
print(id(df), id(a_slice))
# generates the warning
a_slice['LASTA'] = 10
# original does not have the data set on a slice!
print(df[df['LASTA'] == 10]['LASTA'].any())
# create a new object to which values can be set, no warning.
a_slice = a_slice.copy()
a_slice['LASTA'] = 10
print(a_slice[a_slice['LASTA'] == 10]['LASTA'].any())
Results
0.20.3
(4549520208, 4594637776)
slicecopy.py:20: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
a_slice['LASTA'] = 10
False
True

Resources